diff --git a/.ci/ci_check.sh b/.ci/ci_check.sh index bfdfac360..4ab58c854 100644 --- a/.ci/ci_check.sh +++ b/.ci/ci_check.sh @@ -1,16 +1,16 @@ -#!/bin/bash - -set -e - -curl -LO https://raw.githubusercontent.com/FISCO-BCOS/FISCO-BCOS/dev/tools/build_chain.sh && chmod u+x build_chain.sh -bash <(curl -s https://raw.githubusercontent.com/FISCO-BCOS/FISCO-BCOS/dev/tools/ci/download_bin.sh) -b dev -m -echo "127.0.0.1:4 agency1 1,2,3" > ipconf -./build_chain.sh -e bin/fisco-bcos -f ipconf -p 30300,20200,8545 -v 2.7.0 -./nodes/127.0.0.1/start_all.sh -./nodes/127.0.0.1/fisco-bcos -v -cp nodes/127.0.0.1/sdk/* src/main/resources/ -cp nodes/127.0.0.1/sdk/* src/test/resources/ -#./gradlew verifyGoogleJavaFormat -# test module needs optimization -./gradlew build -x test -#./gradlew test +#!/bin/bash + +set -e + +curl -LO https://raw.githubusercontent.com/FISCO-BCOS/FISCO-BCOS/dev/tools/build_chain.sh && chmod u+x build_chain.sh +bash <(curl -s https://raw.githubusercontent.com/FISCO-BCOS/FISCO-BCOS/dev/tools/ci/download_bin.sh) -b dev -m +echo "127.0.0.1:4 agency1 1,2,3" > ipconf +./build_chain.sh -e bin/fisco-bcos -f ipconf -p 30300,20200,8545 -v 2.7.2 +./nodes/127.0.0.1/start_all.sh +./nodes/127.0.0.1/fisco-bcos -v +cp nodes/127.0.0.1/sdk/* src/main/resources/ +cp nodes/127.0.0.1/sdk/* src/test/resources/ +#./gradlew verifyGoogleJavaFormat +# test module needs optimization +./gradlew build -x test +#./gradlew test diff --git a/.gitignore b/.gitignore index 7998cc1fc..13c2a671a 100644 --- a/.gitignore +++ b/.gitignore @@ -37,12 +37,14 @@ gradle.properties /bin *.crt *.key +*.publickey h2 /lib/ solcjs -v0.*.js -v0.*.js.gz +v0.*.*.js +v0.*.*.js.gz /output/ +/conf/ diff --git a/.travis.yml b/.travis.yml index e2f75616d..f0b0ef556 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,8 @@ branches: - dev language: java - +services: + - mysql matrix: # fast_finish: true include: @@ -26,6 +27,29 @@ matrix: dist: xenial sudo: required + - language: java + jdk: openjdk11 + os: linux + dist: xenial + sudo: required + + - language: java + jdk: openjdk12 + os: linux + dist: xenial + sudo: required + + - language: java + jdk: openjdk13 + os: linux + dist: xenial + sudo: required + + - language: java + jdk: openjdk14 + os: linux + dist: xenial + sudo: required before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock diff --git a/Changelog.md b/Changelog.md index adc711fa2..e7cec9fcf 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,23 @@ +### v1.5.2(2021-07-16) + +**Add** +- 优化合约Java项目导出功能,支持批量编译合约,支持多用户与channel端口检查 +- 合约仓库新增资产合约模板 +- 增加交易组装接口`/tran/convertRawTxStr`和编码交易函数接口`/trans/encodeFunction` +- 支持合约IDE绑定合约地址 + +**Fix** +- 优化交易窗口,支持无私钥用户时直接创建私钥 + +**兼容性** +- 支持FISCO-BCOS v2.4.x 及以上版本 +- WeBASE-Node-Manager v1.5.0+ +- WeBASE-Sign v1.5.0+ +- WeBASE-Transaction v1.3.0+ + +详细了解,请阅读[**技术文档**](https://webasedoc.readthedocs.io/zh_CN/latest/)。 + + ### v1.5.1(2021-05-28) **Add** @@ -13,7 +33,7 @@ **兼容性** - 支持FISCO-BCOS v2.4.x 及以上版本 -- WeBASE-Node-Manager v1.4.1+ +- WeBASE-Node-Manager v1.5.0+ - WeBASE-Sign v1.5.0+ - WeBASE-Transaction v1.3.0+ @@ -32,7 +52,7 @@ **兼容性** - 支持FISCO-BCOS v2.4.x 及以上版本 -- WeBASE-Node-Manager v1.4.1+ +- WeBASE-Node-Manager v1.5.0+ - WeBASE-Sign v1.5.0+ - WeBASE-Transaction v1.3.0+ diff --git a/README.md b/README.md index 967e80a23..7c3a11ba9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # 节点前置服务 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://webasedoc.readthedocs.io/zh_CN/latest/docs/WeBASE/CONTRIBUTING.html) [![CodeFactor](https://www.codefactor.io/repository/github/webankfintech/webase-front/badge)](https://www.codefactor.io/repository/github/webankfintech/webase-front) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f5be085401f54e7080a654693ac260d4)](https://www.codacy.com/gh/WeBankFinTech/WeBASE-Front?utm_source=github.com&utm_medium=referral&utm_content=WeBankFinTech/WeBASE-Front&utm_campaign=Badge_Grade) [![Code Lines](https://tokei.rs/b1/github/WeBankFinTech/WeBASE-Front?category=code)](https://github.com/WeBankFinTech/WeBASE-Front) [![license](http://img.shields.io/badge/license-Apache%20v2-blue.svg)](http://www.apache.org/licenses/) [![GitHub (pre-)release](https://img.shields.io/github/release/WeBankFinTech/WeBASE-Front/all.svg)](https://github.com/WeBankFinTech/WeBASE-Front/releases) diff --git a/build.gradle b/build.gradle index 76dbfaa45..1aee323d1 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ repositories { } -def spring_version="4.3.27.RELEASE" +def spring_version="4.3.29.RELEASE" List spring =[ "org.springframework:spring-core:$spring_version", "org.springframework:spring-beans:$spring_version", @@ -71,7 +71,7 @@ List jaxb = [ "javax.activation:activation:1.1.1" ] -def jackson_version = "2.11.0" +def jackson_version = "2.11.4" List jackson = [ "com.fasterxml.jackson.core:jackson-annotations:$jackson_version", "com.fasterxml.jackson.core:jackson-core:$jackson_version", @@ -90,9 +90,9 @@ List tomcat = [ ] List scaffold = [ - 'com.webank.webase:solscaffold:1.0.1', - 'com.webank:SmartDev-Scaffold:1.0.0-SNAPSHOT', - 'com.webank:solc-gradle-plugin:1.0.0' + 'com.webank.webase:solscaffold:1.0.2', + 'com.webank:SmartDev-Scaffold:1.0.0.1', + 'com.webank:solc-gradle-plugin:1.0.1' ] dependencies { diff --git a/docker/build/Dockerfile b/docker/build/Dockerfile index c9bfd0d70..b9832f6f7 100644 --- a/docker/build/Dockerfile +++ b/docker/build/Dockerfile @@ -9,6 +9,7 @@ RUN apt-get update \ #COPY --from=builder /code/dist/lib /dist/lib #COPY --from=builder /code/dist/conf_template /dist/conf #COPY --from=builder /code/dist/apps /dist/apps +COPY static /dist/static COPY lib /dist/lib COPY conf_template /dist/conf COPY apps /dist/apps @@ -18,7 +19,7 @@ EXPOSE 5002 ENV CLASSPATH "/dist/conf/:/dist/apps/*:/dist/lib/*" -ENV JAVA_OPTS " -server -Dfile.encoding=UTF-8 -Xmx256m -Xms256m -Xmn128m -Xss512k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/log/heap_error.log -XX:+UseG1GC -XX:MaxGCPauseMillis=200 " +ENV JAVA_OPTS " -server -Dfile.encoding=UTF-8 -Xmx512m -Xms512m -Xmn256m -Xss512k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/log/heap_error.log -XX:+UseG1GC -XX:MaxGCPauseMillis=200 " ENV APP_MAIN "com.webank.webase.front.Application" # start commond diff --git a/release_note.txt b/release_note.txt index 53b5bbb12..a503124bd 100644 --- a/release_note.txt +++ b/release_note.txt @@ -1 +1 @@ -v1.5.1 +v1.5.2 diff --git a/src/main/java/com/webank/webase/front/base/code/ConstantCode.java b/src/main/java/com/webank/webase/front/base/code/ConstantCode.java index f66904601..37d6780f2 100644 --- a/src/main/java/com/webank/webase/front/base/code/ConstantCode.java +++ b/src/main/java/com/webank/webase/front/base/code/ConstantCode.java @@ -152,6 +152,8 @@ public class ConstantCode { public static final RetCode WRITE_PRIVATE_KEY_CRT_KEY_FILE_FAIL = RetCode.mark(201157,"Write private key file fail!"); // add in v1.5.1 public static final RetCode GENERATE_CONTRACT_PROJECT_FAIL = RetCode.mark(201161, "generate project failed in scaffold"); + // v1.5.2 + public static final RetCode IP_FORMAT_ERROR = RetCode.mark(201162, "IP format error."); /* precompiled runtime check or error */ diff --git a/src/main/java/com/webank/webase/front/contract/ContractService.java b/src/main/java/com/webank/webase/front/contract/ContractService.java index 0463871b4..e0a796b47 100644 --- a/src/main/java/com/webank/webase/front/contract/ContractService.java +++ b/src/main/java/com/webank/webase/front/contract/ContractService.java @@ -512,7 +512,7 @@ public void deleteContract(Long contractId, int groupId) { * save contract data. */ public Contract saveContract(ReqContractSave contractReq) { - log.debug("start saveContract contractReq:{}", JsonUtils.toJSONString(contractReq)); + log.info("start saveContract contractReq:{}", JsonUtils.toJSONString(contractReq)); if (contractReq.getContractId() == null) { // new return newContract(contractReq); @@ -580,6 +580,11 @@ public Contract updateContract(ReqContractSave contractReq) { contractReq.getContractName(), contractReq.getContractId()); BeanUtils.copyProperties(contractReq, contract); contract.setModifyTime(LocalDateTime.now()); + if(contract.getContractAddress()!=null && contract.getContractAddress().length()>("0x").length()) + { + contract.setContractStatus(ContractStatus.DEPLOYED.getValue()); + contract.setDeployTime(LocalDateTime.now()); + } contractRepository.save(contract); // update time ContractPath contractPathVo = new ContractPath(); diff --git a/src/main/java/com/webank/webase/front/contract/entity/ReqContractSave.java b/src/main/java/com/webank/webase/front/contract/entity/ReqContractSave.java index 8b3968c21..2fb639e83 100644 --- a/src/main/java/com/webank/webase/front/contract/entity/ReqContractSave.java +++ b/src/main/java/com/webank/webase/front/contract/entity/ReqContractSave.java @@ -39,4 +39,6 @@ public class ReqContractSave { * 合约编译的runtime-bytecode(runtime-bin),用于交易解析 */ private String contractBin; + + private String contractAddress; } diff --git a/src/main/java/com/webank/webase/front/contractStore/PointsConstantContext.java b/src/main/java/com/webank/webase/front/contractStore/PointsConstantContext.java index 35edcbf36..942c838fd 100644 --- a/src/main/java/com/webank/webase/front/contractStore/PointsConstantContext.java +++ b/src/main/java/com/webank/webase/front/contractStore/PointsConstantContext.java @@ -17,6 +17,8 @@ public class PointsConstantContext { public static final String BAC001_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjQ7CgppbXBvcnQgIi4vU2FmZU1hdGguc29sIjsKaW1wb3J0ICIuL1JvbGVzLnNvbCI7CmltcG9ydCAiLi9BZGRyZXNzLnNvbCI7Cgpjb250cmFjdCBJc3N1ZXJSb2xlIHsKICAgIHVzaW5nIFJvbGVzIGZvciBSb2xlcy5Sb2xlOwoKICAgIGV2ZW50IElzc3VlckFkZGVkKGFkZHJlc3MgaW5kZXhlZCBhY2NvdW50KTsKICAgIGV2ZW50IElzc3VlclJlbW92ZWQoYWRkcmVzcyBpbmRleGVkIGFjY291bnQpOwoKICAgIFJvbGVzLlJvbGUgcHJpdmF0ZSBfaXNzdWVyczsKCiAgICBjb25zdHJ1Y3RvciAoKSBpbnRlcm5hbCB7CiAgICAgICAgX2FkZElzc3Vlcihtc2cuc2VuZGVyKTsKICAgIH0KCiAgICBtb2RpZmllciBvbmx5SXNzdWVyKCkgewogICAgICAgIHJlcXVpcmUoaXNJc3N1ZXIobXNnLnNlbmRlciksICJJc3N1ZXJSb2xlOiBjYWxsZXIgZG9lcyBub3QgaGF2ZSB0aGUgSXNzdWVyIHJvbGUiKTsKICAgICAgICBfOwogICAgfQoKICAgIGZ1bmN0aW9uIGlzSXNzdWVyKGFkZHJlc3MgYWNjb3VudCkgcHVibGljIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybiBfaXNzdWVycy5oYXMoYWNjb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gYWRkSXNzdWVyKGFkZHJlc3MgYWNjb3VudCkgcHVibGljIG9ubHlJc3N1ZXIgewogICAgICAgIF9hZGRJc3N1ZXIoYWNjb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gcmVub3VuY2VJc3N1ZXIoKSBwdWJsaWMgewogICAgICAgIF9yZW1vdmVJc3N1ZXIobXNnLnNlbmRlcik7CiAgICB9CgogICAgZnVuY3Rpb24gX2FkZElzc3VlcihhZGRyZXNzIGFjY291bnQpIGludGVybmFsIHsKICAgICAgICBfaXNzdWVycy5hZGQoYWNjb3VudCk7CiAgICAgICAgZW1pdCBJc3N1ZXJBZGRlZChhY2NvdW50KTsKICAgIH0KCiAgICBmdW5jdGlvbiBfcmVtb3ZlSXNzdWVyKGFkZHJlc3MgYWNjb3VudCkgaW50ZXJuYWwgewogICAgICAgIF9pc3N1ZXJzLnJlbW92ZShhY2NvdW50KTsKICAgICAgICBlbWl0IElzc3VlclJlbW92ZWQoYWNjb3VudCk7CiAgICB9Cn0KCmNvbnRyYWN0IFN1c3BlbmRlclJvbGUgewogICAgdXNpbmcgUm9sZXMgZm9yIFJvbGVzLlJvbGU7CgogICAgZXZlbnQgU3VzcGVuZGVyQWRkZWQoYWRkcmVzcyBpbmRleGVkIGFjY291bnQpOwogICAgZXZlbnQgU3VzcGVuZGVyUmVtb3ZlZChhZGRyZXNzIGluZGV4ZWQgYWNjb3VudCk7CgogICAgUm9sZXMuUm9sZSBwcml2YXRlIF9zdXNwZW5kZXJzOwoKICAgIGNvbnN0cnVjdG9yICgpIGludGVybmFsIHsKICAgICAgICBfYWRkU3VzcGVuZGVyKG1zZy5zZW5kZXIpOwogICAgfQoKICAgIG1vZGlmaWVyIG9ubHlTdXNwZW5kZXIoKSB7CiAgICAgICAgcmVxdWlyZShpc1N1c3BlbmRlcihtc2cuc2VuZGVyKSwgIlN1c3BlbmRlclJvbGU6IGNhbGxlciBkb2VzIG5vdCBoYXZlIHRoZSBTdXNwZW5kZXIgcm9sZSIpOwogICAgICAgIF87CiAgICB9CgogICAgZnVuY3Rpb24gaXNTdXNwZW5kZXIoYWRkcmVzcyBhY2NvdW50KSBwdWJsaWMgdmlldyByZXR1cm5zIChib29sKSB7CiAgICAgICAgcmV0dXJuIF9zdXNwZW5kZXJzLmhhcyhhY2NvdW50KTsKICAgIH0KCiAgICBmdW5jdGlvbiBhZGRTdXNwZW5kZXIoYWRkcmVzcyBhY2NvdW50KSBwdWJsaWMgb25seVN1c3BlbmRlciB7CiAgICAgICAgX2FkZFN1c3BlbmRlcihhY2NvdW50KTsKICAgIH0KCiAgICBmdW5jdGlvbiByZW5vdW5jZVN1c3BlbmRlcigpIHB1YmxpYyB7CiAgICAgICAgX3JlbW92ZVN1c3BlbmRlcihtc2cuc2VuZGVyKTsKICAgIH0KCiAgICBmdW5jdGlvbiBfYWRkU3VzcGVuZGVyKGFkZHJlc3MgYWNjb3VudCkgaW50ZXJuYWwgewogICAgICAgIF9zdXNwZW5kZXJzLmFkZChhY2NvdW50KTsKICAgICAgICBlbWl0IFN1c3BlbmRlckFkZGVkKGFjY291bnQpOwogICAgfQoKICAgIGZ1bmN0aW9uIF9yZW1vdmVTdXNwZW5kZXIoYWRkcmVzcyBhY2NvdW50KSBpbnRlcm5hbCB7CiAgICAgICAgX3N1c3BlbmRlcnMucmVtb3ZlKGFjY291bnQpOwogICAgICAgIGVtaXQgU3VzcGVuZGVyUmVtb3ZlZChhY2NvdW50KTsKICAgIH0KfQoKY29udHJhY3QgU3VzcGVuZGFibGUgaXMgU3VzcGVuZGVyUm9sZSB7CgogICAgZXZlbnQgU3VzcGVuZGVkKGFkZHJlc3MgYWNjb3VudCk7CiAgICBldmVudCBVblN1c3BlbmRlZChhZGRyZXNzIGFjY291bnQpOwoKICAgIGJvb2wgcHJpdmF0ZSBfc3VzcGVuZGVkOwoKICAgIGNvbnN0cnVjdG9yICgpIGludGVybmFsIHsKICAgICAgICBfc3VzcGVuZGVkID0gZmFsc2U7CiAgICB9CgogICAgLyoqCiAgICAgKiBAcmV0dXJuIFRydWUgaWYgdGhlIGNvbnRyYWN0IGlzIHN1c3BlbmRlZCwgZmFsc2Ugb3RoZXJ3aXNlLgogICAgICovCiAgICBmdW5jdGlvbiBzdXNwZW5kZWQoKSBwdWJsaWMgdmlldyByZXR1cm5zIChib29sKSB7CiAgICAgICAgcmV0dXJuIF9zdXNwZW5kZWQ7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IE1vZGlmaWVyIHRvIG1ha2UgYSBmdW5jdGlvbiBjYWxsYWJsZSBvbmx5IHdoZW4gdGhlIGNvbnRyYWN0IGlzIG5vdCBzdXNwZW5kZWQuCiAgICAgKi8KICAgIG1vZGlmaWVyIHdoZW5Ob3RTdXNwZW5kZWQoKSB7CiAgICAgICAgcmVxdWlyZSghX3N1c3BlbmRlZCwgIlN1c3BlbmRhYmxlOiBzdXNwZW5kZWQiKTsKICAgICAgICBfOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBNb2RpZmllciB0byBtYWtlIGEgZnVuY3Rpb24gY2FsbGFibGUgb25seSB3aGVuIHRoZSBjb250cmFjdCBpcyBzdXNwZW5kZWQuCiAgICAgKi8KICAgIG1vZGlmaWVyIHdoZW5TdXNwZW5kZWQoKSB7CiAgICAgICAgcmVxdWlyZShfc3VzcGVuZGVkLCAiU3VzcGVuZGFibGU6IG5vdCBzdXNwZW5kZWQiKTsKICAgICAgICBfOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBDYWxsZWQgYnkgYSBTdXNwZW5kZXIgdG8gc3VzcGVuZCwgdHJpZ2dlcnMgc3RvcHBlZCBzdGF0ZS4KICAgICAqLwogICAgZnVuY3Rpb24gc3VzcGVuZCgpIHB1YmxpYyBvbmx5U3VzcGVuZGVyIHdoZW5Ob3RTdXNwZW5kZWQgewogICAgICAgIF9zdXNwZW5kZWQgPSB0cnVlOwogICAgICAgIGVtaXQgU3VzcGVuZGVkKG1zZy5zZW5kZXIpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBDYWxsZWQgYnkgYSBTdXNwZW5kZXIgdG8gdW5TdXNwZW5kLCByZXR1cm5zIHRvIG5vcm1hbCBzdGF0ZS4KICAgICAqLwogICAgZnVuY3Rpb24gdW5TdXNwZW5kKCkgcHVibGljIG9ubHlTdXNwZW5kZXIgd2hlblN1c3BlbmRlZCB7CiAgICAgICAgX3N1c3BlbmRlZCA9IGZhbHNlOwogICAgICAgIGVtaXQgVW5TdXNwZW5kZWQobXNnLnNlbmRlcik7CiAgICB9Cn0KCmNvbnRyYWN0IElCQUMwMDFSZWNlaXZlciB7CiAgICAvKioKICAgICAqIEBub3RpY2UgSGFuZGxlIHRoZSByZWNlaXB0IG9mIGFuIE5GVAogICAgICogQGRldiBUaGUgQkFDMDAxIHNtYXJ0IGNvbnRyYWN0IGNhbGxzIHRoaXMgZnVuY3Rpb24gb24gdGhlIHJlY2lwaWVudAogICAgICovCiAgICBmdW5jdGlvbiBvbkJBQzAwMVJlY2VpdmVkKGFkZHJlc3Mgb3BlcmF0b3IsIGFkZHJlc3MgZnJvbSwgdWludDI1NiB2YWx1ZSwgYnl0ZXMgZGF0YSkKICAgIHB1YmxpYyByZXR1cm5zIChieXRlczQpOwp9Cgpjb250cmFjdCBCQUMwMDFIb2xkZXIgaXMgSUJBQzAwMVJlY2VpdmVyIHsKICAgIGZ1bmN0aW9uIG9uQkFDMDAxUmVjZWl2ZWQoYWRkcmVzcywgYWRkcmVzcywgdWludDI1NiwgYnl0ZXMpIHB1YmxpYyByZXR1cm5zIChieXRlczQpIHsKICAgICAgICByZXR1cm4gdGhpcy5vbkJBQzAwMVJlY2VpdmVkLnNlbGVjdG9yOwogICAgfQp9CgoKLyoqCiAqIEB0aXRsZSBTdGFuZGFyZCBCQUMwMDEgYXNzZXQKICovCmNvbnRyYWN0IEJBQzAwMSBpcyBJc3N1ZXJSb2xlLCBTdXNwZW5kYWJsZSB7CiAgICB1c2luZyBTYWZlTWF0aCBmb3IgdWludDI1NjsKICAgIHVzaW5nIEFkZHJlc3MgZm9yIGFkZHJlc3M7CgogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTYpIHByaXZhdGUgX2JhbGFuY2VzOwogICAgbWFwcGluZyhhZGRyZXNzID0+IG1hcHBpbmcoYWRkcmVzcyA9PiB1aW50MjU2KSkgcHJpdmF0ZSBfYWxsb3dlZDsKICAgIHVpbnQyNTYgcHJpdmF0ZSBfdG90YWxBbW91bnQ7CiAgICBzdHJpbmcgcHJpdmF0ZSBfZGVzY3JpcHRpb247CiAgICBzdHJpbmcgcHJpdmF0ZSBfc2hvcnROYW1lOwogICAgdWludDggcHJpdmF0ZSAgX21pblVuaXQ7CgogICAgLy8gRXF1YWxzIHRvIGBieXRlczQoa2VjY2FrMjU2KCJvbkJBQzAwMVJlY2VpdmVkKGFkZHJlc3MsYWRkcmVzcyx1aW50MjU2LGJ5dGVzKSIpKWAKICAgIGJ5dGVzNCBwcml2YXRlIGNvbnN0YW50IF9CQUMwMDFfUkVDRUlWRUQgPSAweGM3M2QxNmFlOwoKCiAgICBldmVudCBTZW5kKCBhZGRyZXNzIGluZGV4ZWQgZnJvbSwgYWRkcmVzcyBpbmRleGVkIHRvLCB1aW50MjU2IHZhbHVlLCBieXRlcyBkYXRhKTsKICAgIGV2ZW50IEFwcHJvdmFsKCBhZGRyZXNzIGluZGV4ZWQgb3duZXIsIGFkZHJlc3MgaW5kZXhlZCBzcGVuZGVyLCB1aW50MjU2IHZhbHVlKTsKCgogICAgY29uc3RydWN0b3Ioc3RyaW5nIG1lbW9yeSBkZXNjcmlwdGlvbiwgc3RyaW5nIG1lbW9yeSBzaG9ydE5hbWUsIHVpbnQ4IG1pblVuaXQsIHVpbnQyNTYgdG90YWxBbW91bnQpIHB1YmxpYyB7CiAgICAgICAgX2Rlc2NyaXB0aW9uID0gZGVzY3JpcHRpb247CiAgICAgICAgX3Nob3J0TmFtZSA9IHNob3J0TmFtZTsKICAgICAgICBfbWluVW5pdCA9IG1pblVuaXQ7CiAgICAgICAgX2lzc3VlKG1zZy5zZW5kZXIsIHRvdGFsQW1vdW50ICogKDEwICoqIHVpbnQyNTYobWluVW5pdCkpLCAiIik7CiAgICB9CgoKICAgIGZ1bmN0aW9uIHRvdGFsQW1vdW50KCkgcHVibGljIHZpZXcgcmV0dXJucyAodWludDI1NikgewogICAgICAgIHJldHVybiBfdG90YWxBbW91bnQ7CiAgICB9CgogICAgZnVuY3Rpb24gYmFsYW5jZShhZGRyZXNzIG93bmVyKSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50MjU2KSB7CiAgICAgICAgcmV0dXJuIF9iYWxhbmNlc1tvd25lcl07CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IEZ1bmN0aW9uIHRvIGNoZWNrIHRoZSBhbW91bnQgb2YgYXNzZXRzIHRoYXQgYW4gb3duZXIgYWxsb3dlZCB0byBhIHNwZW5kZXIuCiAgICAgKi8KICAgIGZ1bmN0aW9uIGFsbG93YW5jZShhZGRyZXNzIG93bmVyLCBhZGRyZXNzIHNwZW5kZXIpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQyNTYpIHsKICAgICAgICByZXR1cm4gX2FsbG93ZWRbb3duZXJdW3NwZW5kZXJdOwogICAgfQoKICAgIGZ1bmN0aW9uIHNlbmQoYWRkcmVzcyB0bywgdWludDI1NiB2YWx1ZSwgYnl0ZXMgZGF0YSkgcHVibGljIHdoZW5Ob3RTdXNwZW5kZWQgewogICAgICAgIF9zZW5kKG1zZy5zZW5kZXIsIHRvLCB2YWx1ZSwgZGF0YSk7CiAgICAgICAgcmVxdWlyZShfY2hlY2tPbkJBQzAwMVJlY2VpdmVkKG1zZy5zZW5kZXIsIHRvLCB2YWx1ZSwgZGF0YSksICJCQUMwMDE6IHNlbmQgdG8gbm9uIEJBQzAwMVJlY2VpdmVyIGltcGxlbWVudGVyIik7CgogICAgfQoKLy8gICAgZnVuY3Rpb24gc2FmZVNlbmQoYWRkcmVzcyB0bywgdWludDI1NiB2YWx1ZSwgYnl0ZXMgZGF0YSkgcHVibGljIHdoZW5Ob3RTdXNwZW5kZWQgewovLyAgICAgICAgc2VuZCh0bywgdmFsdWUsIGRhdGEpOwovLyAgICAgICAgcmVxdWlyZShfY2hlY2tPbkJBQzAwMVJlY2VpdmVkKG1zZy5zZW5kZXIsIHRvLCB2YWx1ZSwgZGF0YSksICJCQUMwMDE6IHNlbmQgdG8gbm9uIEJBQzAwMVJlY2VpdmVyIGltcGxlbWVudGVyIik7Ci8vICAgIH0KCgogICAgLyoqCiAgICAgKiBAZGV2IEFwcHJvdmUgdGhlIHBhc3NlZCBhZGRyZXNzIHRvIHNwZW5kIHRoZSBzcGVjaWZpZWQgYW1vdW50IG9mIGFzc2V0cyBvbiBiZWhhbGYgb2YgbXNnLnNlbmRlci4KICAgICAqLwogICAgZnVuY3Rpb24gYXBwcm92ZShhZGRyZXNzIHNwZW5kZXIsIHVpbnQyNTYgdmFsdWUpIHB1YmxpYyB3aGVuTm90U3VzcGVuZGVkIHJldHVybnMgKGJvb2wpIHsKICAgICAgICBfYXBwcm92ZShtc2cuc2VuZGVyLCBzcGVuZGVyLCB2YWx1ZSk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IFNlbmQgYXNzZXRzIGZyb20gb25lIGFkZHJlc3MgdG8gYW5vdGhlci4KICAgICAqLwogICAgZnVuY3Rpb24gc2VuZEZyb20oYWRkcmVzcyBmcm9tLCBhZGRyZXNzIHRvLCB1aW50MjU2IHZhbHVlLCBieXRlcyBkYXRhKSBwdWJsaWMgd2hlbk5vdFN1c3BlbmRlZCB7CiAgICAgICAgX3NlbmQoZnJvbSwgdG8sIHZhbHVlLCBkYXRhKTsKICAgICAgICBfYXBwcm92ZShmcm9tLCBtc2cuc2VuZGVyLCBfYWxsb3dlZFtmcm9tXVttc2cuc2VuZGVyXS5zdWIodmFsdWUpKTsKICAgICAgICAvL2FkZAogICAgICAgIHJlcXVpcmUoX2NoZWNrT25CQUMwMDFSZWNlaXZlZChmcm9tLCB0bywgdmFsdWUsIGRhdGEpLCAiQkFDMDAxOiBzZW5kIHRvIG5vbiBCQUMwMDFSZWNlaXZlciBpbXBsZW1lbnRlciIpOwoKCiAgICB9CgovLy8vIHNhZmUgdG9kbwovLyAgICBmdW5jdGlvbiBzYWZlU2VuZEZyb20oYWRkcmVzcyBmcm9tLCBhZGRyZXNzIHRvLCB1aW50MjU2IHZhbHVlLCBieXRlcyBkYXRhKSBwdWJsaWMgd2hlbk5vdFN1c3BlbmRlZCB7Ci8vICAgICAgICBzZW5kRnJvbShmcm9tLCB0bywgdmFsdWUsIGRhdGEpOwovLyAgICAgICAgcmVxdWlyZShfY2hlY2tPbkJBQzAwMVJlY2VpdmVkKGZyb20sIHRvLCB2YWx1ZSwgZGF0YSksICJCQUMwMDE6IHNlbmQgdG8gbm9uIEJBQzAwMVJlY2VpdmVyIGltcGxlbWVudGVyIik7Ci8vICAgIH0KCgogICAgZnVuY3Rpb24gYmF0Y2hTZW5kKGFkZHJlc3NbXSB0bywgdWludDI1NltdIHZhbHVlcywgYnl0ZXMgZGF0YSkgcHVibGljIHdoZW5Ob3RTdXNwZW5kZWQgewoKICAgICAgICAvLyBNVVNUIFRocm93IG9uIGVycm9ycwoKICAgICAgICByZXF1aXJlKHRvLmxlbmd0aCA9PSB2YWx1ZXMubGVuZ3RoLCAidG8gYW5kIHZhbHVlcyBhcnJheSBsZW5naHQgbXVzdCBtYXRjaC4iKTsKCiAgICAgICAgZm9yICh1aW50MjU2IGkgPSAwOyBpIDwgdG8ubGVuZ3RoOyArK2kpIHsKICAgICAgICAgICAgcmVxdWlyZSh0b1tpXSAhPSBhZGRyZXNzKDB4MCksICJkZXN0aW5hdGlvbiBhZGRyZXNzIG11c3QgYmUgbm9uLXplcm8uIik7CgogICAgICAgICAgICBzZW5kKHRvW2ldLCB2YWx1ZXNbaV0sIGRhdGEpOwogICAgICAgIH0KICAgIH0KCgogICAgZnVuY3Rpb24gX2NoZWNrT25CQUMwMDFSZWNlaXZlZChhZGRyZXNzIGZyb20sIGFkZHJlc3MgdG8sIHVpbnQyNTYgdmFsdWUsIGJ5dGVzIGRhdGEpCiAgICBpbnRlcm5hbCByZXR1cm5zIChib29sKQogICAgewogICAgICAgIGlmICghdG8uaXNDb250cmFjdCgpKSB7CiAgICAgICAgICAgIHJldHVybiB0cnVlOwogICAgICAgIH0KCiAgICAgICAgYnl0ZXM0IHJldHZhbCA9IElCQUMwMDFSZWNlaXZlcih0bykub25CQUMwMDFSZWNlaXZlZChmcm9tLCB0bywgdmFsdWUsIGRhdGEpOwogICAgICAgIHJldHVybiAocmV0dmFsID09IF9CQUMwMDFfUkVDRUlWRUQpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBJbmNyZWFzZSB0aGUgYW1vdW50IG9mIGFzc2V0cyB0aGF0IGFuIG93bmVyIGFsbG93ZWQgdG8gYSBzcGVuZGVyLgogICAgICovCiAgICBmdW5jdGlvbiBpbmNyZWFzZUFsbG93YW5jZShhZGRyZXNzIHNwZW5kZXIsIHVpbnQyNTYgYWRkZWRWYWx1ZSkgcHVibGljIHdoZW5Ob3RTdXNwZW5kZWQgcmV0dXJucyAoYm9vbCkgewogICAgICAgIF9hcHByb3ZlKG1zZy5zZW5kZXIsIHNwZW5kZXIsIF9hbGxvd2VkW21zZy5zZW5kZXJdW3NwZW5kZXJdLmFkZChhZGRlZFZhbHVlKSk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IERlY3JlYXNlIHRoZSBhbW91bnQgb2YgYXNzZXRzIHRoYXQgYW4gb3duZXIgYWxsb3dlZCB0byBhIHNwZW5kZXIuCiAgICAgKiBhcHByb3ZlIHNob3VsZCBiZSBjYWxsZWQgd2hlbiBfYWxsb3dlZFttc2cuc2VuZGVyXVtzcGVuZGVyXSA9PSAwLiBUbyBkZWNyZW1lbnQKICAgICAqLwogICAgZnVuY3Rpb24gZGVjcmVhc2VBbGxvd2FuY2UoYWRkcmVzcyBzcGVuZGVyLCB1aW50MjU2IHN1YnRyYWN0ZWRWYWx1ZSkgcHVibGljIHdoZW5Ob3RTdXNwZW5kZWQgcmV0dXJucyAoYm9vbCkgewogICAgICAgIF9hcHByb3ZlKG1zZy5zZW5kZXIsIHNwZW5kZXIsIF9hbGxvd2VkW21zZy5zZW5kZXJdW3NwZW5kZXJdLnN1YihzdWJ0cmFjdGVkVmFsdWUpKTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBmdW5jdGlvbiBkZXN0cm95KHVpbnQyNTYgdmFsdWUsIGJ5dGVzIGRhdGEpIHB1YmxpYyB7CiAgICAgICAgX2Rlc3Ryb3kobXNnLnNlbmRlciwgdmFsdWUsIGRhdGEpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBCdXJucyBhIHNwZWNpZmljIGFtb3VudCBvZiBhc3NldHMgZnJvbSB0aGUgdGFyZ2V0IGFkZHJlc3MgYW5kIGRlY3JlbWVudHMgYWxsb3dhbmNlLgogICAgICovCiAgICBmdW5jdGlvbiBkZXN0cm95RnJvbShhZGRyZXNzIGZyb20sIHVpbnQyNTYgdmFsdWUsIGJ5dGVzIGRhdGEpIHB1YmxpYyB7CiAgICAgICAgX2Rlc3Ryb3lGcm9tKGZyb20sIHZhbHVlLCBkYXRhKTsKICAgIH0KCgogICAgZnVuY3Rpb24gZGVzY3JpcHRpb24oKSBwdWJsaWMgdmlldyByZXR1cm5zIChzdHJpbmcgbWVtb3J5KSB7CiAgICAgICAgcmV0dXJuIF9kZXNjcmlwdGlvbjsKICAgIH0KCiAgICAvKioKICAgICAqIEByZXR1cm4gdGhlIHNob3J0TmFtZSBvZiB0aGUgYXNzZXQuCiAgICAgKi8KICAgIGZ1bmN0aW9uIHNob3J0TmFtZSgpIHB1YmxpYyB2aWV3IHJldHVybnMgKHN0cmluZyBtZW1vcnkpIHsKICAgICAgICByZXR1cm4gX3Nob3J0TmFtZTsKICAgIH0KCiAgICAvKioKICAgICAqIEByZXR1cm4gdGhlIG51bWJlciBvZiBtaW5Vbml0IG9mIHRoZSBhc3NldC4KICAgICAqLwogICAgZnVuY3Rpb24gbWluVW5pdCgpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQ4KSB7CiAgICAgICAgcmV0dXJuIF9taW5Vbml0OwogICAgfQoKCiAgICBmdW5jdGlvbiBpc3N1ZShhZGRyZXNzIHRvLCB1aW50MjU2IHZhbHVlLCBieXRlcyBkYXRhKSBwdWJsaWMgb25seUlzc3VlciByZXR1cm5zIChib29sKSB7CiAgICAgICAgX2lzc3VlKHRvLCB2YWx1ZSwgZGF0YSk7CiAgICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgICAvKioKICAgICAqIEBkZXYgU2VuZCBhc3NldCBmb3IgYSBzcGVjaWZpZWQgYWRkcmVzc2VzLgogICAgICovCiAgICBmdW5jdGlvbiBfc2VuZChhZGRyZXNzIGZyb20sIGFkZHJlc3MgdG8sIHVpbnQyNTYgdmFsdWUsIGJ5dGVzIGRhdGEpIGludGVybmFsIHsKICAgICAgICByZXF1aXJlKHRvICE9IGFkZHJlc3MoMCksICJCQUMwMDE6IHNlbmQgdG8gdGhlIHplcm8gYWRkcmVzcyIpOwoKICAgICAgICBfYmFsYW5jZXNbZnJvbV0gPSBfYmFsYW5jZXNbZnJvbV0uc3ViKHZhbHVlKTsKICAgICAgICBfYmFsYW5jZXNbdG9dID0gX2JhbGFuY2VzW3RvXS5hZGQodmFsdWUpOwogICAgICAgIGVtaXQgU2VuZCggZnJvbSwgdG8sIHZhbHVlLCBkYXRhKTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgSW50ZXJuYWwgZnVuY3Rpb24gdGhhdCBpc3N1ZXMgYW4gYW1vdW50IG9mIHRoZSBhc3NldCBhbmQgYXNzaWducyBpdCB0bwogICAgICovCiAgICBmdW5jdGlvbiBfaXNzdWUoYWRkcmVzcyBhY2NvdW50LCB1aW50MjU2IHZhbHVlLCBieXRlcyBkYXRhKSBpbnRlcm5hbCB7CiAgICAgICAgcmVxdWlyZShhY2NvdW50ICE9IGFkZHJlc3MoMCksICJCQUMwMDE6IGlzc3VlIHRvIHRoZSB6ZXJvIGFkZHJlc3MiKTsKCiAgICAgICAgX3RvdGFsQW1vdW50ID0gX3RvdGFsQW1vdW50LmFkZCh2YWx1ZSk7CiAgICAgICAgX2JhbGFuY2VzW2FjY291bnRdID0gX2JhbGFuY2VzW2FjY291bnRdLmFkZCh2YWx1ZSk7CiAgICAgICAgZW1pdCBTZW5kKCBhZGRyZXNzKDApLCBhY2NvdW50LCB2YWx1ZSwgZGF0YSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IEludGVybmFsIGZ1bmN0aW9uIHRoYXQgZGVzdHJveXMgYW4gYW1vdW50IG9mIHRoZSBhc3NldCBvZiBhIGdpdmVuCiAgICAgKi8KICAgIGZ1bmN0aW9uIF9kZXN0cm95KGFkZHJlc3MgYWNjb3VudCwgdWludDI1NiB2YWx1ZSwgYnl0ZXMgZGF0YSkgaW50ZXJuYWwgewogICAgICAgIHJlcXVpcmUoYWNjb3VudCAhPSBhZGRyZXNzKDApLCAiQkFDMDAxOiBkZXN0cm95IGZyb20gdGhlIHplcm8gYWRkcmVzcyIpOwoKICAgICAgICBfdG90YWxBbW91bnQgPSBfdG90YWxBbW91bnQuc3ViKHZhbHVlKTsKICAgICAgICBfYmFsYW5jZXNbYWNjb3VudF0gPSBfYmFsYW5jZXNbYWNjb3VudF0uc3ViKHZhbHVlKTsKICAgICAgICBlbWl0IFNlbmQoIGFjY291bnQsIGFkZHJlc3MoMCksIHZhbHVlLCBkYXRhKTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgQXBwcm92ZSBhbiBhZGRyZXNzIHRvIHNwZW5kIGFub3RoZXIgYWRkcmVzc2VzJyBhc3NldHMuCiAgICAgKi8KICAgIGZ1bmN0aW9uIF9hcHByb3ZlKGFkZHJlc3Mgb3duZXIsIGFkZHJlc3Mgc3BlbmRlciwgdWludDI1NiB2YWx1ZSkgaW50ZXJuYWwgewogICAgICAgIHJlcXVpcmUob3duZXIgIT0gYWRkcmVzcygwKSwgIkJBQzAwMTogYXBwcm92ZSBmcm9tIHRoZSB6ZXJvIGFkZHJlc3MiKTsKICAgICAgICByZXF1aXJlKHNwZW5kZXIgIT0gYWRkcmVzcygwKSwgIkJBQzAwMTogYXBwcm92ZSB0byB0aGUgemVybyBhZGRyZXNzIik7CgogICAgICAgIF9hbGxvd2VkW293bmVyXVtzcGVuZGVyXSA9IHZhbHVlOwogICAgICAgIGVtaXQgQXBwcm92YWwoIG93bmVyLCBzcGVuZGVyLCB2YWx1ZSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IEludGVybmFsIGZ1bmN0aW9uIHRoYXQgZGVzdHJveXMgYW4gYW1vdW50IG9mIHRoZSBhc3NldCBvZiBhIGdpdmVuCiAgICAgKi8KICAgIGZ1bmN0aW9uIF9kZXN0cm95RnJvbShhZGRyZXNzIGFjY291bnQsIHVpbnQyNTYgdmFsdWUsIGJ5dGVzIGRhdGEpIGludGVybmFsIHsKICAgICAgICBfZGVzdHJveShhY2NvdW50LCB2YWx1ZSwgZGF0YSk7CiAgICAgICAgX2FwcHJvdmUoYWNjb3VudCwgbXNnLnNlbmRlciwgX2FsbG93ZWRbYWNjb3VudF1bbXNnLnNlbmRlcl0uc3ViKHZhbHVlKSk7CiAgICB9Cn0KCg=="; public static final String I_BAC001_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjQ7CgoKaW50ZXJmYWNlIElCQUMwMDEgewoKICAgIGZ1bmN0aW9uIHRvdGFsQW1vdW50KCkgcHVibGljIHZpZXcgcmV0dXJucyAodWludDI1Nik7CgogICAgZnVuY3Rpb24gYmFsYW5jZShhZGRyZXNzIG93bmVyKSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50MjU2KTsKCiAgICBmdW5jdGlvbiBzZW5kKGFkZHJlc3MgdG8sIHVpbnQyNTYgdmFsdWUsIGJ5dGVzIGRhdGEpIHB1YmxpYyA7CgogICAgZnVuY3Rpb24gc2VuZEZyb20oYWRkcmVzcyBmcm9tLCBhZGRyZXNzIHRvLCB1aW50MjU2IHZhbHVlLCBieXRlcyBkYXRhKSBwdWJsaWM7CgogICAgZnVuY3Rpb24gYWxsb3dhbmNlKGFkZHJlc3Mgb3duZXIsIGFkZHJlc3Mgc3BlbmRlcikgcHVibGljIHZpZXcgcmV0dXJucyAodWludDI1Nik7CgogICAgZnVuY3Rpb24gYXBwcm92ZShhZGRyZXNzIHNwZW5kZXIsIHVpbnQyNTYgYW1vdW50KSBwdWJsaWMgcmV0dXJucyAoYm9vbCk7CgogICAgZnVuY3Rpb24gZGVzdHJveSh1aW50MjU2IHZhbHVlLCBieXRlcyBkYXRhKSBwdWJsaWM7CgogICAgZnVuY3Rpb24gZGVzdHJveUZyb20oYWRkcmVzcyBmcm9tLCB1aW50MjU2IHZhbHVlLCBieXRlcyBkYXRhKSBwdWJsaWM7CgogICAgZnVuY3Rpb24gaXNzdWUoYWRkcmVzcyB0bywgdWludDI1NiB2YWx1ZSwgYnl0ZXMgZGF0YSkgcHVibGljICByZXR1cm5zIChib29sKTsKCiAgICBmdW5jdGlvbiBiYXRjaFNlbmQoYWRkcmVzc1tdIHRvLCB1aW50MjU2W10gdmFsdWVzLCBieXRlcyBkYXRhKSBwdWJsaWM7CgogICAgZnVuY3Rpb24gaW5jcmVhc2VBbGxvd2FuY2UoYWRkcmVzcyBzcGVuZGVyLCB1aW50MjU2IGFkZGVkVmFsdWUpIHB1YmxpYyAgcmV0dXJucyAoYm9vbCk7CgogICAgZnVuY3Rpb24gZGVjcmVhc2VBbGxvd2FuY2UoYWRkcmVzcyBzcGVuZGVyLCB1aW50MjU2IHN1YnRyYWN0ZWRWYWx1ZSkgcHVibGljICByZXR1cm5zIChib29sKTsKCiAgICBldmVudCBTZW5kKGFkZHJlc3MgaW5kZXhlZCBmcm9tLCBhZGRyZXNzIGluZGV4ZWQgdG8sIHVpbnQyNTYgdmFsdWUsIGJ5dGVzIGRhdGEpOwoKICAgIGV2ZW50IEFwcHJvdmFsKGFkZHJlc3MgaW5kZXhlZCBvd25lciwgYWRkcmVzcyBpbmRleGVkIHNwZW5kZXIsIHVpbnQyNTYgdmFsdWUpOwoKfQ=="; + public static final String BAC002_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjU7CgppbXBvcnQgIi4vUmVnaXN0ZXIuc29sIjsKaW1wb3J0ICIuL0NvdW50ZXJzLnNvbCI7CmltcG9ydCAiLi9Sb2xlcy5zb2wiOwoKCmNvbnRyYWN0IElCQUMwMDJSZWNlaXZlciB7CiAgICAvKioKICAgICAqIEBub3RpY2UgSGFuZGxlIHRoZSByZWNlaXB0IG9mIGFuIE5GVAogICAgICogQGRldiBUaGUgQkFDMDAyIHNtYXJ0IGNvbnRyYWN0IGNhbGxzIHRoaXMgZnVuY3Rpb24gb24gdGhlIHJlY2lwaWVudAogICAgICovCiAgICBmdW5jdGlvbiBvbkJBQzAwMlJlY2VpdmVkKGFkZHJlc3Mgb3BlcmF0b3IsIGFkZHJlc3MgZnJvbSwgdWludDI1NiBhc3NldElkLCBieXRlcyBtZW1vcnkgZGF0YSkKICAgIHB1YmxpYyByZXR1cm5zIChieXRlczQpOwp9Cgpjb250cmFjdCBCQUMwMDJIb2xkZXIgaXMgSUJBQzAwMlJlY2VpdmVyIHsKICAgIGZ1bmN0aW9uIG9uQkFDMDAyUmVjZWl2ZWQoYWRkcmVzcywgYWRkcmVzcywgdWludDI1NiwgYnl0ZXMgbWVtb3J5KSBwdWJsaWMgcmV0dXJucyAoYnl0ZXM0KSB7CiAgICAgICAgcmV0dXJuIHRoaXMub25CQUMwMDJSZWNlaXZlZC5zZWxlY3RvcjsKICAgIH0KfQoKY29udHJhY3QgSXNzdWVyUm9sZSB7CiAgICB1c2luZyBSb2xlcyBmb3IgUm9sZXMuUm9sZTsKCiAgICBldmVudCBJc3N1ZXJBZGRlZChhZGRyZXNzIGluZGV4ZWQgYWNjb3VudCk7CiAgICBldmVudCBJc3N1ZXJSZW1vdmVkKGFkZHJlc3MgaW5kZXhlZCBhY2NvdW50KTsKCiAgICBSb2xlcy5Sb2xlIHByaXZhdGUgX2lzc3VlcnM7CgogICAgY29uc3RydWN0b3IgKCkgaW50ZXJuYWwgewogICAgICAgIF9hZGRJc3N1ZXIobXNnLnNlbmRlcik7CiAgICB9CgogICAgbW9kaWZpZXIgb25seUlzc3VlcigpIHsKICAgICAgICByZXF1aXJlKGlzSXNzdWVyKG1zZy5zZW5kZXIpLCAiSXNzdWVyUm9sZTogY2FsbGVyIGRvZXMgbm90IGhhdmUgdGhlIElzc3VlciByb2xlIik7CiAgICAgICAgXzsKICAgIH0KCiAgICBmdW5jdGlvbiBpc0lzc3VlcihhZGRyZXNzIGFjY291bnQpIHB1YmxpYyB2aWV3IHJldHVybnMgKGJvb2wpIHsKICAgICAgICByZXR1cm4gX2lzc3VlcnMuaGFzKGFjY291bnQpOwogICAgfQoKICAgIGZ1bmN0aW9uIGFkZElzc3VlcihhZGRyZXNzIGFjY291bnQpIHB1YmxpYyBvbmx5SXNzdWVyIHsKICAgICAgICBfYWRkSXNzdWVyKGFjY291bnQpOwogICAgfQoKICAgIGZ1bmN0aW9uIHJlbm91bmNlSXNzdWVyKCkgcHVibGljIHsKICAgICAgICBfcmVtb3ZlSXNzdWVyKG1zZy5zZW5kZXIpOwogICAgfQoKICAgIGZ1bmN0aW9uIF9hZGRJc3N1ZXIoYWRkcmVzcyBhY2NvdW50KSBpbnRlcm5hbCB7CiAgICAgICAgX2lzc3VlcnMuYWRkKGFjY291bnQpOwogICAgICAgIGVtaXQgSXNzdWVyQWRkZWQoYWNjb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gX3JlbW92ZUlzc3VlcihhZGRyZXNzIGFjY291bnQpIGludGVybmFsIHsKICAgICAgICBfaXNzdWVycy5yZW1vdmUoYWNjb3VudCk7CiAgICAgICAgZW1pdCBJc3N1ZXJSZW1vdmVkKGFjY291bnQpOwogICAgfQp9Cgpjb250cmFjdCBTdXNwZW5kZXJSb2xlIHsKICAgIHVzaW5nIFJvbGVzIGZvciBSb2xlcy5Sb2xlOwoKICAgIGV2ZW50IFN1c3BlbmRlckFkZGVkKGFkZHJlc3MgaW5kZXhlZCBhY2NvdW50KTsKICAgIGV2ZW50IFN1c3BlbmRlclJlbW92ZWQoYWRkcmVzcyBpbmRleGVkIGFjY291bnQpOwoKICAgIFJvbGVzLlJvbGUgcHJpdmF0ZSBfc3VzcGVuZGVyczsKCiAgICBjb25zdHJ1Y3RvciAoKSBpbnRlcm5hbCB7CiAgICAgICAgX2FkZFN1c3BlbmRlcihtc2cuc2VuZGVyKTsKICAgIH0KCiAgICBtb2RpZmllciBvbmx5U3VzcGVuZGVyKCkgewogICAgICAgIHJlcXVpcmUoaXNTdXNwZW5kZXIobXNnLnNlbmRlciksICJTdXNwZW5kZXJSb2xlOiBjYWxsZXIgZG9lcyBub3QgaGF2ZSB0aGUgU3VzcGVuZGVyIHJvbGUiKTsKICAgICAgICBfOwogICAgfQoKICAgIGZ1bmN0aW9uIGlzU3VzcGVuZGVyKGFkZHJlc3MgYWNjb3VudCkgcHVibGljIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybiBfc3VzcGVuZGVycy5oYXMoYWNjb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gYWRkU3VzcGVuZGVyKGFkZHJlc3MgYWNjb3VudCkgcHVibGljIG9ubHlTdXNwZW5kZXIgewogICAgICAgIF9hZGRTdXNwZW5kZXIoYWNjb3VudCk7CiAgICB9CgogICAgZnVuY3Rpb24gcmVub3VuY2VTdXNwZW5kZXIoKSBwdWJsaWMgewogICAgICAgIF9yZW1vdmVTdXNwZW5kZXIobXNnLnNlbmRlcik7CiAgICB9CgogICAgZnVuY3Rpb24gX2FkZFN1c3BlbmRlcihhZGRyZXNzIGFjY291bnQpIGludGVybmFsIHsKICAgICAgICBfc3VzcGVuZGVycy5hZGQoYWNjb3VudCk7CiAgICAgICAgZW1pdCBTdXNwZW5kZXJBZGRlZChhY2NvdW50KTsKICAgIH0KCiAgICBmdW5jdGlvbiBfcmVtb3ZlU3VzcGVuZGVyKGFkZHJlc3MgYWNjb3VudCkgaW50ZXJuYWwgewogICAgICAgIF9zdXNwZW5kZXJzLnJlbW92ZShhY2NvdW50KTsKICAgICAgICBlbWl0IFN1c3BlbmRlclJlbW92ZWQoYWNjb3VudCk7CiAgICB9Cn0KCmNvbnRyYWN0IFN1c3BlbmRhYmxlIGlzIFN1c3BlbmRlclJvbGUgewoKICAgIGV2ZW50IFN1c3BlbmRlZChhZGRyZXNzIGFjY291bnQpOwogICAgZXZlbnQgVW5TdXNwZW5kZWQoYWRkcmVzcyBhY2NvdW50KTsKCiAgICBib29sIHByaXZhdGUgX3N1c3BlbmRlZDsKCiAgICBjb25zdHJ1Y3RvciAoKSBpbnRlcm5hbCB7CiAgICAgICAgX3N1c3BlbmRlZCA9IGZhbHNlOwogICAgfQoKICAgIC8qKgogICAgICogQHJldHVybiBUcnVlIGlmIHRoZSBjb250cmFjdCBpcyBzdXNwZW5kZWQsIGZhbHNlIG90aGVyd2lzZS4KICAgICAqLwogICAgZnVuY3Rpb24gc3VzcGVuZGVkKCkgcHVibGljIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybiBfc3VzcGVuZGVkOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBNb2RpZmllciB0byBtYWtlIGEgZnVuY3Rpb24gY2FsbGFibGUgb25seSB3aGVuIHRoZSBjb250cmFjdCBpcyBub3Qgc3VzcGVuZGVkLgogICAgICovCiAgICBtb2RpZmllciB3aGVuTm90U3VzcGVuZGVkKCkgewogICAgICAgIHJlcXVpcmUoIV9zdXNwZW5kZWQsICJTdXNwZW5kYWJsZTogc3VzcGVuZGVkIik7CiAgICAgICAgXzsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgTW9kaWZpZXIgdG8gbWFrZSBhIGZ1bmN0aW9uIGNhbGxhYmxlIG9ubHkgd2hlbiB0aGUgY29udHJhY3QgaXMgc3VzcGVuZGVkLgogICAgICovCiAgICBtb2RpZmllciB3aGVuU3VzcGVuZGVkKCkgewogICAgICAgIHJlcXVpcmUoX3N1c3BlbmRlZCwgIlN1c3BlbmRhYmxlOiBub3Qgc3VzcGVuZGVkIik7CiAgICAgICAgXzsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgQ2FsbGVkIGJ5IGEgU3VzcGVuZGVyIHRvIHN1c3BlbmQsIHRyaWdnZXJzIHN0b3BwZWQgc3RhdGUuCiAgICAgKi8KICAgIGZ1bmN0aW9uIHN1c3BlbmQoKSBwdWJsaWMgb25seVN1c3BlbmRlciB3aGVuTm90U3VzcGVuZGVkIHsKICAgICAgICBfc3VzcGVuZGVkID0gdHJ1ZTsKICAgICAgICBlbWl0IFN1c3BlbmRlZChtc2cuc2VuZGVyKTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgQ2FsbGVkIGJ5IGEgU3VzcGVuZGVyIHRvIHVuU3VzcGVuZCwgcmV0dXJucyB0byBub3JtYWwgc3RhdGUuCiAgICAgKi8KICAgIGZ1bmN0aW9uIHVuU3VzcGVuZCgpIHB1YmxpYyBvbmx5U3VzcGVuZGVyIHdoZW5TdXNwZW5kZWQgewogICAgICAgIF9zdXNwZW5kZWQgPSBmYWxzZTsKICAgICAgICBlbWl0IFVuU3VzcGVuZGVkKG1zZy5zZW5kZXIpOwogICAgfQp9CgovL2RlbGV0ZSByZWdpc3Rlcgpjb250cmFjdCBCQUMwMDIgaXMgIElzc3VlclJvbGUsIFN1c3BlbmRhYmxlIHsKICAgIHVzaW5nIFNhZmVNYXRoIGZvciB1aW50MjU2OwogICAgdXNpbmcgQWRkcmVzcyBmb3IgYWRkcmVzczsKICAgIHVzaW5nIENvdW50ZXJzIGZvciBDb3VudGVycy5Db3VudGVyOwoKICAgIC8vIEVxdWFscyB0byBgYnl0ZXM0KGtlY2NhazI1Nigib25CQUMwMDJSZWNlaXZlZChhZGRyZXNzLGFkZHJlc3MsdWludDI1NixieXRlcykiKSlgCiAgICBieXRlczQgcHJpdmF0ZSBjb25zdGFudCBfQkFDMDAyX1JFQ0VJVkVEID0gMHgzMWY2ZjUwZTsKCiAgICAvLyBNYXBwaW5nIGZyb20gYXNzZXQgSUQgdG8gb3duZXIKICAgIG1hcHBpbmcodWludDI1NiA9PiBhZGRyZXNzKSBwcml2YXRlIF9hc3NldE93bmVyOwoKICAgIC8vIE1hcHBpbmcgZnJvbSBhc3NldCBJRCB0byBhcHByb3ZlZCBhZGRyZXNzCiAgICBtYXBwaW5nKHVpbnQyNTYgPT4gYWRkcmVzcykgcHJpdmF0ZSBfYXNzZXRBcHByb3ZhbHM7CgogICAgLy8gTWFwcGluZyBmcm9tIG93bmVyIHRvIG51bWJlciBvZiBvd25lZCBhc3NldAogICAgbWFwcGluZyhhZGRyZXNzID0+IENvdW50ZXJzLkNvdW50ZXIpIHByaXZhdGUgX293bmVkQXNzZXRzQ291bnQ7CgogICAgLy8gTWFwcGluZyBmcm9tIG93bmVyIHRvIG9wZXJhdG9yIGFwcHJvdmFscwogICAgbWFwcGluZyhhZGRyZXNzID0+IG1hcHBpbmcoYWRkcmVzcyA9PiBib29sKSkgcHJpdmF0ZSBfb3BlcmF0b3JBcHByb3ZhbHM7CgogICAgc3RyaW5nIHByaXZhdGUgX2Rlc2NyaXB0aW9uOwoKICAgIHN0cmluZyBwcml2YXRlIF9zaG9ydE5hbWU7CgogICAgLy8gT3B0aW9uYWwgbWFwcGluZyBmb3IgYXNzZXQgVVJJcwogICAgbWFwcGluZyh1aW50MjU2ID0+IHN0cmluZykgcHJpdmF0ZSBfYXNzZXRVUklzOwoKICAgIC8vIE1hcHBpbmcgZnJvbSBvd25lciB0byBsaXN0IG9mIG93bmVkIGFzc2V0IElEcwogICAgbWFwcGluZyhhZGRyZXNzID0+IHVpbnQyNTZbXSkgcHJpdmF0ZSBfb3duZWRBc3NldHM7CgogICAgLy8gTWFwcGluZyBmcm9tIGFzc2V0IElEIHRvIGluZGV4IG9mIHRoZSBvd25lciBhc3NldHMgbGlzdAogICAgbWFwcGluZyh1aW50MjU2ID0+IHVpbnQyNTYpIHByaXZhdGUgX293bmVkQXNzZXRzSW5kZXg7CgogICAgLy8gQXJyYXkgd2l0aCBhbGwgYXNzZXQgaWRzLCB1c2VkIGZvciBlbnVtZXJhdGlvbgogICAgdWludDI1NltdIHByaXZhdGUgX2FsbEFzc2V0czsKCiAgICAvLyBNYXBwaW5nIGZyb20gYXNzZXQgaWQgdG8gcG9zaXRpb24gaW4gdGhlIGFsbEFzc2V0cyBhcnJheQogICAgbWFwcGluZyh1aW50MjU2ID0+IHVpbnQyNTYpIHByaXZhdGUgX2FsbEFzc2V0c0luZGV4OwoKICAgIGV2ZW50IFNlbmQoYWRkcmVzcyBpbmRleGVkIG9wZXJhdG9yLCBhZGRyZXNzIGluZGV4ZWQgZnJvbSwgYWRkcmVzcyBpbmRleGVkIHRvLCB1aW50MjU2IGFzc2V0SWQsIGJ5dGVzIGRhdGEpOwogICAgZXZlbnQgQXBwcm92YWwoIGFkZHJlc3MgaW5kZXhlZCBvd25lciwgYWRkcmVzcyBhcHByb3ZlZCwgdWludDI1NiBhc3NldElkKTsKICAgIGV2ZW50IEFwcHJvdmFsRm9yQWxsKCBhZGRyZXNzIGluZGV4ZWQgb3duZXIsIGFkZHJlc3MgaW5kZXhlZCBvcGVyYXRvciwgYm9vbCBhcHByb3ZlZCk7CgogICAgLy8gY29uc3RydWN0b3IKICAgIGNvbnN0cnVjdG9yKHN0cmluZyBkZXNjcmlwdGlvbiwgc3RyaW5nIHNob3J0TmFtZSkgcHVibGljCiAgICB7CiAgICAgICAgX2Rlc2NyaXB0aW9uID0gZGVzY3JpcHRpb247CiAgICAgICAgX3Nob3J0TmFtZSA9IHNob3J0TmFtZTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgR2V0cyB0aGUgYmFsYW5jZSBvZiB0aGUgc3BlY2lmaWVkIGFkZHJlc3MuCiAgICAgKi8KICAgIGZ1bmN0aW9uIGJhbGFuY2UoYWRkcmVzcyBvd25lcikgcHVibGljIHZpZXcgcmV0dXJucyAodWludDI1NikgewogICAgICAgIHJlcXVpcmUob3duZXIgIT0gYWRkcmVzcygwKSwgIkJBQzAwMjogYmFsYW5jZSBxdWVyeSBmb3IgdGhlIHplcm8gYWRkcmVzcyIpOwogICAgICAgIHJldHVybiBfb3duZWRBc3NldHNDb3VudFtvd25lcl0uY3VycmVudCgpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBHZXRzIHRoZSBvd25lciBvZiB0aGUgc3BlY2lmaWVkIGFzc2V0IElELgogICAgICovCiAgICBmdW5jdGlvbiBvd25lck9mKHVpbnQyNTYgYXNzZXRJZCkgcHVibGljIHZpZXcgcmV0dXJucyAoYWRkcmVzcykgewogICAgICAgIGFkZHJlc3Mgb3duZXIgPSBfYXNzZXRPd25lclthc3NldElkXTsKICAgICAgICByZXF1aXJlKG93bmVyICE9IGFkZHJlc3MoMCksICJCQUMwMDI6IG93bmVyIHF1ZXJ5IGZvciBub25leGlzdGVudCBhc3NldCIpOwogICAgICAgIHJldHVybiBvd25lcjsKICAgIH0KCgogICAgZnVuY3Rpb24gYXNzZXRPZk93bmVyQnlJbmRleChhZGRyZXNzIG93bmVyLCB1aW50MjU2IGluZGV4KSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50MjU2KSB7CiAgICAgICAgcmVxdWlyZShpbmRleCA8IGJhbGFuY2Uob3duZXIpLCAiQkFDMDAyRW51bWVyYWJsZTogb3duZXIgaW5kZXggb3V0IG9mIGJvdW5kcyIpOwogICAgICAgIHJldHVybiBfb3duZWRBc3NldHNbb3duZXJdW2luZGV4XTsKICAgIH0KCiAgICBmdW5jdGlvbiBhc3NldE9mT3duZXIoYWRkcmVzcyBvd25lcikgcHVibGljIHZpZXcgcmV0dXJucyAodWludDI1NltdKSB7CiAgICAgICAgcmV0dXJuIF9vd25lZEFzc2V0c1tvd25lcl07CiAgICB9CgoKICAgIGZ1bmN0aW9uIGFzc2V0QnlJbmRleCh1aW50MjU2IGluZGV4KSBwdWJsaWMgdmlldyByZXR1cm5zICh1aW50MjU2KSB7CiAgICAgICAgcmVxdWlyZShpbmRleCA8IHRvdGFsU3VwcGx5KCksICJCQUMwMDJFbnVtZXJhYmxlOiBnbG9iYWwgaW5kZXggb3V0IG9mIGJvdW5kcyIpOwogICAgICAgIHJldHVybiBfYWxsQXNzZXRzW2luZGV4XTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgQXBwcm92ZXMgYW5vdGhlciBhZGRyZXNzIHRvIHNlbmQgdGhlIGdpdmVuIGFzc2V0IElECiAgICAgKi8KICAgIGZ1bmN0aW9uIGFwcHJvdmUoYWRkcmVzcyB0bywgdWludDI1NiBhc3NldElkKSBwdWJsaWMgd2hlbk5vdFN1c3BlbmRlZCB7CiAgICAgICAgYWRkcmVzcyBvd25lciA9IG93bmVyT2YoYXNzZXRJZCk7CiAgICAgICAgcmVxdWlyZSh0byAhPSBvd25lciwgIkJBQzAwMjogYXBwcm92YWwgdG8gY3VycmVudCBvd25lciIpOwoKICAgICAgICByZXF1aXJlKG1zZy5zZW5kZXIgPT0gb3duZXIgfHwgaXNBcHByb3ZlZEZvckFsbChvd25lciwgbXNnLnNlbmRlciksCiAgICAgICAgICAgICJCQUMwMDI6IGFwcHJvdmUgY2FsbGVyIGlzIG5vdCBvd25lciBub3IgYXBwcm92ZWQgZm9yIGFsbCIKICAgICAgICApOwogICAgICAgIF9hc3NldEFwcHJvdmFsc1thc3NldElkXSA9IHRvOwogICAgICAgIGVtaXQgQXBwcm92YWwoIG93bmVyLCB0bywgYXNzZXRJZCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IEdldHMgdGhlIGFwcHJvdmVkIGFkZHJlc3MgZm9yIGEgYXNzZXQgSUQsIG9yIHplcm8gaWYgbm8gYWRkcmVzcyBzZXQKICAgICAqLwogICAgZnVuY3Rpb24gZ2V0QXBwcm92ZWQodWludDI1NiBhc3NldElkKSBwdWJsaWMgdmlldyByZXR1cm5zIChhZGRyZXNzKSB7CiAgICAgICAgcmVxdWlyZShfZXhpc3RzKGFzc2V0SWQpLCAiQkFDMDAyOiBhcHByb3ZlZCBxdWVyeSBmb3Igbm9uZXhpc3RlbnQgYXNzZXQiKTsKICAgICAgICByZXR1cm4gX2Fzc2V0QXBwcm92YWxzW2Fzc2V0SWRdOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBTZXRzIG9yIHVuc2V0cyB0aGUgYXBwcm92YWwgb2YgYSBnaXZlbiBvcGVyYXRvcgogICAgICovCiAgICBmdW5jdGlvbiBzZXRBcHByb3ZhbEZvckFsbChhZGRyZXNzIHRvLCBib29sIGFwcHJvdmVkKSBwdWJsaWMgd2hlbk5vdFN1c3BlbmRlZCB7CiAgICAgICAgcmVxdWlyZSh0byAhPSBtc2cuc2VuZGVyLCAiQkFDMDAyOiBhcHByb3ZlIHRvIGNhbGxlciIpOwogICAgICAgIF9vcGVyYXRvckFwcHJvdmFsc1ttc2cuc2VuZGVyXVt0b10gPSBhcHByb3ZlZDsKICAgICAgICBlbWl0IEFwcHJvdmFsRm9yQWxsKCBtc2cuc2VuZGVyLCB0bywgYXBwcm92ZWQpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBUZWxscyB3aGV0aGVyIGFuIG9wZXJhdG9yIGlzIGFwcHJvdmVkIGJ5IGEgZ2l2ZW4gb3duZXIuCiAgICAgKi8KICAgIGZ1bmN0aW9uIGlzQXBwcm92ZWRGb3JBbGwoYWRkcmVzcyBvd25lciwgYWRkcmVzcyBvcGVyYXRvcikgcHVibGljIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJldHVybiBfb3BlcmF0b3JBcHByb3ZhbHNbb3duZXJdW29wZXJhdG9yXTsKICAgIH0KCi8vICAgIC8qKgovLyAgICAgKiBAZGV2IFNlbmRzIHRoZSBvd25lcnNoaXAgb2YgYSBnaXZlbiBhc3NldCBJRCB0byBhbm90aGVyIGFkZHJlc3MuCi8vICAgICAqLwovLyAgICBmdW5jdGlvbiBzZW5kRnJvbShhZGRyZXNzIGZyb20sIGFkZHJlc3MgdG8sIHVpbnQyNTYgYXNzZXRJZCwgYnl0ZXMgbWVtb3J5IGRhdGEpIHB1YmxpYyB3aGVuTm90U3VzcGVuZGVkIHsKLy8gICAgICAgIC8vc29saGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGluZS1sZW5ndGgKLy8gICAgICAgIHJlcXVpcmUoX2lzQXBwcm92ZWRPck93bmVyKG1zZy5zZW5kZXIsIGFzc2V0SWQpLCAiQkFDMDAyOiBzZW5kIGNhbGxlciBpcyBub3Qgb3duZXIgbm9yIGFwcHJvdmVkIik7Ci8vICAgICAgICBfc2VuZEZyb20oZnJvbSwgdG8sIGFzc2V0SWQsIGRhdGEpOwovLyAgICB9CgogICAgLy8gLyoqCiAgICAvLyAgKiBAZGV2IFNhZmVseSBzZW5kcyB0aGUgb3duZXJzaGlwIG9mIGEgZ2l2ZW4gYXNzZXQgSUQgdG8gYW5vdGhlciBhZGRyZXNzCiAgICAvLyAgKi8KICAgIC8vIGZ1bmN0aW9uIHNhZmVTZW5kRnJvbShhZGRyZXNzIGZyb20sIGFkZHJlc3MgdG8sIHVpbnQyNTYgYXNzZXRJZCkgcHVibGljIHdoZW5Ob3RTdXNwZW5kZWQgewogICAgLy8gICAgIHNhZmVTZW5kRnJvbShmcm9tLCB0bywgYXNzZXRJZCwgIiIpOwogICAgLy8gfQoKICAgIC8qKgogICAgICogQGRldiBTYWZlbHkgc2VuZHMgdGhlIG93bmVyc2hpcCBvZiBhIGdpdmVuIGFzc2V0IElEIHRvIGFub3RoZXIgYWRkcmVzcwogICAgICovCiAgICBmdW5jdGlvbiBzZW5kRnJvbShhZGRyZXNzIGZyb20sIGFkZHJlc3MgdG8sIHVpbnQyNTYgYXNzZXRJZCwgYnl0ZXMgbWVtb3J5IGRhdGEpIHB1YmxpYyB3aGVuTm90U3VzcGVuZGVkIHsKCgogICAgICAgIHJlcXVpcmUoX2lzQXBwcm92ZWRPck93bmVyKG1zZy5zZW5kZXIsIGFzc2V0SWQpLCAiQkFDMDAyOiBzZW5kIGNhbGxlciBpcyBub3Qgb3duZXIgbm9yIGFwcHJvdmVkIik7CiAgICAgICAgX3NlbmRGcm9tKGZyb20sIHRvLCBhc3NldElkLCBkYXRhKTsKICAgICAgICByZXF1aXJlKF9jaGVja09uQkFDMDAyUmVjZWl2ZWQoZnJvbSwgdG8sIGFzc2V0SWQsIGRhdGEpLCAiQkFDMDAyOiBzZW5kIHRvIG5vbiBCQUMwMDJSZWNlaXZlciBpbXBsZW1lbnRlciIpOwogICAgfQoKCiAgICBmdW5jdGlvbiBiYXRjaFNlbmRGcm9tKGFkZHJlc3MgZnJvbSwgYWRkcmVzc1tdIHRvLCB1aW50MjU2W10gYXNzZXRJZCwgYnl0ZXMgbWVtb3J5IGRhdGEpIHB1YmxpYyB3aGVuTm90U3VzcGVuZGVkIHsKCiAgICAgICAgcmVxdWlyZSh0by5sZW5ndGggPT0gYXNzZXRJZC5sZW5ndGgsICJ0byBhbmQgYXNzZXRJZCBhcnJheSBsZW5naHQgbXVzdCBtYXRjaC4iKTsKCiAgICAgICAgZm9yICh1aW50MjU2IGkgPSAwOyBpIDwgdG8ubGVuZ3RoOyArK2kpIHsKICAgICAgICAgICAgcmVxdWlyZSh0b1tpXSAhPSBhZGRyZXNzKDB4MCksICJkZXN0aW5hdGlvbiBhZGRyZXNzIG11c3QgYmUgbm9uLXplcm8uIik7CiAgICAgICAgICAgIHNlbmRGcm9tKGZyb20sIHRvW2ldLCBhc3NldElkW2ldLCBkYXRhKTsKCiAgICAgICAgfQogICAgfQoKCiAgICBmdW5jdGlvbiBkZXN0cm95KHVpbnQyNTYgYXNzZXRJZCwgYnl0ZXMgZGF0YSkgcHVibGljIHsKICAgICAgICAvL3NvbGhpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWxpbmUtbGVuZ3RoCiAgICAgICAgcmVxdWlyZShfaXNBcHByb3ZlZE9yT3duZXIobXNnLnNlbmRlciwgYXNzZXRJZCksICJCQUMwMDJCdXJuYWJsZTogY2FsbGVyIGlzIG5vdCBvd25lciBub3IgYXBwcm92ZWQiKTsKICAgICAgICBfZGVzdHJveShhc3NldElkLCBkYXRhKTsKICAgIH0KCiAgICAvL2FkZCBpc3N1ZXJBZGRyZXNzCiAgICBmdW5jdGlvbiBpc3N1ZVdpdGhBc3NldFVSSShhZGRyZXNzIHRvLCB1aW50MjU2IGFzc2V0SWQsIHN0cmluZyBtZW1vcnkgYXNzZXRVUkksIGJ5dGVzIGRhdGEpIHB1YmxpYyBvbmx5SXNzdWVyIHJldHVybnMgKGJvb2wpIHsKICAgICAgICBfaXNzdWUoIHRvLCBhc3NldElkLCBkYXRhKTsKICAgICAgICBfc2V0QXNzZXRVUkkoYXNzZXRJZCwgYXNzZXRVUkkpOwogICAgICAgIHJldHVybiB0cnVlOwogICAgfQoKICAgIGZ1bmN0aW9uIGRlc2NyaXB0aW9uKCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChzdHJpbmcgbWVtb3J5KSB7CiAgICAgICAgcmV0dXJuIF9kZXNjcmlwdGlvbjsKICAgIH0KCiAgICBmdW5jdGlvbiBzaG9ydE5hbWUoKSBleHRlcm5hbCB2aWV3IHJldHVybnMgKHN0cmluZyBtZW1vcnkpIHsKICAgICAgICByZXR1cm4gX3Nob3J0TmFtZTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgUmV0dXJucyBhbiBVUkkgZm9yIGEgZ2l2ZW4gYXNzZXQgSUQuCiAgICAgKi8KICAgIGZ1bmN0aW9uIGFzc2V0VVJJKHVpbnQyNTYgYXNzZXRJZCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChzdHJpbmcgbWVtb3J5KSB7CiAgICAgICAgcmVxdWlyZShfZXhpc3RzKGFzc2V0SWQpLCAiQkFDMDAyTWV0YWRhdGE6IFVSSSBxdWVyeSBmb3Igbm9uZXhpc3RlbnQgYXNzZXQiKTsKICAgICAgICByZXR1cm4gX2Fzc2V0VVJJc1thc3NldElkXTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgSW50ZXJuYWwgZnVuY3Rpb24gdG8gc2V0IHRoZSBhc3NldCBVUkkgZm9yIGEgZ2l2ZW4gYXNzZXQuCiAgICAgKi8KICAgIGZ1bmN0aW9uIF9zZXRBc3NldFVSSSh1aW50MjU2IGFzc2V0SWQsIHN0cmluZyBtZW1vcnkgdXJpKSBpbnRlcm5hbCB7CiAgICAgICAgcmVxdWlyZShfZXhpc3RzKGFzc2V0SWQpLCAiQkFDMDAyTWV0YWRhdGE6IFVSSSBzZXQgb2Ygbm9uZXhpc3RlbnQgYXNzZXQiKTsKICAgICAgICBfYXNzZXRVUklzW2Fzc2V0SWRdID0gdXJpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBSZXR1cm5zIHdoZXRoZXIgdGhlIHNwZWNpZmllZCBhc3NldCBleGlzdHMuCiAgICAgKi8KICAgIGZ1bmN0aW9uIF9leGlzdHModWludDI1NiBhc3NldElkKSBpbnRlcm5hbCB2aWV3IHJldHVybnMgKGJvb2wpIHsKICAgICAgICBhZGRyZXNzIG93bmVyID0gX2Fzc2V0T3duZXJbYXNzZXRJZF07CiAgICAgICAgcmV0dXJuIG93bmVyICE9IGFkZHJlc3MoMCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IFJldHVybnMgd2hldGhlciB0aGUgZ2l2ZW4gc3BlbmRlciBjYW4gc2VuZCBhIGdpdmVuIGFzc2V0IElELgogICAgICovCiAgICBmdW5jdGlvbiBfaXNBcHByb3ZlZE9yT3duZXIoYWRkcmVzcyBzcGVuZGVyLCB1aW50MjU2IGFzc2V0SWQpIGludGVybmFsIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJlcXVpcmUoX2V4aXN0cyhhc3NldElkKSwgIkJBQzAwMjogb3BlcmF0b3IgcXVlcnkgZm9yIG5vbmV4aXN0ZW50IGFzc2V0Iik7CiAgICAgICAgYWRkcmVzcyBvd25lciA9IG93bmVyT2YoYXNzZXRJZCk7CiAgICAgICAgcmV0dXJuIChzcGVuZGVyID09IG93bmVyIHx8IGdldEFwcHJvdmVkKGFzc2V0SWQpID09IHNwZW5kZXIgfHwgaXNBcHByb3ZlZEZvckFsbChvd25lciwgc3BlbmRlcikpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBJbnRlcm5hbCBmdW5jdGlvbiB0byBtaW50IGEgbmV3IGFzc2V0LgogICAgICovCiAgICBmdW5jdGlvbiBfaXNzdWUoIGFkZHJlc3MgdG8sIHVpbnQyNTYgYXNzZXRJZCwgYnl0ZXMgZGF0YSkgaW50ZXJuYWwgewogICAgICAgIHJlcXVpcmUodG8gIT0gYWRkcmVzcygwKSwgIkJBQzAwMjogbWludCB0byB0aGUgemVybyBhZGRyZXNzIik7CiAgICAgICAgcmVxdWlyZSghX2V4aXN0cyhhc3NldElkKSwgIkJBQzAwMjogYXNzZXQgYWxyZWFkeSBtaW50ZWQiKTsKCiAgICAgICAgX2Fzc2V0T3duZXJbYXNzZXRJZF0gPSB0bzsKICAgICAgICBfb3duZWRBc3NldHNDb3VudFt0b10uaW5jcmVtZW50KCk7CgogICAgICAgIGVtaXQgU2VuZChtc2cuc2VuZGVyLCBhZGRyZXNzKDApLCB0bywgYXNzZXRJZCwgZGF0YSk7CgogICAgICAgIF9hZGRBc3NldFRvT3duZXJFbnVtZXJhdGlvbih0bywgYXNzZXRJZCk7CgogICAgICAgIF9hZGRBc3NldFRvQWxsQXNzZXRzRW51bWVyYXRpb24oYXNzZXRJZCk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IEludGVybmFsIGZ1bmN0aW9uIHRvIGRlc3Ryb3kgYSBzcGVjaWZpYyBhc3NldC4KICAgICAqIFJldmVydHMgaWYgdGhlIGFzc2V0IGRvZXMgbm90IGV4aXN0LgogICAgICovCiAgICBmdW5jdGlvbiBfZGVzdHJveShhZGRyZXNzIG93bmVyLCB1aW50MjU2IGFzc2V0SWQsIGJ5dGVzIGRhdGEpIGludGVybmFsIHsKICAgICAgICByZXF1aXJlKG93bmVyT2YoYXNzZXRJZCkgPT0gb3duZXIsICJCQUMwMDI6IGRlc3Ryb3kgb2YgYXNzZXQgdGhhdCBpcyBub3Qgb3duIik7CgogICAgICAgIF9jbGVhckFwcHJvdmFsKGFzc2V0SWQpOwoKICAgICAgICBfb3duZWRBc3NldHNDb3VudFtvd25lcl0uZGVjcmVtZW50KCk7CiAgICAgICAgX2Fzc2V0T3duZXJbYXNzZXRJZF0gPSBhZGRyZXNzKDApOwoKICAgICAgICBpZiAoYnl0ZXMoX2Fzc2V0VVJJc1thc3NldElkXSkubGVuZ3RoICE9IDApIHsKICAgICAgICAgICAgZGVsZXRlIF9hc3NldFVSSXNbYXNzZXRJZF07CiAgICAgICAgfQoKICAgICAgICBlbWl0IFNlbmQodGhpcywgb3duZXIsIGFkZHJlc3MoMCksIGFzc2V0SWQsIGRhdGEpOwoKICAgICAgICBfcmVtb3ZlQXNzZXRGcm9tT3duZXJFbnVtZXJhdGlvbihvd25lciwgYXNzZXRJZCk7CiAgICAgICAgLy8gU2luY2UgYXNzZXRJZCB3aWxsIGJlIGRlbGV0ZWQsIHdlIGNhbiBjbGVhciBpdHMgc2xvdCBpbiBfb3duZWRBc3NldHNJbmRleCB0byB0cmlnZ2VyIGEgZ2FzIHJlZnVuZAogICAgICAgIF9vd25lZEFzc2V0c0luZGV4W2Fzc2V0SWRdID0gMDsKCiAgICAgICAgX3JlbW92ZUFzc2V0RnJvbUFsbEFzc2V0c0VudW1lcmF0aW9uKGFzc2V0SWQpOwogICAgfQoKCiAgICAvKioKICAgICAqIEBkZXYgR2V0cyB0aGUgdG90YWwgYW1vdW50IG9mIGFzc2V0cyBzdG9yZWQgYnkgdGhlIGNvbnRyYWN0LgogICAgICogQHJldHVybiB1aW50MjU2IHJlcHJlc2VudGluZyB0aGUgdG90YWwgYW1vdW50IG9mIGFzc2V0cwogICAgICovCiAgICBmdW5jdGlvbiB0b3RhbFN1cHBseSgpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQyNTYpIHsKICAgICAgICByZXR1cm4gX2FsbEFzc2V0cy5sZW5ndGg7CiAgICB9CgoKICAgIGZ1bmN0aW9uIF9hc3NldHNPZk93bmVyKGFkZHJlc3Mgb3duZXIpIGludGVybmFsIHZpZXcgcmV0dXJucyAodWludDI1NltdIHN0b3JhZ2UpIHsKICAgICAgICByZXR1cm4gX293bmVkQXNzZXRzW293bmVyXTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgUHJpdmF0ZSBmdW5jdGlvbiB0byBhZGQgYSBhc3NldCB0byB0aGlzIGV4dGVuc2lvbidzIG93bmVyc2hpcC10cmFja2luZyBkYXRhIHN0cnVjdHVyZXMuCiAgICAgKi8KICAgIGZ1bmN0aW9uIF9hZGRBc3NldFRvT3duZXJFbnVtZXJhdGlvbihhZGRyZXNzIHRvLCB1aW50MjU2IGFzc2V0SWQpIHByaXZhdGUgewogICAgICAgIF9vd25lZEFzc2V0c0luZGV4W2Fzc2V0SWRdID0gX293bmVkQXNzZXRzW3RvXS5sZW5ndGg7CiAgICAgICAgX293bmVkQXNzZXRzW3RvXS5wdXNoKGFzc2V0SWQpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBQcml2YXRlIGZ1bmN0aW9uIHRvIGFkZCBhIGFzc2V0IHRvIHRoaXMgZXh0ZW5zaW9uJ3MgYXNzZXQgdHJhY2tpbmcgZGF0YSBzdHJ1Y3R1cmVzLgogICAgICovCiAgICBmdW5jdGlvbiBfYWRkQXNzZXRUb0FsbEFzc2V0c0VudW1lcmF0aW9uKHVpbnQyNTYgYXNzZXRJZCkgcHJpdmF0ZSB7CiAgICAgICAgX2FsbEFzc2V0c0luZGV4W2Fzc2V0SWRdID0gX2FsbEFzc2V0cy5sZW5ndGg7CiAgICAgICAgX2FsbEFzc2V0cy5wdXNoKGFzc2V0SWQpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBQcml2YXRlIGZ1bmN0aW9uIHRvIHJlbW92ZSBhIGFzc2V0IGZyb20gdGhpcyBleHRlbnNpb24ncyBvd25lcnNoaXAtdHJhY2tpbmcgZGF0YSBzdHJ1Y3R1cmVzLiBOb3RlIHRoYXQKICAgICAqLwogICAgZnVuY3Rpb24gX3JlbW92ZUFzc2V0RnJvbU93bmVyRW51bWVyYXRpb24oYWRkcmVzcyBmcm9tLCB1aW50MjU2IGFzc2V0SWQpIHByaXZhdGUgewogICAgICAgIC8vIFRvIHByZXZlbnQgYSBnYXAgaW4gZnJvbSdzIGFzc2V0cyBhcnJheSwgd2Ugc3RvcmUgdGhlIGxhc3QgYXNzZXQgaW4gdGhlIGluZGV4IG9mIHRoZSBhc3NldCB0byBkZWxldGUsIGFuZAogICAgICAgIC8vIHRoZW4gZGVsZXRlIHRoZSBsYXN0IHNsb3QgKHN3YXAgYW5kIHBvcCkuCgogICAgICAgIHVpbnQyNTYgbGFzdEFzc2V0SW5kZXggPSBfb3duZWRBc3NldHNbZnJvbV0ubGVuZ3RoLnN1YigxKTsKICAgICAgICB1aW50MjU2IGFzc2V0SW5kZXggPSBfb3duZWRBc3NldHNJbmRleFthc3NldElkXTsKCiAgICAgICAgLy8gV2hlbiB0aGUgYXNzZXQgdG8gZGVsZXRlIGlzIHRoZSBsYXN0IGFzc2V0LCB0aGUgc3dhcCBvcGVyYXRpb24gaXMgdW5uZWNlc3NhcnkKICAgICAgICBpZiAoYXNzZXRJbmRleCAhPSBsYXN0QXNzZXRJbmRleCkgewogICAgICAgICAgICB1aW50MjU2IGxhc3RBc3NldElkID0gX293bmVkQXNzZXRzW2Zyb21dW2xhc3RBc3NldEluZGV4XTsKCiAgICAgICAgICAgIF9vd25lZEFzc2V0c1tmcm9tXVthc3NldEluZGV4XSA9IGxhc3RBc3NldElkOwogICAgICAgICAgICAvLyBNb3ZlIHRoZSBsYXN0IGFzc2V0IHRvIHRoZSBzbG90IG9mIHRoZSB0by1kZWxldGUgYXNzZXQKICAgICAgICAgICAgX293bmVkQXNzZXRzSW5kZXhbbGFzdEFzc2V0SWRdID0gYXNzZXRJbmRleDsKICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSBtb3ZlZCBhc3NldCdzIGluZGV4CiAgICAgICAgfQoKICAgICAgICAvLyBUaGlzIGFsc28gZGVsZXRlcyB0aGUgY29udGVudHMgYXQgdGhlIGxhc3QgcG9zaXRpb24gb2YgdGhlIGFycmF5CiAgICAgICAgX293bmVkQXNzZXRzW2Zyb21dLmxlbmd0aC0tOwoKICAgICAgICAvLyBOb3RlIHRoYXQgX293bmVkQXNzZXRzSW5kZXhbYXNzZXRJZF0gaGFzbid0IGJlZW4gY2xlYXJlZDogaXQgc3RpbGwgcG9pbnRzIHRvIHRoZSBvbGQgc2xvdCAobm93IG9jY3VwaWVkIGJ5CiAgICAgICAgLy8gbGFzdEFzc2V0SWQsIG9yIGp1c3Qgb3ZlciB0aGUgZW5kIG9mIHRoZSBhcnJheSBpZiB0aGUgYXNzZXQgd2FzIHRoZSBsYXN0IG9uZSkuCiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IFByaXZhdGUgZnVuY3Rpb24gdG8gcmVtb3ZlIGEgYXNzZXQgZnJvbSB0aGlzIGV4dGVuc2lvbidzIGFzc2V0IHRyYWNraW5nIGRhdGEgc3RydWN0dXJlcy4KICAgICAqLwogICAgZnVuY3Rpb24gX3JlbW92ZUFzc2V0RnJvbUFsbEFzc2V0c0VudW1lcmF0aW9uKHVpbnQyNTYgYXNzZXRJZCkgcHJpdmF0ZSB7CiAgICAgICAgLy8gVG8gcHJldmVudCBhIGdhcCBpbiB0aGUgYXNzZXRzIGFycmF5LCB3ZSBzdG9yZSB0aGUgbGFzdCBhc3NldCBpbiB0aGUgaW5kZXggb2YgdGhlIGFzc2V0IHRvIGRlbGV0ZSwgYW5kCiAgICAgICAgLy8gdGhlbiBkZWxldGUgdGhlIGxhc3Qgc2xvdCAoc3dhcCBhbmQgcG9wKS4KCiAgICAgICAgdWludDI1NiBsYXN0QXNzZXRJbmRleCA9IF9hbGxBc3NldHMubGVuZ3RoLnN1YigxKTsKICAgICAgICB1aW50MjU2IGFzc2V0SW5kZXggPSBfYWxsQXNzZXRzSW5kZXhbYXNzZXRJZF07CgogICAgICAgIC8vIFdoZW4gdGhlIGFzc2V0IHRvIGRlbGV0ZSBpcyB0aGUgbGFzdCBhc3NldCwgdGhlIHN3YXAgb3BlcmF0aW9uIGlzIHVubmVjZXNzYXJ5LiBIb3dldmVyLCBzaW5jZSB0aGlzIG9jY3VycyBzbwogICAgICAgIC8vIHJhcmVseSAod2hlbiB0aGUgbGFzdCBtaW50ZWQgYXNzZXQgaXMgZGVzdHJveXQpIHRoYXQgd2Ugc3RpbGwgZG8gdGhlIHN3YXAgaGVyZSB0byBhdm9pZCB0aGUgZ2FzIGNvc3Qgb2YgYWRkaW5nCiAgICAgICAgLy8gYW4gJ2lmJyBzdGF0ZW1lbnQgKGxpa2UgaW4gX3JlbW92ZUFzc2V0RnJvbU93bmVyRW51bWVyYXRpb24pCiAgICAgICAgdWludDI1NiBsYXN0QXNzZXRJZCA9IF9hbGxBc3NldHNbbGFzdEFzc2V0SW5kZXhdOwoKICAgICAgICBfYWxsQXNzZXRzW2Fzc2V0SW5kZXhdID0gbGFzdEFzc2V0SWQ7CiAgICAgICAgLy8gTW92ZSB0aGUgbGFzdCBhc3NldCB0byB0aGUgc2xvdCBvZiB0aGUgdG8tZGVsZXRlIGFzc2V0CiAgICAgICAgX2FsbEFzc2V0c0luZGV4W2xhc3RBc3NldElkXSA9IGFzc2V0SW5kZXg7CiAgICAgICAgLy8gVXBkYXRlIHRoZSBtb3ZlZCBhc3NldCdzIGluZGV4CgogICAgICAgIC8vIFRoaXMgYWxzbyBkZWxldGVzIHRoZSBjb250ZW50cyBhdCB0aGUgbGFzdCBwb3NpdGlvbiBvZiB0aGUgYXJyYXkKICAgICAgICBfYWxsQXNzZXRzLmxlbmd0aC0tOwogICAgICAgIF9hbGxBc3NldHNJbmRleFthc3NldElkXSA9IDA7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IEludGVybmFsIGZ1bmN0aW9uIHRvIGRlc3Ryb3kgYSBzcGVjaWZpYyBhc3NldC4KICAgICAqLwogICAgZnVuY3Rpb24gX2Rlc3Ryb3kodWludDI1NiBhc3NldElkLCBieXRlcyBkYXRhKSBpbnRlcm5hbCB7CiAgICAgICAgX2Rlc3Ryb3kob3duZXJPZihhc3NldElkKSwgYXNzZXRJZCwgZGF0YSk7CiAgICB9CgogICAgLyoqCiAgICAgKiBAZGV2IEludGVybmFsIGZ1bmN0aW9uIHRvIHNlbmQgb3duZXJzaGlwIG9mIGEgZ2l2ZW4gYXNzZXQgSUQgdG8gYW5vdGhlciBhZGRyZXNzLgogICAgICovCiAgICBmdW5jdGlvbiBfc2VuZEZyb20oYWRkcmVzcyBmcm9tLCBhZGRyZXNzIHRvLCB1aW50MjU2IGFzc2V0SWQsIGJ5dGVzIGRhdGEpIGludGVybmFsIHsKICAgICAgICByZXF1aXJlKG93bmVyT2YoYXNzZXRJZCkgPT0gZnJvbSwgIkJBQzAwMjogc2VuZCBvZiBhc3NldCB0aGF0IGlzIG5vdCBvd24iKTsKICAgICAgICByZXF1aXJlKHRvICE9IGFkZHJlc3MoMCksICJCQUMwMDI6IHNlbmQgdG8gdGhlIHplcm8gYWRkcmVzcyIpOwoKICAgICAgICBfY2xlYXJBcHByb3ZhbChhc3NldElkKTsKICAgICAgICBfb3duZWRBc3NldHNDb3VudFtmcm9tXS5kZWNyZW1lbnQoKTsKICAgICAgICBfb3duZWRBc3NldHNDb3VudFt0b10uaW5jcmVtZW50KCk7CgogICAgICAgIF9hc3NldE93bmVyW2Fzc2V0SWRdID0gdG87CgogICAgICAgIGVtaXQgU2VuZChtc2cuc2VuZGVyLCBmcm9tLCB0bywgYXNzZXRJZCwgZGF0YSk7CgogICAgICAgIF9yZW1vdmVBc3NldEZyb21Pd25lckVudW1lcmF0aW9uKGZyb20sIGFzc2V0SWQpOwoKICAgICAgICBfYWRkQXNzZXRUb093bmVyRW51bWVyYXRpb24odG8sIGFzc2V0SWQpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBJbnRlcm5hbCBmdW5jdGlvbiB0byBpbnZva2UgYG9uQkFDMDAyUmVjZWl2ZWRgIG9uIGEgdGFyZ2V0IGFkZHJlc3MuCiAgICAgKi8KICAgIGZ1bmN0aW9uIF9jaGVja09uQkFDMDAyUmVjZWl2ZWQoYWRkcmVzcyBmcm9tLCBhZGRyZXNzIHRvLCB1aW50MjU2IGFzc2V0SWQsIGJ5dGVzIG1lbW9yeSBfZGF0YSkKICAgIGludGVybmFsIHJldHVybnMgKGJvb2wpCiAgICB7CiAgICAgICAgaWYgKCF0by5pc0NvbnRyYWN0KCkpIHsKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfQoKICAgICAgICBieXRlczQgcmV0dmFsID0gSUJBQzAwMlJlY2VpdmVyKHRvKS5vbkJBQzAwMlJlY2VpdmVkKG1zZy5zZW5kZXIsIGZyb20sIGFzc2V0SWQsIF9kYXRhKTsKICAgICAgICByZXR1cm4gKHJldHZhbCA9PSBfQkFDMDAyX1JFQ0VJVkVEKTsKICAgIH0KCiAgICAvKioKICAgICAqIEBkZXYgUHJpdmF0ZSBmdW5jdGlvbiB0byBjbGVhciBjdXJyZW50IGFwcHJvdmFsIG9mIGEgZ2l2ZW4gYXNzZXQgSUQuCiAgICAgKi8KICAgIGZ1bmN0aW9uIF9jbGVhckFwcHJvdmFsKHVpbnQyNTYgYXNzZXRJZCkgcHJpdmF0ZSB7CiAgICAgICAgaWYgKF9hc3NldEFwcHJvdmFsc1thc3NldElkXSAhPSBhZGRyZXNzKDApKSB7CiAgICAgICAgICAgIF9hc3NldEFwcHJvdmFsc1thc3NldElkXSA9IGFkZHJlc3MoMCk7CiAgICAgICAgfQogICAgfQp9"; + public static final String I_BAC002_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjU7Cgpjb250cmFjdCBJQkFDMDAyICB7CiAgICBldmVudCBTZW5kKGFkZHJlc3MgaW5kZXhlZCBmcm9tLCBhZGRyZXNzIGluZGV4ZWQgdG8sIHVpbnQyNTYgYXNzZXRJZCwgYnl0ZXMgZGF0YSk7CiAgICBldmVudCBBcHByb3ZhbCggYWRkcmVzcyBpbmRleGVkIG93bmVyLCBhZGRyZXNzIGFwcHJvdmVkLCB1aW50MjU2IGFzc2V0SWQpOwogICAgZXZlbnQgQXBwcm92YWxGb3JBbGwoIGFkZHJlc3MgaW5kZXhlZCBvd25lciwgYWRkcmVzcyBpbmRleGVkIG9wZXJhdG9yLCBib29sIGFwcHJvdmVkKTsKCiAgICBmdW5jdGlvbiBiYWxhbmNlKGFkZHJlc3Mgb3duZXIpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQyNTYgYmFsYW5jZSk7CgogICAgZnVuY3Rpb24gb3duZXJPZih1aW50MjU2IGFzc2V0SWQpIHB1YmxpYyB2aWV3IHJldHVybnMgKGFkZHJlc3Mgb3duZXIpOwoKICAgIGZ1bmN0aW9uIHNlbmRGcm9tKGFkZHJlc3MgZnJvbSwgYWRkcmVzcyB0bywgdWludDI1NiBhc3NldElkLCBieXRlcyBtZW1vcnkgZGF0YSkgcHVibGljOwoKICAgIGZ1bmN0aW9uIGJhdGNoU2VuZEZyb20oYWRkcmVzcyBmcm9tLCBhZGRyZXNzW10gdG8sIHVpbnQyNTZbXSBhc3NldElkLCBieXRlcyBtZW1vcnkgZGF0YSkgcHVibGljOwoKICAgIGZ1bmN0aW9uIGRlc3Ryb3kodWludDI1NiBhc3NldElkLCBieXRlcyBkYXRhKSBwdWJsaWM7CgogICAgZnVuY3Rpb24gaXNzdWVXaXRoQXNzZXRVUkkoYWRkcmVzcyB0bywgdWludDI1NiBhc3NldElkLCBzdHJpbmcgbWVtb3J5IGFzc2V0VVJJLCBieXRlcyBkYXRhKSBwdWJsaWMgIHJldHVybnMgKGJvb2wpOwoKICAgIGZ1bmN0aW9uIGFzc2V0VVJJKHVpbnQyNTYgYXNzZXRJZCkgZXh0ZXJuYWwgdmlldyByZXR1cm5zIChzdHJpbmcgbWVtb3J5KTsKCiAgICBmdW5jdGlvbiBhcHByb3ZlKGFkZHJlc3MgdG8sIHVpbnQyNTYgYXNzZXRJZCkgcHVibGljOwogICAgZnVuY3Rpb24gZ2V0QXBwcm92ZWQodWludDI1NiBhc3NldElkKSBwdWJsaWMgdmlldyByZXR1cm5zIChhZGRyZXNzIG9wZXJhdG9yKTsKCiAgICBmdW5jdGlvbiBzZXRBcHByb3ZhbEZvckFsbChhZGRyZXNzIHRvLCBib29sIF9hcHByb3ZlZCkgcHVibGljOwogICAgZnVuY3Rpb24gaXNBcHByb3ZlZEZvckFsbChhZGRyZXNzIG93bmVyLCBhZGRyZXNzIG9wZXJhdG9yKSBwdWJsaWMgdmlldyByZXR1cm5zIChib29sKTsKCiAgICBmdW5jdGlvbiBhc3NldE9mT3duZXJCeUluZGV4KGFkZHJlc3Mgb3duZXIsIHVpbnQyNTYgaW5kZXgpIHB1YmxpYyB2aWV3IHJldHVybnMgKHVpbnQyNTYpIDsKCiAgICBmdW5jdGlvbiBzYWZlVHJhbnNmZXJGcm9tKGFkZHJlc3MgZnJvbSwgYWRkcmVzcyB0bywgdWludDI1NiB0b2tlbklkLCBieXRlcyBtZW1vcnkgZGF0YSkgcHVibGljOwp9Cg=="; public static final String BAC001_MD = "# 积分合约\n" + "\n" + "## 简介\n" + @@ -58,7 +60,7 @@ public class PointsConstantContext { "\n" + "- 销毁\n" + "\n" + - " 调用 destory 以及 destoryFrom 销毁自己地址下积分和特定地址下的积分\n" + + " 调用 destroy 以及 destroyFrom 销毁自己地址下积分和特定地址下的积分\n" + "\n" + "- 暂停\n" + "\n" + @@ -142,7 +144,7 @@ public class PointsConstantContext { "\n" + " 积分描述\n" + "\n" + - "- destory(uint256 value, string data)\n" + + "- destroy(uint256 value, string data)\n" + "\n" + " 减少自己的积分,data 是转账备注\n" + "\n" + @@ -203,4 +205,156 @@ public class PointsConstantContext { " - 配合 suspend / addSuspender 方法使用\n" + "\n" + "\n"; + public static final String BAC002_MD = "# BAC002 合约规范\n" + + "\n" + + "## 简介\n" + + " BAC002 是区块链上定义非同质化资产的一种标准,可以用于唯一性资产类型,如房产、汽车、道具、版权等。,并可以做相应增发,销毁,暂停合约,黑白名单等权限控制。\n" + + "## 三个基本元素\n" + + "- description\n" + + "\n" + + " 资产的具体描述\n" + + "\n" + + "- shortName\n" + + "\n" + + " 资产简称\n" + + "\n" + + "- assetId\n" + + "\n" + + " 资产编号\n" + + "\n" + + " ## 五个基本行为\n" + + "- 发行\n" + + "\n" + + " 调用合约的 deploy 方法,传入 description 和 shortName,即在区块链上发行指定名称的资产\n" + + "\n" + + "- 转账\n" + + "\n" + + " 调用 safeSendFrom 方法实现转账,调用 balance 方法可以查看自己的资产数量\n" + + "\n" + + "- 增发\n" + + "\n" + + " 调用 issueWithAssetURI 方法向资产地址增发指定资产编号和资产描述链接信息的资产。另外,可以通过 addIssuer 增加 有权限增发资产的人,也可以通过 renounceIssuer 方法移除增发权限\n" + + "\n" + + "- 销毁\n" + + "\n" + + " 调用 destroy 以及 destroyFrom 销毁自己地址下资产和特定地址下的资产\n" + + "\n" + + "- 暂停\n" + + "\n" + + " 遇到紧急状况,你可以调用 suspend 方法,暂停合约,这样任何人都不能调用 send 函数。故障修复后,可以调用 unSuspend 方法解除暂停。也可以通过 addSuspender 和 renounceSuspender 相应增加和移除暂停者权限\n" + + "\n" + + "\n" + + "## 接口说明\n" + + "\n" + + "- shortName()\n" + + "\n" + + " 资产简称\n" + + "\n" + + "- description()\n" + + "\n" + + " 资产描述\n" + + "\n" + + "- balance(address owner)\n" + + "\n" + + " 返回 owner 的资产总数\n" + + "\n" + + "- totalSupply()\n" + + "\n" + + " 获得当前合约总的资产数目\n" + + "\n" + + "- ownerOf(uint256 assetId)\n" + + "\n" + + " 返回资产持有者的地址\n" + + "\n" + + "- approve(address to, uint256 assetId)\n" + + "\n" + + " 授予地址to具有指定资产的控制权\n" + + "\n" + + " - 此方法配合 getapproved 使用\n" + + "\n" + + "- getApproved(uint256 assetId)\n" + + "\n" + + " 获得资产授权的地址用户\n" + + "\n" + + " - 此方法配合 approve 使用,注意不要配合 setapprovealforall 方法使用\n" + + "\n" + + "- setApprovalForAll(address operator, bool approved)\n" + + "\n" + + " 授予地址operator具有自己所有资产的控制权\n" + + "\n" + + "- isApprovedForAll(address owner, address operator)\n" + + "\n" + + " 查询授权\n" + + "\n" + + "- sendFrom(address from, address to, uint256 assetId, bytes memory data)\n" + + "\n" + + " 安全转账,防止你转到错误的合约地址 ( to如果是合约地址,必须实现接收接口 BAC002Holder 才可以接收转账 ),并可以带转账备注\n" + + "\n" + + " - suspend 状态下无法执行此操作\n" + + "\n" + + "- batchSendFrom(address from, address[] to, uint256[] assetId, bytes memory data)\n" + + "\n" + + " 批量安全转账\n" + + "\n" + + " - suspend 状态下无法执行此操作\n" + + " - to 数组元素个数需要和 assetid 数组元素个数一致\n" + + "\n" + + "- issueWithAssetURI(address to, uint256 assetId, string memory assetURI, bytes data)\n" + + "\n" + + " 给地址 to 创建资产 assetId,data 是转账备注, assetURI 资产描述\n" + + "\n" + + "- isIssuer(address account)\n" + + "\n" + + " 检查account是否有增加资产的权限\n" + + "\n" + + "- addIssuer(address account)\n" + + "\n" + + " 使地址 account 拥有增加资产的权限\n" + + "\n" + + "- renounceIssuer()\n" + + "\n" + + " 移除增加资产的权限\n" + + "\n" + + "- suspend()\n" + + "\n" + + " 暂停合约\n" + + "\n" + + " - suspend 后无法进行 safesendfrom / sendfrom / safeBatchSendFrom 操作\n" + + "\n" + + "- unSuspend()\n" + + "\n" + + " 重启合约\n" + + "\n" + + " - 此方法配合 suspend 使用\n" + + "\n" + + "- isSuspender(address account)\n" + + "\n" + + " 是否有暂停合约权限\n" + + "\n" + + " - 此方法配合 addsuspender 使用\n" + + "\n" + + "- addSuspender(address account)\n" + + "\n" + + " 增加暂停权限者\n" + + "\n" + + " - 此方法配合 renouncesuspender / issuspender 放啊发使用\n" + + "\n" + + "- renounceSuspender()\n" + + "\n" + + " 移除暂停权限\n" + + "\n" + + "- destroy(uint256 assetId, bytes data)\n" + + "\n" + + " 减少自己的资产,data 是转账备注\n" + + "\n" + + " - 调用时,value 值需要小于等于目前自己的资产总量\n" + + "\n" + + "- assetOfOwnerByIndex(address owner, uint256 index)\n" + + "\n" + + " 根据索引 index 获取 owner 的资产 ID\n" + + "\n" + + "- assetByIndex(uint256 index)\n" + + "\n" + + " 根据索引 index 获取当前合约的资产 ID\n" + + "\n"; } diff --git a/src/main/java/com/webank/webase/front/contractStore/PresetDataService.java b/src/main/java/com/webank/webase/front/contractStore/PresetDataService.java index 230ffe9a4..83b790270 100644 --- a/src/main/java/com/webank/webase/front/contractStore/PresetDataService.java +++ b/src/main/java/com/webank/webase/front/contractStore/PresetDataService.java @@ -28,6 +28,7 @@ public class PresetDataService { public static final Integer smartDevToolFolderId = 4; public static final Integer smartDevEvidenceFolderId = 5; + public static final Integer assetFolderId = 6; public void initStoreItem() { @@ -47,6 +48,11 @@ public void initStoreItem() { "Smart-Dev-Contract\'s Evidence Contract suite of business_template", "Smart-Dev-Contracts仓库中的存证应用模板", "Smart-Dev-Contract\'s Evidence Contract suite of business_template"); + insertStoreItem(assetFolderId, "资产应用", "Asset", "4", "pointsId", + "一套非同质化资产合约,具有于唯一性资产类型,如房产、汽车、道具、版权等", + "Asset Contract suite", + "套非同质化资产合约,具有于唯一性资产类型,如房产、汽车、道具、版权等", + "Asset Contract suite"); } public void insertStoreItem(long storeId, String storeName, String StoreName_en, String StoreType, @@ -75,35 +81,41 @@ public void insertStoreItem(long storeId, String storeName, String StoreName_en, public void initContractFolderItem() { int contractFolderIndex = 1; - insertContractFolderItem(contractFolderIndex++,toolboxId,"Tools", + insertContractFolderItem(toolboxId,toolboxId,"Tools", "工具箱中有常用的工具合约", "工具箱中有常用的工具合约", "Toolbox Contract suite", "Toolbox Contract suite"); - insertContractFolderItem(contractFolderIndex++,evidenceId,"Evidence", + insertContractFolderItem(evidenceId,evidenceId,"Evidence", "一套区块链存证合约,实现区块链存证、取证", "一套区块链存证合约,实现区块链存证、取证", "Evidence Contract suite", "Evidence Contract suite"); - insertContractFolderItem(contractFolderIndex++,pointsId,"Points", + insertContractFolderItem(pointsId,pointsId,"Points", "一套积分合约,具有积分相关的增发,销毁,暂停合约,黑白名单等权限控制等功能", "一套积分合约,具有积分相关的增发,销毁,暂停合约,黑白名单等权限控制等功能", "Points Contract suite", "Points Contract suite"); - - insertContractFolderItem(contractFolderIndex++,toolboxId,"Smart_Dev_Basic", + // belong to points store, and new folder + insertContractFolderItem(smartDevToolFolderId,toolboxId,"Smart_Dev_Basic", "SmartDev基础合约,包含Table/KVTable/Sha/Crypto/HelloWorld等", "SmartDev基础合约,包含Table/KVTable/Sha/Crypto/HelloWorld等", "Smart-Dev-Contract basic contract suite, including Table/KVTable/Sha/Crypto/HelloWorld etc.", "Smart-Dev-Contract basic contract suite, including Table/KVTable/Sha/Crypto/HelloWorld etc."); - insertContractFolderItem(contractFolderIndex++,smartDevId,"Smart_Dev_Evidence", + insertContractFolderItem(smartDevEvidenceFolderId,smartDevId,"Smart_Dev_Evidence", "SmartDev存证合约案例", "SmartDev存证合约案例", "Smart-Dev-Contract Evidence contract suite", "Smart-Dev-Contract Evidence contract suite"); + // belong to points store, and new folder + insertContractFolderItem(assetFolderId,assetFolderId,"Asset", + "一套非同质化资产合约,具有于唯一性资产类型,如房产、汽车、道具、版权等,具有增发、销毁,暂停合约,黑白名单等权限控制等功能", + "一套非同质化资产合约,具有于唯一性资产类型,如房产、汽车、道具、版权等,具有增发、销毁,暂停合约,黑白名单等权限控制等功能", + "Asset Contract suite", + "Asset Contract suite"); } public void insertContractFolderItem(long contractFolderId, long storeId, String contractFolderName, String contractFolderDesc, String contractFolderDetail, @@ -141,7 +153,6 @@ public void initContractItem() { insertContractItem(contractIndex++,toolboxId,"Roles",ToolsConstantContext.ROLES_SOURCE, ToolsConstantContext.ROLES_MD,ToolsConstantContext.ROLES_MD); - //evidence insertContractItem(contractIndex++,evidenceId,"Evidence", EvidenceConstantContext.EVIDENCE_SOURCE, @@ -188,6 +199,28 @@ public void initContractItem() { SmartDevConstantContext.EVIDENCE_API_MD,SmartDevConstantContext.EVIDENCE_API_MD); insertContractItem(contractIndex++,smartDevEvidenceFolderId,"Authentication",SmartDevConstantContext.AUTH_SOURCE, SmartDevConstantContext.EVIDENCE_API_MD,SmartDevConstantContext.EVIDENCE_API_MD); + + // asset + insertContractItem(contractIndex++,assetFolderId,"BAC002", + PointsConstantContext.BAC002_SOURCE, PointsConstantContext.BAC002_MD,""); + insertContractItem(contractIndex++,assetFolderId,"IBAC002", + PointsConstantContext.I_BAC002_SOURCE, PointsConstantContext.BAC002_MD,""); + // asset tool + insertContractItem(contractIndex++,assetFolderId,"Counters",ToolsConstantContext.COUNTERS_SOURCE, + ToolsConstantContext.ROLES_MD,ToolsConstantContext.COUNTERS_MD); + insertContractItem(contractIndex++,assetFolderId,"Register",ToolsConstantContext.REGISTER_SOURCE, + ToolsConstantContext.ROLES_MD,ToolsConstantContext.REGISTER_MD); + insertContractItem(contractIndex++,assetFolderId,"Roles",ToolsConstantContext.ROLES_SOURCE, + ToolsConstantContext.ROLES_MD,ToolsConstantContext.ROLES_MD); + insertContractItem(contractIndex++,assetFolderId,"SafeMath",ToolsConstantContext.SAFE_MATH_SOURCE, + ToolsConstantContext.SAFE_MATH_MD,ToolsConstantContext.ROLES_MD); + + // v1.5.2 tools + insertContractItem(contractIndex++,toolboxId,"Counters",ToolsConstantContext.COUNTERS_SOURCE, + ToolsConstantContext.ROLES_MD,ToolsConstantContext.COUNTERS_MD); + insertContractItem(contractIndex++,toolboxId,"Register",ToolsConstantContext.REGISTER_SOURCE, + ToolsConstantContext.ROLES_MD,ToolsConstantContext.REGISTER_MD); + } diff --git a/src/main/java/com/webank/webase/front/contractStore/ToolsConstantContext.java b/src/main/java/com/webank/webase/front/contractStore/ToolsConstantContext.java index 64be6e801..3cda4df73 100644 --- a/src/main/java/com/webank/webase/front/contractStore/ToolsConstantContext.java +++ b/src/main/java/com/webank/webase/front/contractStore/ToolsConstantContext.java @@ -20,6 +20,10 @@ public class ToolsConstantContext { public static final String SAFE_MATH_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjQ7CgoKbGlicmFyeSBTYWZlTWF0aCB7CiAgICBmdW5jdGlvbiBtdWwodWludDI1NiBhLCB1aW50MjU2IGIpIGludGVybmFsIHB1cmUgcmV0dXJucyAodWludDI1NikgewogICAgICAgIC8vIEdhcyBvcHRpbWl6YXRpb246IHRoaXMgaXMgY2hlYXBlciB0aGFuIHJlcXVpcmluZyAnYScgbm90IGJlaW5nIHplcm8sIGJ1dCB0aGUKICAgICAgICAvLyBiZW5lZml0IGlzIGxvc3QgaWYgJ2InIGlzIGFsc28gdGVzdGVkLgogICAgICAgIC8vIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL09wZW5aZXBwZWxpbi9vcGVuemVwcGVsaW4tc29saWRpdHkvcHVsbC81MjIKICAgICAgICBpZiAoYSA9PSAwKSB7CiAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgIH0KCiAgICAgICAgdWludDI1NiBjID0gYSAqIGI7CiAgICAgICAgcmVxdWlyZShjIC8gYSA9PSBiLCAiU2FmZU1hdGg6IG11bHRpcGxpY2F0aW9uIG92ZXJmbG93Iik7CgogICAgICAgIHJldHVybiBjOwogICAgfQogICAgZnVuY3Rpb24gZGl2KHVpbnQyNTYgYSwgdWludDI1NiBiKSBpbnRlcm5hbCBwdXJlIHJldHVybnMgKHVpbnQyNTYpIHsKICAgICAgICAvLyBTb2xpZGl0eSBvbmx5IGF1dG9tYXRpY2FsbHkgYXNzZXJ0cyB3aGVuIGRpdmlkaW5nIGJ5IDAKICAgICAgICByZXF1aXJlKGIgPiAwLCAiU2FmZU1hdGg6IGRpdmlzaW9uIGJ5IHplcm8iKTsKICAgICAgICB1aW50MjU2IGMgPSBhIC8gYjsKICAgICAgICAvLyBhc3NlcnQoYSA9PSBiICogYyArIGEgJSBiKTsgLy8gVGhlcmUgaXMgbm8gY2FzZSBpbiB3aGljaCB0aGlzIGRvZXNuJ3QgaG9sZAoKICAgICAgICByZXR1cm4gYzsKICAgIH0KICAgIGZ1bmN0aW9uIHN1Yih1aW50MjU2IGEsIHVpbnQyNTYgYikgaW50ZXJuYWwgcHVyZSByZXR1cm5zICh1aW50MjU2KSB7CiAgICAgICAgcmVxdWlyZShiIDw9IGEsICJTYWZlTWF0aDogc3VidHJhY3Rpb24gb3ZlcmZsb3ciKTsKICAgICAgICB1aW50MjU2IGMgPSBhIC0gYjsKCiAgICAgICAgcmV0dXJuIGM7CiAgICB9CiAgICBmdW5jdGlvbiBhZGQodWludDI1NiBhLCB1aW50MjU2IGIpIGludGVybmFsIHB1cmUgcmV0dXJucyAodWludDI1NikgewogICAgICAgIHVpbnQyNTYgYyA9IGEgKyBiOwogICAgICAgIHJlcXVpcmUoYyA+PSBhLCAiU2FmZU1hdGg6IGFkZGl0aW9uIG92ZXJmbG93Iik7CgogICAgICAgIHJldHVybiBjOwogICAgfQogICAgZnVuY3Rpb24gbW9kKHVpbnQyNTYgYSwgdWludDI1NiBiKSBpbnRlcm5hbCBwdXJlIHJldHVybnMgKHVpbnQyNTYpIHsKICAgICAgICByZXF1aXJlKGIgIT0gMCwgIlNhZmVNYXRoOiBtb2R1bG8gYnkgemVybyIpOwogICAgICAgIHJldHVybiBhICUgYjsKICAgIH0KfQo="; public static final String TABLE_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjQ7Cgpjb250cmFjdCBUYWJsZUZhY3RvcnkgewogICAgZnVuY3Rpb24gb3BlblRhYmxlKHN0cmluZykgcHVibGljIHZpZXcgcmV0dXJucyAoVGFibGUpOyAvL29wZW4gdGFibGUKICAgIGZ1bmN0aW9uIGNyZWF0ZVRhYmxlKHN0cmluZywgc3RyaW5nLCBzdHJpbmcpIHB1YmxpYyByZXR1cm5zIChpbnQyNTYpOyAvL2NyZWF0ZSB0YWJsZQp9CgovL3NlbGVjdCBjb25kaXRpb24KY29udHJhY3QgQ29uZGl0aW9uIHsKICAgIGZ1bmN0aW9uIEVRKHN0cmluZywgaW50MjU2KSBwdWJsaWMgdmlldzsKICAgIGZ1bmN0aW9uIEVRKHN0cmluZywgc3RyaW5nKSBwdWJsaWMgdmlldzsKICAgIGZ1bmN0aW9uIEVRKHN0cmluZywgYWRkcmVzcykgcHVibGljIHZpZXc7CgogICAgZnVuY3Rpb24gTkUoc3RyaW5nLCBpbnQyNTYpIHB1YmxpYyB2aWV3OwogICAgZnVuY3Rpb24gTkUoc3RyaW5nLCBzdHJpbmcpIHB1YmxpYyB2aWV3OwoKICAgIGZ1bmN0aW9uIEdUKHN0cmluZywgaW50MjU2KSBwdWJsaWMgdmlldzsKICAgIGZ1bmN0aW9uIEdFKHN0cmluZywgaW50MjU2KSBwdWJsaWMgdmlldzsKCiAgICBmdW5jdGlvbiBMVChzdHJpbmcsIGludDI1NikgcHVibGljIHZpZXc7CiAgICBmdW5jdGlvbiBMRShzdHJpbmcsIGludDI1NikgcHVibGljIHZpZXc7CgogICAgZnVuY3Rpb24gbGltaXQoaW50MjU2KSBwdWJsaWMgdmlldzsKICAgIGZ1bmN0aW9uIGxpbWl0KGludDI1NiwgaW50MjU2KSBwdWJsaWMgdmlldzsKfQoKLy9vbmUgcmVjb3JkCmNvbnRyYWN0IEVudHJ5IHsKICAgIGZ1bmN0aW9uIGdldEludChzdHJpbmcpIHB1YmxpYyB2aWV3IHJldHVybnMgKGludDI1Nik7CiAgICBmdW5jdGlvbiBnZXRVSW50KHN0cmluZykgcHVibGljIHZpZXcgcmV0dXJucyAodWludDI1Nik7CiAgICBmdW5jdGlvbiBnZXRBZGRyZXNzKHN0cmluZykgcHVibGljIHZpZXcgcmV0dXJucyAoYWRkcmVzcyk7CiAgICBmdW5jdGlvbiBnZXRCeXRlczY0KHN0cmluZykgcHVibGljIHZpZXcgcmV0dXJucyAoYnl0ZXMxWzY0XSk7CiAgICBmdW5jdGlvbiBnZXRCeXRlczMyKHN0cmluZykgcHVibGljIHZpZXcgcmV0dXJucyAoYnl0ZXMzMik7CiAgICBmdW5jdGlvbiBnZXRTdHJpbmcoc3RyaW5nKSBwdWJsaWMgdmlldyByZXR1cm5zIChzdHJpbmcpOwoKICAgIGZ1bmN0aW9uIHNldChzdHJpbmcsIGludDI1NikgcHVibGljOwogICAgZnVuY3Rpb24gc2V0KHN0cmluZywgdWludDI1NikgcHVibGljOwogICAgZnVuY3Rpb24gc2V0KHN0cmluZywgc3RyaW5nKSBwdWJsaWM7CiAgICBmdW5jdGlvbiBzZXQoc3RyaW5nLCBhZGRyZXNzKSBwdWJsaWM7Cn0KCi8vcmVjb3JkIHNldHMKY29udHJhY3QgRW50cmllcyB7CiAgICBmdW5jdGlvbiBnZXQoaW50MjU2KSBwdWJsaWMgdmlldyByZXR1cm5zIChFbnRyeSk7CiAgICBmdW5jdGlvbiBzaXplKCkgcHVibGljIHZpZXcgcmV0dXJucyAoaW50MjU2KTsKfQoKLy9UYWJsZSBtYWluIGNvbnRyYWN0CmNvbnRyYWN0IFRhYmxlIHsKICAgIGZ1bmN0aW9uIHNlbGVjdChzdHJpbmcsIENvbmRpdGlvbikgcHVibGljIHZpZXcgcmV0dXJucyAoRW50cmllcyk7CiAgICBmdW5jdGlvbiBpbnNlcnQoc3RyaW5nLCBFbnRyeSkgcHVibGljIHJldHVybnMgKGludDI1Nik7CiAgICBmdW5jdGlvbiB1cGRhdGUoc3RyaW5nLCBFbnRyeSwgQ29uZGl0aW9uKSBwdWJsaWMgcmV0dXJucyAoaW50MjU2KTsKICAgIGZ1bmN0aW9uIHJlbW92ZShzdHJpbmcsIENvbmRpdGlvbikgcHVibGljIHJldHVybnMgKGludDI1Nik7CgogICAgZnVuY3Rpb24gbmV3RW50cnkoKSBwdWJsaWMgdmlldyByZXR1cm5zIChFbnRyeSk7CiAgICBmdW5jdGlvbiBuZXdDb25kaXRpb24oKSBwdWJsaWMgdmlldyByZXR1cm5zIChDb25kaXRpb24pOwp9Cgpjb250cmFjdCBLVlRhYmxlRmFjdG9yeSB7CiAgICBmdW5jdGlvbiBvcGVuVGFibGUoc3RyaW5nKSBwdWJsaWMgdmlldyByZXR1cm5zIChLVlRhYmxlKTsKICAgIGZ1bmN0aW9uIGNyZWF0ZVRhYmxlKHN0cmluZywgc3RyaW5nLCBzdHJpbmcpIHB1YmxpYyByZXR1cm5zIChpbnQyNTYpOwp9CgovL0tWVGFibGUgcGVyIHBlcm1pYXJ5IGtleSBoYXMgb25seSBvbmUgRW50cnkKY29udHJhY3QgS1ZUYWJsZSB7CiAgICBmdW5jdGlvbiBnZXQoc3RyaW5nKSBwdWJsaWMgdmlldyByZXR1cm5zIChib29sLCBFbnRyeSk7CiAgICBmdW5jdGlvbiBzZXQoc3RyaW5nLCBFbnRyeSkgcHVibGljIHJldHVybnMgKGludDI1Nik7CiAgICBmdW5jdGlvbiBuZXdFbnRyeSgpIHB1YmxpYyB2aWV3IHJldHVybnMgKEVudHJ5KTsKfQo="; public static final String ROLES_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjQ7CgpsaWJyYXJ5IFJvbGVzIHsKICAgIHN0cnVjdCBSb2xlIHsKICAgICAgICBtYXBwaW5nIChhZGRyZXNzID0+IGJvb2wpIGJlYXJlcjsKICAgIH0KCiAgICBmdW5jdGlvbiBhZGQoUm9sZSBzdG9yYWdlIHJvbGUsIGFkZHJlc3MgYWNjb3VudCkgaW50ZXJuYWwgewogICAgICAgIHJlcXVpcmUoIWhhcyhyb2xlLCBhY2NvdW50KSwgIlJvbGVzOiBhY2NvdW50IGFscmVhZHkgaGFzIHJvbGUiKTsKICAgICAgICByb2xlLmJlYXJlclthY2NvdW50XSA9IHRydWU7CiAgICB9CgogICAgZnVuY3Rpb24gcmVtb3ZlKFJvbGUgc3RvcmFnZSByb2xlLCBhZGRyZXNzIGFjY291bnQpIGludGVybmFsIHsKICAgICAgICByZXF1aXJlKGhhcyhyb2xlLCBhY2NvdW50KSwgIlJvbGVzOiBhY2NvdW50IGRvZXMgbm90IGhhdmUgcm9sZSIpOwogICAgICAgIHJvbGUuYmVhcmVyW2FjY291bnRdID0gZmFsc2U7CiAgICB9CgogICAgZnVuY3Rpb24gaGFzKFJvbGUgc3RvcmFnZSByb2xlLCBhZGRyZXNzIGFjY291bnQpIGludGVybmFsIHZpZXcgcmV0dXJucyAoYm9vbCkgewogICAgICAgIHJlcXVpcmUoYWNjb3VudCAhPSBhZGRyZXNzKDApLCAiUm9sZXM6IGFjY291bnQgaXMgdGhlIHplcm8gYWRkcmVzcyIpOwogICAgICAgIHJldHVybiByb2xlLmJlYXJlclthY2NvdW50XTsKICAgIH0KfQo="; + // v1.5.2 + public static final String REGISTER_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjU7CgoKY29udHJhY3QgUmVnaXN0ZXIgIHsKICAgIC8qCiAgICAgKiBieXRlczQoa2VjY2FrMjU2KCdzdXBwb3J0c0ludGVyZmFjZShieXRlczQpJykpID09IDB4MDFmZmM5YTcKICAgICAqLwogICAgYnl0ZXM0IHByaXZhdGUgY29uc3RhbnQgX0lOVEVSRkFDRV9JRF9CQUMgPSAweDAxZmZjOWE3OwoKICAgIC8qKgogICAgICogQGRldiBNYXBwaW5nIG9mIGludGVyZmFjZSBpZHMgdG8gd2hldGhlciBvciBub3QgaXQncyBzdXBwb3J0ZWQuCiAgICAgKi8KICAgIG1hcHBpbmcoYnl0ZXM0ID0+IGJvb2wpIHByaXZhdGUgX3N1cHBvcnRlZEludGVyZmFjZXM7CgogICAgLyoqCiAgICAgKiBAZGV2IEEgY29udHJhY3QgaW1wbGVtZW50aW5nIFN1cHBvcnRzSW50ZXJmYWNlV2l0aExvb2t1cAogICAgICoKICAgICAqCiAgICAgKi8KICAgIGNvbnN0cnVjdG9yICgpIGludGVybmFsIHsKICAgICAgICBfcmVnaXN0ZXJJbnRlcmZhY2UoX0lOVEVSRkFDRV9JRF9CQUMpOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBJbXBsZW1lbnQgc3VwcG9ydHNJbnRlcmZhY2UoYnl0ZXM0KSB1c2luZyBhIGxvb2t1cCB0YWJsZS4KICAgICAqLwogICAgZnVuY3Rpb24gc3VwcG9ydHNJbnRlcmZhY2UoYnl0ZXM0IGludGVyZmFjZUlkKSBleHRlcm5hbCB2aWV3IHJldHVybnMgKGJvb2wpIHsKICAgICAgICByZXR1cm4gX3N1cHBvcnRlZEludGVyZmFjZXNbaW50ZXJmYWNlSWRdOwogICAgfQoKICAgIC8qKgogICAgICogQGRldiBJbnRlcm5hbCBtZXRob2QgZm9yIHJlZ2lzdGVyaW5nIGFuIGludGVyZmFjZS4KICAgICAqLwogICAgZnVuY3Rpb24gX3JlZ2lzdGVySW50ZXJmYWNlKGJ5dGVzNCBpbnRlcmZhY2VJZCkgaW50ZXJuYWwgewogICAgICAgIHJlcXVpcmUoaW50ZXJmYWNlSWQgIT0gMHhmZmZmZmZmZiwgIkJBQzogaW52YWxpZCBpbnRlcmZhY2UgaWQiKTsKICAgICAgICBfc3VwcG9ydGVkSW50ZXJmYWNlc1tpbnRlcmZhY2VJZF0gPSB0cnVlOwogICAgfQp9Cg=="; + public static final String COUNTERS_SOURCE = "cHJhZ21hIHNvbGlkaXR5IF4wLjQuMjU7CmltcG9ydCAiLi9TYWZlTWF0aC5zb2wiOwoKCmxpYnJhcnkgQ291bnRlcnMgewogICAgdXNpbmcgU2FmZU1hdGggZm9yIHVpbnQyNTY7CgogICAgc3RydWN0IENvdW50ZXIgewogICAgICAgIC8vIFRoaXMgdmFyaWFibGUgc2hvdWxkIG5ldmVyIGJlIGRpcmVjdGx5IGFjY2Vzc2VkIGJ5IHVzZXJzIG9mIHRoZSBsaWJyYXJ5OiBpbnRlcmFjdGlvbnMgbXVzdCBiZSByZXN0cmljdGVkIHRvCiAgICAgICAgLy8gdGhlIGxpYnJhcnkncyBmdW5jdGlvbi4gQXMgb2YgU29saWRpdHkgdjAuNS4yLCB0aGlzIGNhbm5vdCBiZSBlbmZvcmNlZCwgdGhvdWdoIHRoZXJlIGlzIGEgcHJvcG9zYWwgdG8gYWRkCiAgICAgICAgdWludDI1NiBfdmFsdWU7IC8vIGRlZmF1bHQ6IDAKICAgIH0KCiAgICBmdW5jdGlvbiBjdXJyZW50KENvdW50ZXIgc3RvcmFnZSBjb3VudGVyKSBpbnRlcm5hbCB2aWV3IHJldHVybnMgKHVpbnQyNTYpIHsKICAgICAgICByZXR1cm4gY291bnRlci5fdmFsdWU7CiAgICB9CgogICAgZnVuY3Rpb24gaW5jcmVtZW50KENvdW50ZXIgc3RvcmFnZSBjb3VudGVyKSBpbnRlcm5hbCB7CiAgICAgICAgY291bnRlci5fdmFsdWUgKz0gMTsKICAgIH0KCiAgICBmdW5jdGlvbiBkZWNyZW1lbnQoQ291bnRlciBzdG9yYWdlIGNvdW50ZXIpIGludGVybmFsIHsKICAgICAgICBjb3VudGVyLl92YWx1ZSA9IGNvdW50ZXIuX3ZhbHVlLnN1YigxKTsKICAgIH0KfQoKCi8qKgogKiBVdGlsaXR5IGxpYnJhcnkgb2YgaW5saW5lIGZ1bmN0aW9ucyBvbiBhZGRyZXNzZXMKICovCmxpYnJhcnkgQWRkcmVzcyB7CiAgICAvKioKICAgICAqIFJldHVybnMgd2hldGhlciB0aGUgdGFyZ2V0IGFkZHJlc3MgaXMgYSBjb250cmFjdAogICAgICogQGRldiBUaGlzIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIGZhbHNlIGlmIGludm9rZWQgZHVyaW5nIHRoZSBjb25zdHJ1Y3RvciBvZiBhIGNvbnRyYWN0LAogICAgICogYXMgdGhlIGNvZGUgaXMgbm90IGFjdHVhbGx5IGNyZWF0ZWQgdW50aWwgYWZ0ZXIgdGhlIGNvbnN0cnVjdG9yIGZpbmlzaGVzLgogICAgICogQHBhcmFtIGFjY291bnQgYWRkcmVzcyBvZiB0aGUgYWNjb3VudCB0byBjaGVjawogICAgICogQHJldHVybiB3aGV0aGVyIHRoZSB0YXJnZXQgYWRkcmVzcyBpcyBhIGNvbnRyYWN0CiAgICAgKi8KICAgIGZ1bmN0aW9uIGlzQ29udHJhY3QoYWRkcmVzcyBhY2NvdW50KSBpbnRlcm5hbCB2aWV3IHJldHVybnMgKGJvb2wpIHsKICAgICAgICB1aW50MjU2IHNpemU7CiAgICAgICAgLy8gWFhYIEN1cnJlbnRseSB0aGVyZSBpcyBubyBiZXR0ZXIgd2F5IHRvIGNoZWNrIGlmIHRoZXJlIGlzIGEgY29udHJhY3QgaW4gYW4gYWRkcmVzcwogICAgICAgIC8vIHRoYW4gdG8gY2hlY2sgdGhlIHNpemUgb2YgdGhlIGNvZGUgYXQgdGhhdCBhZGRyZXNzLgogICAgICAgIC8vIFNlZSBodHRwczovL2V0aGVyZXVtLnN0YWNrZXhjaGFuZ2UuY29tL2EvMTQwMTYvMzY2MDMKICAgICAgICAvLyBmb3IgbW9yZSBkZXRhaWxzIGFib3V0IGhvdyB0aGlzIHdvcmtzLgogICAgICAgIC8vIFRPRE8gQ2hlY2sgdGhpcyBhZ2FpbiBiZWZvcmUgdGhlIFNlcmVuaXR5IHJlbGVhc2UsIGJlY2F1c2UgYWxsIGFkZHJlc3NlcyB3aWxsIGJlCiAgICAgICAgLy8gY29udHJhY3RzIHRoZW4uCiAgICAgICAgLy8gc29saGludC1kaXNhYmxlLW5leHQtbGluZSBuby1pbmxpbmUtYXNzZW1ibHkKICAgICAgICBhc3NlbWJseSB7IHNpemUgOj0gZXh0Y29kZXNpemUoYWNjb3VudCkgfQogICAgICAgIHJldHVybiBzaXplID4gMDsKICAgIH0KfQ=="; + public static final String ADDRESS_MD = "# Address\n" + "\n" + "Address library\n" + @@ -46,6 +50,12 @@ public class ToolsConstantContext { public static final String ROLES_MD ="# Roles\n" + "\n" + "Role permissions control contracts\n"; + public static final String REGISTER_MD ="# Register\n" + + "\n" + + "Register control contract\n"; + public static final String COUNTERS_MD ="# Counters\n" + + "\n" + + "Counters tool contract\n"; /** * tool contract from smart dev diff --git a/src/main/java/com/webank/webase/front/keystore/entity/EncodeInfo.java b/src/main/java/com/webank/webase/front/keystore/entity/EncodeInfo.java index f7146112d..df049472e 100644 --- a/src/main/java/com/webank/webase/front/keystore/entity/EncodeInfo.java +++ b/src/main/java/com/webank/webase/front/keystore/entity/EncodeInfo.java @@ -14,15 +14,19 @@ package com.webank.webase.front.keystore.entity; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; /** * EncodeInfo */ @Data +@AllArgsConstructor +@NoArgsConstructor public class EncodeInfo { /** - * userId deprecated, use signUserId instead + * signUserId in webase-sign */ private String signUserId; private String encodedDataStr; diff --git a/src/main/java/com/webank/webase/front/scaffold/ScaffoldController.java b/src/main/java/com/webank/webase/front/scaffold/ScaffoldController.java index a549f1846..ba4f8b278 100644 --- a/src/main/java/com/webank/webase/front/scaffold/ScaffoldController.java +++ b/src/main/java/com/webank/webase/front/scaffold/ScaffoldController.java @@ -21,6 +21,7 @@ import com.webank.webase.front.scaffold.entity.ReqProject; import com.webank.webase.front.scaffold.entity.RspFile; import com.webank.webase.front.util.CommonUtils; +import com.webank.webase.front.util.ValidateUtil; import java.time.Duration; import java.time.Instant; import java.util.regex.Pattern; @@ -28,9 +29,11 @@ import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** @@ -43,6 +46,7 @@ public class ScaffoldController extends BaseController { @Autowired private ScaffoldService scaffoldService; + @PostMapping("/export") public BaseResponse exportProjectApi(@Valid @RequestBody ReqProject param) { Instant startTime = Instant.now(); @@ -81,7 +85,24 @@ public BaseResponse exportProjectApi(@Valid @RequestBody ReqProject param) { // start export RspFile rspFile = scaffoldService.exportProject(param); log.info("end exportProjectApi useTime:{} result:{}", - Duration.between(startTime, Instant.now()).toMillis(), rspFile); + Duration.between(startTime, Instant.now()).toMillis(), rspFile.getFileName()); return new BaseResponse(ConstantCode.RET_SUCCESS, rspFile); } + + @GetMapping("/check") + public BaseResponse checkChannelPort(@RequestParam("nodeIp") String nodeIp, + @RequestParam("channelPort") int channelPort) { + Instant startTime = Instant.now(); + log.info("start checkChannelPort startTime:{}, nodeIp:{} channelPort:{}", + startTime.toEpochMilli(), nodeIp, channelPort); + if(!ValidateUtil.ipv4Valid(nodeIp)) { + log.error("not valid nodeIp:{}", nodeIp); + throw new FrontException(ConstantCode.IP_FORMAT_ERROR); + } + Boolean result = scaffoldService.telnetChannelPort(nodeIp, channelPort); + + log.info("end exportProjectApi useTime:{} result:{}", + Duration.between(startTime, Instant.now()).toMillis(), result); + return new BaseResponse(ConstantCode.RET_SUCCESS, result); + } } diff --git a/src/main/java/com/webank/webase/front/scaffold/ScaffoldService.java b/src/main/java/com/webank/webase/front/scaffold/ScaffoldService.java index 98274b02d..35af489b2 100644 --- a/src/main/java/com/webank/webase/front/scaffold/ScaffoldService.java +++ b/src/main/java/com/webank/webase/front/scaffold/ScaffoldService.java @@ -26,6 +26,7 @@ import com.webank.webase.front.scaffold.entity.ReqProject; import com.webank.webase.front.scaffold.entity.RspFile; import com.webank.webase.front.util.CommonUtils; +import com.webank.webase.front.util.NetUtils; import com.webank.webase.front.util.ZipUtils; import com.webank.webase.front.web3api.Web3ApiService; import java.io.File; @@ -35,6 +36,7 @@ import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.fisco.bcos.sdk.crypto.CryptoSuite; import org.fisco.bcos.sdk.model.CryptoType; import org.springframework.beans.BeanUtils; @@ -86,8 +88,10 @@ public RspFile exportProject(ReqProject reqProject) { List tbContractList = new ArrayList<>(); for (Integer id : contractIdList) { Contract contract = contractService.findById(id.longValue()); - if (contract == null || StringUtils.isBlank(contract.getBytecodeBin())) { - log.error("exportProject contract not exist or not compiled, id:{}", id); + // if contract abi is null, not compile + // if abi is [](empty list), compile already + if (contract == null || contract.getContractAbi() == null) { + log.error("exportProject contract not exist or abi empty, id:{}", id); throw new FrontException(ConstantCode.INVALID_CONTRACT_ID); } tbContractList.add(contract); @@ -104,8 +108,8 @@ public RspFile exportProject(ReqProject reqProject) { List userAddressList = reqProject.getUserAddressList(); String hexPrivateKeyListStr = ""; if (userAddressList != null && !userAddressList.isEmpty()) { - // hexPrivateKeyListStr = this.handleUserList(reqProject.getGroupId(), userAddressList); - hexPrivateKeyListStr = keyStoreService.getPrivateKey(userAddressList.get(0)); + hexPrivateKeyListStr = this.handleUserList(userAddressList); + //hexPrivateKeyListStr = keyStoreService.getPrivateKey(userAddressList.get(0)); } // generate String projectPath = this.generateProject(thisConfig, reqProject.getGroup(), reqProject.getArtifactName(), @@ -147,7 +151,7 @@ public String generateProject(NodeConfig nodeConfig, String projectGroup, String log.info("generateProject projectGroup:{},artifactName:{},OUTPUT_DIR:{},frontChannelIpPort:{},groupId:{}", projectGroup, artifactName, OUTPUT_DIR, frontChannelIpPort, groupId); try { - projectFactory.buildProjectDir(contractInfoList, + projectFactory.buildProjectDirWebase(contractInfoList, projectGroup, artifactName, OUTPUT_DIR, GRADLE_WRAPPER_DIR, frontChannelIpPort, groupId, hexPrivateKeyListStr, sdkMap); } catch (Exception e) { @@ -160,9 +164,8 @@ public String generateProject(NodeConfig nodeConfig, String projectGroup, String } private List handleContractList(List contractList) { - log.info("handleContractList contractList:{}", contractList); + log.info("handleContractList contractList size:{}", contractList.size()); List contractInfoList = new ArrayList<>(); - log.info("handleContractList param contractList size:{}", contractList.size()); for (Contract contract : contractList) { String sourceCodeBase64 = contract.getContractSource(); String solSourceCode = new String(Base64.getDecoder().decode(sourceCodeBase64)); @@ -186,7 +189,6 @@ private List handleContractList(List contractList) { contractInfoList.add(contractInfo); } log.info("handleContractList result contractInfoList size:{}", contractInfoList.size()); - log.info("handleContractList contractList:{}", contractInfoList); return contractInfoList; } @@ -206,4 +208,17 @@ private String handleUserList(List userAddressList) { } return StringUtils.join(keyList, ","); } + + /** + * telnet channel port to check reachable + * @param nodeIp + * @param channelPort + * @return + */ + public Boolean telnetChannelPort(String nodeIp, int channelPort) { + Pair telnetResult = NetUtils.checkPorts(nodeIp, 2000, channelPort); + // if true, telnet success, port is in use, which means node's channelPort is correct + log.info("telnet {}:{} result:{}", nodeIp, channelPort, telnetResult); + return telnetResult.getLeft(); + } } diff --git a/src/main/java/com/webank/webase/front/transaction/TransController.java b/src/main/java/com/webank/webase/front/transaction/TransController.java index b0998788f..fbb71f1f0 100644 --- a/src/main/java/com/webank/webase/front/transaction/TransController.java +++ b/src/main/java/com/webank/webase/front/transaction/TransController.java @@ -15,6 +15,7 @@ */ package com.webank.webase.front.transaction; +import static com.webank.webase.front.base.code.ConstantCode.CONTRACT_ADDRESS_INVALID; import static com.webank.webase.front.base.code.ConstantCode.ENCODE_STR_CANNOT_BE_NULL; import static com.webank.webase.front.base.code.ConstantCode.INVALID_VERSION; import static com.webank.webase.front.base.code.ConstantCode.PARAM_ADDRESS_IS_INVALID; @@ -24,6 +25,7 @@ import com.webank.webase.front.base.code.ConstantCode; import com.webank.webase.front.base.controller.BaseController; import com.webank.webase.front.base.exception.FrontException; +import com.webank.webase.front.transaction.entity.ReqEncodeFunction; import com.webank.webase.front.transaction.entity.ReqQueryTransHandle; import com.webank.webase.front.transaction.entity.ReqSignMessageHash; import com.webank.webase.front.transaction.entity.ReqSignedTransHandle; @@ -38,6 +40,7 @@ import io.swagger.annotations.ApiOperation; import java.time.Duration; import java.time.Instant; +import java.util.List; import javax.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -45,10 +48,7 @@ import org.fisco.bcos.sdk.utils.Numeric; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.BindingResult; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * TransController. @@ -81,7 +81,8 @@ public Object transHandle(@Valid @RequestBody ReqTransHandleWithSign reqTransHan if (StringUtils.isBlank(reqTransHandle.getVersion()) && StringUtils.isBlank(address)) { throw new FrontException(VERSION_AND_ADDRESS_CANNOT_ALL_BE_NULL); } - if (!StringUtils.isBlank(address) && (address.length() != Address.ValidLen + if (StringUtils.isNotBlank(address) + && (address.length() != Address.ValidLen || org.fisco.bcos.sdk.abi.datatypes.Address.DEFAULT.toString().equals(address))) { throw new FrontException(PARAM_ADDRESS_IS_INVALID); } @@ -164,7 +165,10 @@ public Object sendQueryTransaction(@Valid @RequestBody ReqQueryTransHandle reqQu if (StringUtils.isBlank(encodeStr)) { throw new FrontException(ENCODE_STR_CANNOT_BE_NULL); } - Object obj = transServiceImpl.sendQueryTransaction(encodeStr, reqQueryTransHandle.getContractAddress(),reqQueryTransHandle.getFuncName(),reqQueryTransHandle.getContractAbi(),reqQueryTransHandle.getGroupId(),reqQueryTransHandle.getUserAddress()); + List contractAbi = JsonUtils.toJavaObjectList(reqQueryTransHandle.getContractAbi(), Object.class); + Object obj = transServiceImpl.sendQueryTransaction(encodeStr, reqQueryTransHandle.getContractAddress(), + reqQueryTransHandle.getFuncName(), contractAbi, reqQueryTransHandle.getGroupId(), + reqQueryTransHandle.getUserAddress()); log.info("transHandleLocal end useTime:{}", Duration.between(startTime, Instant.now()).toMillis()); return obj; } @@ -179,6 +183,27 @@ public Object signMessageHash(@Valid @RequestBody ReqSignMessageHash reqSignMess Instant startTime = Instant.now(); log.info("transHandleLocal start startTime:{}", startTime.toEpochMilli()); + if (!CommonUtils.isHexNumber(Numeric.cleanHexPrefix(reqSignMessageHash.getHash()))) { + throw new FrontException(ConstantCode.GET_MESSAGE_HASH, "not a hexadecimal hash string"); + } + if (Numeric.cleanHexPrefix(reqSignMessageHash.getHash()).length() != CommonUtils.HASH_LENGTH_64) { + throw new FrontException(ConstantCode.GET_MESSAGE_HASH, "wrong length"); + } + Object obj = transServiceImpl.signMessageLocal(reqSignMessageHash); + log.info("signMessageLocal end useTime:{}", + Duration.between(startTime, Instant.now()).toMillis()); + return obj; + } + + @ApiOperation(value = "sign Message locally", notes = "sign Message locally") + @ApiImplicitParam(name = "reqSignMessageHash", value = "ReqSignMessageHash info", required = true, dataType = "ReqSignMessageHash") + @PostMapping("/signMessageHashExternal") + public Object signMessageHashExternal(@Valid @RequestBody ReqSignMessageHash reqSignMessageHash, BindingResult result) { + log.info("transHandleLocal start. ReqTransHandle:[{}]", JsonUtils.toJSONString(reqSignMessageHash)); +// checkParamResult(result); + Instant startTime = Instant.now(); + log.info("signMessageHashExternal start startTime:{}", startTime.toEpochMilli()); + if(!CommonUtils.isHexNumber(Numeric.cleanHexPrefix(reqSignMessageHash.getHash()))) { throw new FrontException(ConstantCode.GET_MESSAGE_HASH, "not a hexadecimal hash string"); @@ -187,32 +212,35 @@ public Object signMessageHash(@Valid @RequestBody ReqSignMessageHash reqSignMess { throw new FrontException(ConstantCode.GET_MESSAGE_HASH, "wrong length"); } - Object obj = transServiceImpl.signMessageLocal(reqSignMessageHash); + Object obj = transServiceImpl.signMessageLocalExternal(reqSignMessageHash); log.info("signMessageLocal end useTime:{}", Duration.between(startTime, Instant.now()).toMillis()); return obj; } + /** - * transHandle through webase-sign + * raw tx to encoded string, and signed locally * @return */ - @ApiOperation(value = "transaction to raw tx str", notes = "transaction handling") + @ApiOperation(value = "transaction to raw tx str locally", notes = "transaction handling") @ApiImplicitParam(name = "reqTransHandle", value = "transaction info", required = true, dataType = "ReqTransHandle") - @PostMapping("/convertSignedTrans") - public String transToRawTxStrLocal(@Valid @RequestBody ReqTransHandle reqTransHandle, BindingResult result) throws Exception { + @PostMapping("/convertRawTxStr/local") + public String transToRawTxStrLocal(@Valid @RequestBody ReqTransHandle reqTransHandle, BindingResult result) + throws Exception { log.info("transToRawTxStrLocal start. ReqTransHandle:[{}]", JsonUtils.toJSONString(reqTransHandle)); Instant startTime = Instant.now(); log.info("transToRawTxStrLocal start startTime:{}", startTime.toEpochMilli()); checkParamResult(result); - String address = reqTransHandle.getContractAddress(); - if (StringUtils.isBlank(reqTransHandle.getVersion()) && StringUtils.isBlank(address)) { + // check contractAddress + String contractAddress = reqTransHandle.getContractAddress(); + if (StringUtils.isBlank(reqTransHandle.getVersion()) && StringUtils.isBlank(contractAddress)) { throw new FrontException(VERSION_AND_ADDRESS_CANNOT_ALL_BE_NULL); } - if (!StringUtils.isBlank(address) && address.length() != Address.ValidLen) { - throw new FrontException(PARAM_ADDRESS_IS_INVALID); + if (!StringUtils.isBlank(contractAddress) && contractAddress.length() != Address.ValidLen) { + throw new FrontException(CONTRACT_ADDRESS_INVALID); } if (reqTransHandle.isUseCns()) { if (!PrecompiledUtils.checkVersion(reqTransHandle.getVersion())) { @@ -222,11 +250,78 @@ public String transToRawTxStrLocal(@Valid @RequestBody ReqTransHandle reqTransHa throw new FrontException(PARAM_FAIL_CNS_NAME_IS_EMPTY); } } - String encodedOrSignedResult = transServiceImpl.transToRawTxStr(reqTransHandle); + String encodedOrSignedResult = transServiceImpl.createRawTxEncoded(true, reqTransHandle.getUser(), + reqTransHandle.getGroupId(), reqTransHandle.getContractAddress(), reqTransHandle.getContractAbi(), + reqTransHandle.isUseCns(), reqTransHandle.getVersion(), reqTransHandle.getVersion(), + reqTransHandle.getFuncName(), reqTransHandle.getFuncParam()); log.info("transToRawTxStrLocal end useTime:{},encodedOrSignedResult:{}", Duration.between(startTime, Instant.now()).toMillis(), encodedOrSignedResult); return encodedOrSignedResult; } + /** + * raw tx to encoded string signed by webase-sign + * @return + */ + @ApiOperation(value = "transaction to raw tx str", notes = "transaction handling") + @ApiImplicitParam(name = "reqTransHandle", value = "transaction info", required = true, dataType = "ReqTransHandleWithSign") + @PostMapping("/convertRawTxStr/withSign") + public String transToRawTxStrWithSign(@Valid @RequestBody ReqTransHandleWithSign reqTransHandle, + BindingResult result) throws Exception { + log.info("transToRawTxStrWithSign start. ReqTransHandleWithSign:[{}]", JsonUtils.toJSONString(reqTransHandle)); + + Instant startTime = Instant.now(); + log.info("transToRawTxStrWithSign start startTime:{}", startTime.toEpochMilli()); + + checkParamResult(result); + // check contractAddress + String contractAddress = reqTransHandle.getContractAddress(); + if (StringUtils.isBlank(reqTransHandle.getVersion()) && StringUtils.isBlank(contractAddress)) { + throw new FrontException(VERSION_AND_ADDRESS_CANNOT_ALL_BE_NULL); + } + if (StringUtils.isNotBlank(contractAddress) && contractAddress.length() != Address.ValidLen) { + throw new FrontException(PARAM_ADDRESS_IS_INVALID); + } + if (reqTransHandle.isUseCns()) { + if (!PrecompiledUtils.checkVersion(reqTransHandle.getVersion())) { + throw new FrontException(INVALID_VERSION); + } + if (StringUtils.isBlank(reqTransHandle.getCnsName())) { + throw new FrontException(PARAM_FAIL_CNS_NAME_IS_EMPTY); + } + } + String encodedOrSignedResult = transServiceImpl.createRawTxEncoded(false, reqTransHandle.getSignUserId(), + reqTransHandle.getGroupId(), reqTransHandle.getContractAddress(), reqTransHandle.getContractAbi(), + reqTransHandle.isUseCns(), reqTransHandle.getVersion(), reqTransHandle.getVersion(), + reqTransHandle.getFuncName(), reqTransHandle.getFuncParam()); + log.info("transToRawTxStrWithSign end useTime:{},encodedOrSignedResult:{}", + Duration.between(startTime, Instant.now()).toMillis(), encodedOrSignedResult); + return encodedOrSignedResult; + } + + + /** + * get encoded function string + * @return + */ + @ApiOperation(value = "transaction to encoded function string", notes = "transaction encode") + @ApiImplicitParam(name = "reqEncodeFunction", value = "transaction abi and function name and function param", required = true, dataType = "ReqEncodeFunction") + @PostMapping("/encodeFunction") + public String transEncoded2Str(@Valid @RequestBody ReqEncodeFunction reqEncodeFunction, BindingResult result) + throws Exception { + log.info("transEncoded2Str start. reqEncodeFunction:[{}]", JsonUtils.toJSONString(reqEncodeFunction)); + + Instant startTime = Instant.now(); + log.info("transEncoded2Str start startTime:{}", startTime.toEpochMilli()); + + checkParamResult(result); + + String encodedOrSignedResult = transServiceImpl.convertEncodedFunction2Str(reqEncodeFunction.getContractAbi(), + reqEncodeFunction.getFuncName(), reqEncodeFunction.getFuncParam()); + log.info("transEncoded2Str end useTime:{},encodedOrSignedResult:{}", + Duration.between(startTime, Instant.now()).toMillis(), encodedOrSignedResult); + return encodedOrSignedResult; + } + } diff --git a/src/main/java/com/webank/webase/front/transaction/TransService.java b/src/main/java/com/webank/webase/front/transaction/TransService.java index 5b982f537..86c516f84 100644 --- a/src/main/java/com/webank/webase/front/transaction/TransService.java +++ b/src/main/java/com/webank/webase/front/transaction/TransService.java @@ -26,7 +26,6 @@ import com.webank.webase.front.base.enums.PrecompiledTypes; import com.webank.webase.front.base.exception.FrontException; import com.webank.webase.front.base.properties.Constants; -import com.webank.webase.front.base.response.BaseResponse; import com.webank.webase.front.contract.CommonContract; import com.webank.webase.front.contract.ContractRepository; import com.webank.webase.front.contract.entity.Contract; @@ -34,6 +33,7 @@ import com.webank.webase.front.keystore.entity.EncodeInfo; import com.webank.webase.front.keystore.entity.KeyStoreInfo; import com.webank.webase.front.keystore.entity.RspMessageHashSignature; +import com.webank.webase.front.keystore.entity.RspUserInfo; import com.webank.webase.front.precompiledapi.PrecompiledCommonInfo; import com.webank.webase.front.precompiledapi.PrecompiledService; import com.webank.webase.front.transaction.entity.ContractFunction; @@ -49,13 +49,16 @@ import java.security.SecureRandom; import java.time.Duration; import java.time.Instant; + +import java.util.*; +import javax.persistence.Tuple; + import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Random; -import javax.persistence.Tuple; + import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.fisco.bcos.sdk.BcosSDK; @@ -85,7 +88,6 @@ import org.fisco.bcos.sdk.transaction.model.exception.ContractException; import org.fisco.bcos.sdk.transaction.model.po.RawTransaction; import org.fisco.bcos.sdk.transaction.pusher.TransactionPusherService; -import org.fisco.bcos.sdk.utils.ByteUtils; import org.fisco.bcos.sdk.utils.Numeric; import org.fisco.bcos.sdk.utils.ObjectMapperFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -224,6 +226,7 @@ private Object handleTransByFunction(int groupId, Client web3j, String signUserI TransactionDecoderService txDecoder = new TransactionDecoderService(cryptoSuite); String receiptMsg = txDecoder.decodeReceiptStatus(responseReceipt).getReceiptMessages(); responseReceipt.setMessage(receiptMsg); + CommonUtils.processReceiptHexNumber(responseReceipt); response = responseReceipt; log.info("***node cost time***: {}", Duration.between(nodeStartTime, Instant.now()).toMillis()); @@ -299,9 +302,9 @@ public static TransactionReceipt execTransaction(Function function, log.info("execTransaction start startTime:{}", startTime.toEpochMilli()); TransactionReceipt transactionReceipt = commonContract.execTransaction(function); // cover null message through statusCode - // String receiptMsg = FrontUtils.handleReceiptMsg(transactionReceipt); String receiptMsg = txDecoder.decodeReceiptStatus(transactionReceipt).getReceiptMessages(); transactionReceipt.setMessage(receiptMsg); + CommonUtils.processReceiptHexNumber(transactionReceipt); log.info("execTransaction end useTime:{}", Duration.between(startTime, Instant.now()).toMillis()); return transactionReceipt; @@ -530,7 +533,7 @@ public TransactionReceipt sendSignedTransaction(String signedStr, Boolean sync, public Object sendQueryTransaction(String encodeStr, String contractAddress, String funcName, - String contractAbi, int groupId, String userAddress) { + List contractAbi, int groupId, String userAddress) { Client web3j = web3ApiService.getWeb3j(groupId); String callOutput = web3j @@ -538,7 +541,7 @@ public Object sendQueryTransaction(String encodeStr, String contractAddress, Str encodeStr)) .getCallResult().getOutput(); - ABIDefinition abiDefinition = getFunctionAbiDefinition(funcName, contractAbi); + ABIDefinition abiDefinition = getFunctionAbiDefinition(funcName, JsonUtils.toJSONString(contractAbi)); if (Objects.isNull(abiDefinition)) { throw new FrontException(IN_FUNCTION_ERROR); } @@ -592,8 +595,7 @@ private CryptoKeyPair getCredentials(boolean constant, String keyUser) { return credentials; } - public SignatureResult signMessageHashByType(String messageHash, CryptoKeyPair cryptoKeyPair, - int encryptType) { + public SignatureResult signMessageHashByType(String messageHash, CryptoKeyPair cryptoKeyPair, int encryptType) { try { if (encryptType == CryptoType.SM_TYPE) { return smCryptoSuite.sign(messageHash, cryptoKeyPair); @@ -601,21 +603,22 @@ public SignatureResult signMessageHashByType(String messageHash, CryptoKeyPair c return ecdsaCryptoSuite.sign(messageHash, cryptoKeyPair); } } catch (Exception e) { + log.error("signMessageHashByType failed:[]", e); throw new FrontException(ConstantCode.GET_MESSAGE_HASH, e.getMessage()); } } /** * signMessageLocal + * @return SignatureResult */ public Object signMessageLocal(ReqSignMessageHash req) { log.info("transHandle start. ReqSignMessageHash:[{}]", JsonUtils.toJSONString(req)); - CryptoKeyPair cryptoKeyPair = keyStoreService.getCredentials(req.getUser()); - + CryptoKeyPair cryptoKeyPair = this.getCredentials(false, req.getUser()); SignatureResult signResult = signMessageHashByType( - org.fisco.bcos.sdk.utils.Numeric.cleanHexPrefix(req.getHash()), cryptoKeyPair, + Numeric.cleanHexPrefix(req.getHash()), cryptoKeyPair, cryptoSuite.cryptoTypeConfig); if (cryptoSuite.cryptoTypeConfig == CryptoType.SM_TYPE) { SM2SignatureResult sm2SignatureResult = (SM2SignatureResult) signResult; @@ -636,24 +639,53 @@ public Object signMessageLocal(ReqSignMessageHash req) { } } + + + /** + * signMessageLocalExternal + */ + public Object signMessageLocalExternal(ReqSignMessageHash req) { + log.info("transHandle start. ReqSignMessageHash:[{}]", JsonUtils.toJSONString(req)); + RspUserInfo rspUserInfo = keyStoreService.getUserInfoWithSign(req.getSignUserId(),true); + String privateKeyRaw = new String(Base64.getDecoder().decode(rspUserInfo.getPrivateKey())); + CryptoKeyPair cryptoKeyPair = cryptoSuite.createKeyPair(privateKeyRaw); + SignatureResult signResult = signMessageHashByType( + org.fisco.bcos.sdk.utils.Numeric.cleanHexPrefix(req.getHash()),cryptoKeyPair, + cryptoSuite.cryptoTypeConfig + ); + + if (cryptoSuite.cryptoTypeConfig == CryptoType.SM_TYPE) { + SM2SignatureResult sm2SignatureResult = (SM2SignatureResult) signResult; + RspMessageHashSignature rspMessageHashSignature = new RspMessageHashSignature(); + rspMessageHashSignature.setP(Numeric.toHexString(sm2SignatureResult.getPub())); + rspMessageHashSignature.setR(Numeric.toHexString(sm2SignatureResult.getR())); + rspMessageHashSignature.setS(Numeric.toHexString(sm2SignatureResult.getS())); + rspMessageHashSignature.setV((byte) 0); + return rspMessageHashSignature; + } else { + ECDSASignatureResult sm2SignatureResult = (ECDSASignatureResult) signResult; + RspMessageHashSignature rspMessageHashSignature = new RspMessageHashSignature(); + rspMessageHashSignature.setP("0x"); + rspMessageHashSignature.setR(Numeric.toHexString(sm2SignatureResult.getR())); + rspMessageHashSignature.setS(Numeric.toHexString(sm2SignatureResult.getS())); + rspMessageHashSignature.setV((byte) (sm2SignatureResult.getV()+27)); + return rspMessageHashSignature; + } + } + /** * get encoded raw transaction - * @param req req.user userAddress, if not null, return signed raw tx + * @param contractAddress if not null, return signed raw tx */ - public String transToRawTxStr(ReqTransHandle req) throws Exception { - // get signUserId - String user = req.getUser(); + public String createRawTxEncoded(boolean isLocal, String user, + int groupId, String contractAddress, List contractAbi, + boolean isUseCns, String cnsName, String cnsVersion, + String funcName, List funcParam) throws Exception { // check param get function of abi - ContractFunction contractFunction = buildContractFunctionWithAbi(req.getContractAbi(), - req.getFuncName(), req.getFuncParam()); - // check groupId - int groupId = req.getGroupId(); - Client web3j = web3ApiService.getWeb3j(groupId); - // check contractAddress - String contractAddress = req.getContractAddress(); - if (req.isUseCns()) { - List cnsList = precompiledService.queryCnsByNameAndVersion(req.getGroupId(), - req.getCnsName(), req.getVersion()); + ContractFunction contractFunction = buildContractFunctionWithAbi(contractAbi, funcName, funcParam); + + if (isUseCns) { + List cnsList = precompiledService.queryCnsByNameAndVersion(groupId, cnsName, cnsVersion); if (CollectionUtils.isEmpty(cnsList)) { throw new FrontException(VERSION_NOT_EXISTS); } @@ -661,18 +693,48 @@ public String transToRawTxStr(ReqTransHandle req) throws Exception { log.info("transHandleWithSign cns contractAddress:{}", contractAddress); } // encode function - Function function = new Function(req.getFuncName(), contractFunction.getFinalInputs(), + Function function = new Function(funcName, contractFunction.getFinalInputs(), contractFunction.getFinalOutputs()); - return createRawTxEncoded(groupId, web3j, contractAddress, function, user); + // check groupId + Client web3j = web3ApiService.getWeb3j(groupId); + // isLocal: + // true: user is userAddress locally + // false: user is signUserId in webase-sign + return this.convertRawTx2Str(groupId, web3j, contractAddress, function, user, isLocal); } + /** + * get encoded function for /trans/query-transaction + * @param contractAbi + * @param funcName + * @param funcParam + * @return + */ + public String convertEncodedFunction2Str(List contractAbi, + String funcName, List funcParam) { + // check param get function of abi + ContractFunction contractFunction = buildContractFunctionWithAbi(contractAbi, funcName, funcParam); + // encode function + Function function = new Function(funcName, contractFunction.getFinalInputs(), + contractFunction.getFinalOutputs()); + + FunctionEncoder functionEncoder = new FunctionEncoder(cryptoSuite); + String encodedFunction = functionEncoder.encode(function); + log.info("convertEncodedFunction2Str encodedFunction:{}", encodedFunction); + return encodedFunction; + } + + /** + * get encoded raw transaction * handleTransByFunction by whether is constant * if use signed data to send tx, call @send-signed-transaction api + * @case1 if @userAddress is blank, return not signed raw tx encoded str + * @case2 if @userAddress not blank, return signed str */ - private String createRawTxEncoded(int groupId, Client web3j, String contractAddress, - Function function, String userAddress) { + private String convertRawTx2Str(int groupId, Client web3j, String contractAddress, + Function function, String user, boolean isLocal) { // to encode raw tx BigInteger randomId = new BigInteger(250, new SecureRandom()); @@ -689,21 +751,44 @@ private String createRawTxEncoded(int groupId, Client web3j, String contractAddr TransactionEncoderService encoderService = new TransactionEncoderService(cryptoSuite); byte[] encodedTransaction = encoderService.encode(rawTransaction, null); // if user not null: sign, else, not sign - SignatureResult userSignResult = null; - if (!StringUtils.isBlank(userAddress)) { - log.info("createRawTxEncoded use key of {} to sign message", userAddress); + if (StringUtils.isBlank(user)) { + // return unsigned raw tx encoded str + String unsignedResultStr = Numeric.toHexString(encodedTransaction); + log.info("createRawTxEncoded unsignedResultStr:{}", unsignedResultStr); + return unsignedResultStr; + } else { + log.info("createRawTxEncoded use key of address [{}] to sign", user); + // hash encoded, to sign locally byte[] hashMessage = cryptoSuite.hash(encodedTransaction); String hashMessageStr = Numeric.toHexString(hashMessage); - log.info("createRawTxEncoded hashMessageStr:{}", hashMessageStr); - userSignResult = signMessageHashByType(hashMessageStr, - getCredentials(false, userAddress), - cryptoSuite.cryptoTypeConfig); + log.info("createRawTxEncoded encoded tx of hex str:{}", hashMessageStr); + // if local, sign locally + log.info("createRawTxEncoded isLocal:{}", isLocal); + String signResultStr; + if (isLocal) { + CryptoKeyPair cryptoKeyPair = this.getCredentials(false, user); + SignatureResult userSignResult = signMessageHashByType(hashMessageStr, + cryptoKeyPair, cryptoSuite.cryptoTypeConfig); + // encode again + byte[] signedMessage = encoderService.encode(rawTransaction, userSignResult); + signResultStr = Numeric.toHexString(signedMessage); + } else { + // sign by webase-sign + // convert encoded to hex string (no need to hash then toHex) + hashMessageStr = Numeric.toHexString(encodedTransaction); + EncodeInfo encodeInfo = new EncodeInfo(user, hashMessageStr); + String signDataStr = keyStoreService.getSignData(encodeInfo); + SignatureResult signData = CommonUtils.stringToSignatureData(signDataStr, cryptoSuite.cryptoTypeConfig); + byte[] signedMessage = encoderService.encode(rawTransaction, signData); + signResultStr = Numeric.toHexString(signedMessage); + } + log.info("createRawTxEncoded signResultStr:{}", signResultStr); + return signResultStr; } - // encode again - byte[] signedMessage = encoderService.encode(rawTransaction, userSignResult); - return Numeric.toHexString(signedMessage); + // trans hash is cryptoSuite.hash(signedStr) } + } diff --git a/src/main/java/com/webank/webase/front/transaction/entity/ReqEncodeFunction.java b/src/main/java/com/webank/webase/front/transaction/entity/ReqEncodeFunction.java new file mode 100644 index 000000000..7fd8199f7 --- /dev/null +++ b/src/main/java/com/webank/webase/front/transaction/entity/ReqEncodeFunction.java @@ -0,0 +1,34 @@ +/** + * Copyright 2014-2020 the original author or authors. + * + * 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.webank.webase.front.transaction.entity; + +import java.util.List; +import javax.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +/** + * get encoded function string + * @author marsli + */ +@Data +public class ReqEncodeFunction { + @NotBlank + private String funcName; + @NotNull + private List contractAbi; + @NotNull + private List funcParam; +} diff --git a/src/main/java/com/webank/webase/front/transaction/entity/ReqQueryTransHandle.java b/src/main/java/com/webank/webase/front/transaction/entity/ReqQueryTransHandle.java index 6a2945268..ed70626b8 100644 --- a/src/main/java/com/webank/webase/front/transaction/entity/ReqQueryTransHandle.java +++ b/src/main/java/com/webank/webase/front/transaction/entity/ReqQueryTransHandle.java @@ -1,9 +1,9 @@ package com.webank.webase.front.transaction.entity; -import lombok.Data; - import javax.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; @Data public class ReqQueryTransHandle { @@ -12,7 +12,7 @@ public class ReqQueryTransHandle { @NotNull private String contractAddress; private String funcName; - @NotNull + @NotBlank private String contractAbi; private String userAddress = "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"; private int groupId =1 ; diff --git a/src/main/java/com/webank/webase/front/transaction/entity/ReqSignMessageHash.java b/src/main/java/com/webank/webase/front/transaction/entity/ReqSignMessageHash.java index 513b91541..f5ea800f9 100644 --- a/src/main/java/com/webank/webase/front/transaction/entity/ReqSignMessageHash.java +++ b/src/main/java/com/webank/webase/front/transaction/entity/ReqSignMessageHash.java @@ -22,8 +22,6 @@ import org.hibernate.validator.constraints.NotBlank; import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; /** * signMessageHash interface parameter. @@ -37,5 +35,8 @@ public class ReqSignMessageHash { */ @NotNull(message = ConstantCode.PARAM_FAIL_USER_IS_EMPTY_STRING) private String user; + @NotBlank private String hash; + private String signUserId; + } diff --git a/src/main/java/com/webank/webase/front/util/NetUtils.java b/src/main/java/com/webank/webase/front/util/NetUtils.java new file mode 100644 index 000000000..be9984d8a --- /dev/null +++ b/src/main/java/com/webank/webase/front/util/NetUtils.java @@ -0,0 +1,86 @@ +/** + * Copyright 2014-2021 the original author or authors. + * + * 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.webank.webase.front.util; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.tuple.Pair; + +import lombok.extern.slf4j.Slf4j; + +/** + * check port by telnet: if connection reachable, it means port in use + * @author marsli + */ +@Slf4j +public class NetUtils { + + public static Pair checkPorts(String ip, int timeout, int ... portArray) { + if (ArrayUtils.isEmpty(portArray)){ + return Pair.of(false,0); + } + + for (int port : portArray) { + boolean reachable = checkAddress(ip, port, timeout); + if (reachable){ + return Pair.of(true, port); + } + } + return Pair.of(false,0); + } + + + public static boolean checkAddress(String ip, int port, int timeout) { + int newTimeout = timeout > 0 ? timeout : 2000; + + try { + try (Socket crunchifySocket = new Socket()) { + // Connects this socket to the server with a specified timeout value. + crunchifySocket.connect(new InetSocketAddress(ip, port), newTimeout); + } + // Return true if connection successful + return true; + } catch (IOException e) { + log.error("Connect to host:[{}] and port:[{}] with timeout:[{}] is error:{}.", ip, port, newTimeout, e.getMessage() ); + } + return false; + } + + /** + * Check ip:port accessible. + * @param address format ip:port, like 129.204.174.191:6004; + * @param timeout + * @return + */ + public static boolean checkAddress(String address, int timeout) { + String[] ipPortArray = address.split(":"); + if (ArrayUtils.getLength(ipPortArray) != 2) { + log.error("Address:[{}] format error, should be [ip:port], like 129.204.174.191:6004.", address); + return false; + } + try { + int port = Integer.parseInt(ipPortArray[1]); + return checkAddress(ipPortArray[0], port, timeout); + } catch (Exception e) { + log.error("Address:[{}] port error, should be [ip:port], like 129.204.174.191:6004.", address); + } + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/webank/webase/front/util/ValidateUtil.java b/src/main/java/com/webank/webase/front/util/ValidateUtil.java new file mode 100644 index 000000000..f0bde44fb --- /dev/null +++ b/src/main/java/com/webank/webase/front/util/ValidateUtil.java @@ -0,0 +1,67 @@ +/** + * Copyright 2014-2021 the original author or authors. + * + * 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.webank.webase.front.util; + +import org.apache.commons.lang3.StringUtils; +import lombok.extern.log4j.Log4j2; + +/** + * ValidateUtil. + */ + +@Log4j2 +public class ValidateUtil { + public static final String IP_PATTERN = + "^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$"; + + public static final String AGENCY_NAME_PATTERN = "^[0-9a-zA-Z_]+$"; + + /** + * Validate ipv4 address. + * + * @param ip + * @return return false if ip is not a valid IP format. + */ + public static boolean ipv4Valid(final String ip) { + if (StringUtils.isBlank(ip)) { + return false; + } + return ip.matches(IP_PATTERN); + } + + public static boolean validateAgencyName(final String agencyName) { + if (StringUtils.isBlank(agencyName)) { + return false; + } + return agencyName.matches(AGENCY_NAME_PATTERN); + } + + public static boolean validateUrl(String url) { + if (StringUtils.isBlank(url)) { + return false; + } + url = url.toLowerCase(); + String regex = "^((https|http|ftp|rtsp|mms)?://)" // https、http、ftp、rtsp、mms + + "?(([0-9a-z_!~*‘().&=+$%-]+: )?[0-9a-z_!~*‘().&=+$%-]+@)?" // ftp的user@ + + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 例如:199.194.52.184 + + "|" // 允许IP和DOMAIN(域名) + + "([0-9a-z_!~*‘()-]+\\.)*" // 域名- www. + + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名 + + "[a-z]{2,6})" // first level domain- .com or .museum + + "(:[0-9]{1,5})?" // 端口号最大为65535,5位数 + + "((/?)|" // a slash isn‘t required if there is no file name + + "(/[0-9a-z_!~*‘().;?:@&=+$,%#-]+)+/?)$"; + return url.matches(regex); + } +} diff --git a/src/main/java/com/webank/webase/front/util/ZipUtils.java b/src/main/java/com/webank/webase/front/util/ZipUtils.java index b3e28975b..cb270ab7c 100644 --- a/src/main/java/com/webank/webase/front/util/ZipUtils.java +++ b/src/main/java/com/webank/webase/front/util/ZipUtils.java @@ -82,11 +82,9 @@ private static void generateFile(ZipOutputStream out, File file, String dir) thr if (file.isDirectory()) { //得到文件列表信息 File[] files = file.listFiles(); - - //将文件夹添加到下一级打包目录 - out.putNextEntry(new ZipEntry(dir + "/")); - dir = dir.length() == 0 ? "" : dir + "/"; + //将文件夹添加到下一级打包目录 + out.putNextEntry(new ZipEntry(dir)); //循环将文件夹中的文件打包 for (int i = 0; i < files.length; i++) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6fb538c42..344dd00c3 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ # server version -version: v1.5.1 +version: v1.5.2 spring: datasource: diff --git a/src/main/resources/conf/gm/gmsdk.publickey b/src/main/resources/conf/gm/gmsdk.publickey new file mode 100644 index 000000000..46d9c60f4 --- /dev/null +++ b/src/main/resources/conf/gm/gmsdk.publickey @@ -0,0 +1 @@ +7e95dc204b7f83e686cb6317becba3e3a83e9e88c08f28c17e20db479b1abdb4b0629e1c3d40d5e696c518e4c857eb8cc2063cba159868c5b9f6f4287482d891 diff --git a/src/main/resources/conf/sdk.publickey b/src/main/resources/conf/sdk.publickey new file mode 100644 index 000000000..0eddc3691 --- /dev/null +++ b/src/main/resources/conf/sdk.publickey @@ -0,0 +1 @@ +508ad0422c058db68ab6b36c62bb5ed6d41ec28bf3118a5de536877b4bd979d72d13b181aab08eb106ef6b2d55b9c4475021ed7c9ab9d0ee5e867a118b74d35c diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 5afb04103..7ac69c057 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -15,7 +15,7 @@ vertical-align: -0.15em; fill: currentColor; overflow: hidden; - }
+ * 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.webank.webase.front.transaction.entity; + +import java.util.List; +import javax.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; + +/** + * get encoded function string + * @author marsli + */ +@Data +public class ReqEncodeFunction { + @NotBlank + private String funcName; + @NotNull + private List contractAbi; + @NotNull + private List funcParam; +} diff --git a/src/main/java/com/webank/webase/front/transaction/entity/ReqQueryTransHandle.java b/src/main/java/com/webank/webase/front/transaction/entity/ReqQueryTransHandle.java index 6a2945268..ed70626b8 100644 --- a/src/main/java/com/webank/webase/front/transaction/entity/ReqQueryTransHandle.java +++ b/src/main/java/com/webank/webase/front/transaction/entity/ReqQueryTransHandle.java @@ -1,9 +1,9 @@ package com.webank.webase.front.transaction.entity; -import lombok.Data; - import javax.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.NotBlank; @Data public class ReqQueryTransHandle { @@ -12,7 +12,7 @@ public class ReqQueryTransHandle { @NotNull private String contractAddress; private String funcName; - @NotNull + @NotBlank private String contractAbi; private String userAddress = "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"; private int groupId =1 ; diff --git a/src/main/java/com/webank/webase/front/transaction/entity/ReqSignMessageHash.java b/src/main/java/com/webank/webase/front/transaction/entity/ReqSignMessageHash.java index 513b91541..f5ea800f9 100644 --- a/src/main/java/com/webank/webase/front/transaction/entity/ReqSignMessageHash.java +++ b/src/main/java/com/webank/webase/front/transaction/entity/ReqSignMessageHash.java @@ -22,8 +22,6 @@ import org.hibernate.validator.constraints.NotBlank; import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; /** * signMessageHash interface parameter. @@ -37,5 +35,8 @@ public class ReqSignMessageHash { */ @NotNull(message = ConstantCode.PARAM_FAIL_USER_IS_EMPTY_STRING) private String user; + @NotBlank private String hash; + private String signUserId; + } diff --git a/src/main/java/com/webank/webase/front/util/NetUtils.java b/src/main/java/com/webank/webase/front/util/NetUtils.java new file mode 100644 index 000000000..be9984d8a --- /dev/null +++ b/src/main/java/com/webank/webase/front/util/NetUtils.java @@ -0,0 +1,86 @@ +/** + * Copyright 2014-2021 the original author or authors. + * + * 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.webank.webase.front.util; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.tuple.Pair; + +import lombok.extern.slf4j.Slf4j; + +/** + * check port by telnet: if connection reachable, it means port in use + * @author marsli + */ +@Slf4j +public class NetUtils { + + public static Pair checkPorts(String ip, int timeout, int ... portArray) { + if (ArrayUtils.isEmpty(portArray)){ + return Pair.of(false,0); + } + + for (int port : portArray) { + boolean reachable = checkAddress(ip, port, timeout); + if (reachable){ + return Pair.of(true, port); + } + } + return Pair.of(false,0); + } + + + public static boolean checkAddress(String ip, int port, int timeout) { + int newTimeout = timeout > 0 ? timeout : 2000; + + try { + try (Socket crunchifySocket = new Socket()) { + // Connects this socket to the server with a specified timeout value. + crunchifySocket.connect(new InetSocketAddress(ip, port), newTimeout); + } + // Return true if connection successful + return true; + } catch (IOException e) { + log.error("Connect to host:[{}] and port:[{}] with timeout:[{}] is error:{}.", ip, port, newTimeout, e.getMessage() ); + } + return false; + } + + /** + * Check ip:port accessible. + * @param address format ip:port, like 129.204.174.191:6004; + * @param timeout + * @return + */ + public static boolean checkAddress(String address, int timeout) { + String[] ipPortArray = address.split(":"); + if (ArrayUtils.getLength(ipPortArray) != 2) { + log.error("Address:[{}] format error, should be [ip:port], like 129.204.174.191:6004.", address); + return false; + } + try { + int port = Integer.parseInt(ipPortArray[1]); + return checkAddress(ipPortArray[0], port, timeout); + } catch (Exception e) { + log.error("Address:[{}] port error, should be [ip:port], like 129.204.174.191:6004.", address); + } + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/webank/webase/front/util/ValidateUtil.java b/src/main/java/com/webank/webase/front/util/ValidateUtil.java new file mode 100644 index 000000000..f0bde44fb --- /dev/null +++ b/src/main/java/com/webank/webase/front/util/ValidateUtil.java @@ -0,0 +1,67 @@ +/** + * Copyright 2014-2021 the original author or authors. + * + * 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.webank.webase.front.util; + +import org.apache.commons.lang3.StringUtils; +import lombok.extern.log4j.Log4j2; + +/** + * ValidateUtil. + */ + +@Log4j2 +public class ValidateUtil { + public static final String IP_PATTERN = + "^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$"; + + public static final String AGENCY_NAME_PATTERN = "^[0-9a-zA-Z_]+$"; + + /** + * Validate ipv4 address. + * + * @param ip + * @return return false if ip is not a valid IP format. + */ + public static boolean ipv4Valid(final String ip) { + if (StringUtils.isBlank(ip)) { + return false; + } + return ip.matches(IP_PATTERN); + } + + public static boolean validateAgencyName(final String agencyName) { + if (StringUtils.isBlank(agencyName)) { + return false; + } + return agencyName.matches(AGENCY_NAME_PATTERN); + } + + public static boolean validateUrl(String url) { + if (StringUtils.isBlank(url)) { + return false; + } + url = url.toLowerCase(); + String regex = "^((https|http|ftp|rtsp|mms)?://)" // https、http、ftp、rtsp、mms + + "?(([0-9a-z_!~*‘().&=+$%-]+: )?[0-9a-z_!~*‘().&=+$%-]+@)?" // ftp的user@ + + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 例如:199.194.52.184 + + "|" // 允许IP和DOMAIN(域名) + + "([0-9a-z_!~*‘()-]+\\.)*" // 域名- www. + + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名 + + "[a-z]{2,6})" // first level domain- .com or .museum + + "(:[0-9]{1,5})?" // 端口号最大为65535,5位数 + + "((/?)|" // a slash isn‘t required if there is no file name + + "(/[0-9a-z_!~*‘().;?:@&=+$,%#-]+)+/?)$"; + return url.matches(regex); + } +} diff --git a/src/main/java/com/webank/webase/front/util/ZipUtils.java b/src/main/java/com/webank/webase/front/util/ZipUtils.java index b3e28975b..cb270ab7c 100644 --- a/src/main/java/com/webank/webase/front/util/ZipUtils.java +++ b/src/main/java/com/webank/webase/front/util/ZipUtils.java @@ -82,11 +82,9 @@ private static void generateFile(ZipOutputStream out, File file, String dir) thr if (file.isDirectory()) { //得到文件列表信息 File[] files = file.listFiles(); - - //将文件夹添加到下一级打包目录 - out.putNextEntry(new ZipEntry(dir + "/")); - dir = dir.length() == 0 ? "" : dir + "/"; + //将文件夹添加到下一级打包目录 + out.putNextEntry(new ZipEntry(dir)); //循环将文件夹中的文件打包 for (int i = 0; i < files.length; i++) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6fb538c42..344dd00c3 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ # server version -version: v1.5.1 +version: v1.5.2 spring: datasource: diff --git a/src/main/resources/conf/gm/gmsdk.publickey b/src/main/resources/conf/gm/gmsdk.publickey new file mode 100644 index 000000000..46d9c60f4 --- /dev/null +++ b/src/main/resources/conf/gm/gmsdk.publickey @@ -0,0 +1 @@ +7e95dc204b7f83e686cb6317becba3e3a83e9e88c08f28c17e20db479b1abdb4b0629e1c3d40d5e696c518e4c857eb8cc2063cba159868c5b9f6f4287482d891 diff --git a/src/main/resources/conf/sdk.publickey b/src/main/resources/conf/sdk.publickey new file mode 100644 index 000000000..0eddc3691 --- /dev/null +++ b/src/main/resources/conf/sdk.publickey @@ -0,0 +1 @@ +508ad0422c058db68ab6b36c62bb5ed6d41ec28bf3118a5de536877b4bd979d72d13b181aab08eb106ef6b2d55b9c4475021ed7c9ab9d0ee5e867a118b74d35c diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 5afb04103..7ac69c057 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -15,7 +15,7 @@ vertical-align: -0.15em; fill: currentColor; overflow: hidden; - }
+ * 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 + *
+ * 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.webank.webase.front.util; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.tuple.Pair; + +import lombok.extern.slf4j.Slf4j; + +/** + * check port by telnet: if connection reachable, it means port in use + * @author marsli + */ +@Slf4j +public class NetUtils { + + public static Pair checkPorts(String ip, int timeout, int ... portArray) { + if (ArrayUtils.isEmpty(portArray)){ + return Pair.of(false,0); + } + + for (int port : portArray) { + boolean reachable = checkAddress(ip, port, timeout); + if (reachable){ + return Pair.of(true, port); + } + } + return Pair.of(false,0); + } + + + public static boolean checkAddress(String ip, int port, int timeout) { + int newTimeout = timeout > 0 ? timeout : 2000; + + try { + try (Socket crunchifySocket = new Socket()) { + // Connects this socket to the server with a specified timeout value. + crunchifySocket.connect(new InetSocketAddress(ip, port), newTimeout); + } + // Return true if connection successful + return true; + } catch (IOException e) { + log.error("Connect to host:[{}] and port:[{}] with timeout:[{}] is error:{}.", ip, port, newTimeout, e.getMessage() ); + } + return false; + } + + /** + * Check ip:port accessible. + * @param address format ip:port, like 129.204.174.191:6004; + * @param timeout + * @return + */ + public static boolean checkAddress(String address, int timeout) { + String[] ipPortArray = address.split(":"); + if (ArrayUtils.getLength(ipPortArray) != 2) { + log.error("Address:[{}] format error, should be [ip:port], like 129.204.174.191:6004.", address); + return false; + } + try { + int port = Integer.parseInt(ipPortArray[1]); + return checkAddress(ipPortArray[0], port, timeout); + } catch (Exception e) { + log.error("Address:[{}] port error, should be [ip:port], like 129.204.174.191:6004.", address); + } + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/webank/webase/front/util/ValidateUtil.java b/src/main/java/com/webank/webase/front/util/ValidateUtil.java new file mode 100644 index 000000000..f0bde44fb --- /dev/null +++ b/src/main/java/com/webank/webase/front/util/ValidateUtil.java @@ -0,0 +1,67 @@ +/** + * Copyright 2014-2021 the original author or authors. + * + * 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.webank.webase.front.util; + +import org.apache.commons.lang3.StringUtils; +import lombok.extern.log4j.Log4j2; + +/** + * ValidateUtil. + */ + +@Log4j2 +public class ValidateUtil { + public static final String IP_PATTERN = + "^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$"; + + public static final String AGENCY_NAME_PATTERN = "^[0-9a-zA-Z_]+$"; + + /** + * Validate ipv4 address. + * + * @param ip + * @return return false if ip is not a valid IP format. + */ + public static boolean ipv4Valid(final String ip) { + if (StringUtils.isBlank(ip)) { + return false; + } + return ip.matches(IP_PATTERN); + } + + public static boolean validateAgencyName(final String agencyName) { + if (StringUtils.isBlank(agencyName)) { + return false; + } + return agencyName.matches(AGENCY_NAME_PATTERN); + } + + public static boolean validateUrl(String url) { + if (StringUtils.isBlank(url)) { + return false; + } + url = url.toLowerCase(); + String regex = "^((https|http|ftp|rtsp|mms)?://)" // https、http、ftp、rtsp、mms + + "?(([0-9a-z_!~*‘().&=+$%-]+: )?[0-9a-z_!~*‘().&=+$%-]+@)?" // ftp的user@ + + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 例如:199.194.52.184 + + "|" // 允许IP和DOMAIN(域名) + + "([0-9a-z_!~*‘()-]+\\.)*" // 域名- www. + + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名 + + "[a-z]{2,6})" // first level domain- .com or .museum + + "(:[0-9]{1,5})?" // 端口号最大为65535,5位数 + + "((/?)|" // a slash isn‘t required if there is no file name + + "(/[0-9a-z_!~*‘().;?:@&=+$,%#-]+)+/?)$"; + return url.matches(regex); + } +} diff --git a/src/main/java/com/webank/webase/front/util/ZipUtils.java b/src/main/java/com/webank/webase/front/util/ZipUtils.java index b3e28975b..cb270ab7c 100644 --- a/src/main/java/com/webank/webase/front/util/ZipUtils.java +++ b/src/main/java/com/webank/webase/front/util/ZipUtils.java @@ -82,11 +82,9 @@ private static void generateFile(ZipOutputStream out, File file, String dir) thr if (file.isDirectory()) { //得到文件列表信息 File[] files = file.listFiles(); - - //将文件夹添加到下一级打包目录 - out.putNextEntry(new ZipEntry(dir + "/")); - dir = dir.length() == 0 ? "" : dir + "/"; + //将文件夹添加到下一级打包目录 + out.putNextEntry(new ZipEntry(dir)); //循环将文件夹中的文件打包 for (int i = 0; i < files.length; i++) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6fb538c42..344dd00c3 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ # server version -version: v1.5.1 +version: v1.5.2 spring: datasource: diff --git a/src/main/resources/conf/gm/gmsdk.publickey b/src/main/resources/conf/gm/gmsdk.publickey new file mode 100644 index 000000000..46d9c60f4 --- /dev/null +++ b/src/main/resources/conf/gm/gmsdk.publickey @@ -0,0 +1 @@ +7e95dc204b7f83e686cb6317becba3e3a83e9e88c08f28c17e20db479b1abdb4b0629e1c3d40d5e696c518e4c857eb8cc2063cba159868c5b9f6f4287482d891 diff --git a/src/main/resources/conf/sdk.publickey b/src/main/resources/conf/sdk.publickey new file mode 100644 index 000000000..0eddc3691 --- /dev/null +++ b/src/main/resources/conf/sdk.publickey @@ -0,0 +1 @@ +508ad0422c058db68ab6b36c62bb5ed6d41ec28bf3118a5de536877b4bd979d72d13b181aab08eb106ef6b2d55b9c4475021ed7c9ab9d0ee5e867a118b74d35c diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 5afb04103..7ac69c057 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -15,7 +15,7 @@ vertical-align: -0.15em; fill: currentColor; overflow: hidden; - }
+ * 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.webank.webase.front.util; + +import org.apache.commons.lang3.StringUtils; +import lombok.extern.log4j.Log4j2; + +/** + * ValidateUtil. + */ + +@Log4j2 +public class ValidateUtil { + public static final String IP_PATTERN = + "^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$"; + + public static final String AGENCY_NAME_PATTERN = "^[0-9a-zA-Z_]+$"; + + /** + * Validate ipv4 address. + * + * @param ip + * @return return false if ip is not a valid IP format. + */ + public static boolean ipv4Valid(final String ip) { + if (StringUtils.isBlank(ip)) { + return false; + } + return ip.matches(IP_PATTERN); + } + + public static boolean validateAgencyName(final String agencyName) { + if (StringUtils.isBlank(agencyName)) { + return false; + } + return agencyName.matches(AGENCY_NAME_PATTERN); + } + + public static boolean validateUrl(String url) { + if (StringUtils.isBlank(url)) { + return false; + } + url = url.toLowerCase(); + String regex = "^((https|http|ftp|rtsp|mms)?://)" // https、http、ftp、rtsp、mms + + "?(([0-9a-z_!~*‘().&=+$%-]+: )?[0-9a-z_!~*‘().&=+$%-]+@)?" // ftp的user@ + + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" // IP形式的URL- 例如:199.194.52.184 + + "|" // 允许IP和DOMAIN(域名) + + "([0-9a-z_!~*‘()-]+\\.)*" // 域名- www. + + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." // 二级域名 + + "[a-z]{2,6})" // first level domain- .com or .museum + + "(:[0-9]{1,5})?" // 端口号最大为65535,5位数 + + "((/?)|" // a slash isn‘t required if there is no file name + + "(/[0-9a-z_!~*‘().;?:@&=+$,%#-]+)+/?)$"; + return url.matches(regex); + } +} diff --git a/src/main/java/com/webank/webase/front/util/ZipUtils.java b/src/main/java/com/webank/webase/front/util/ZipUtils.java index b3e28975b..cb270ab7c 100644 --- a/src/main/java/com/webank/webase/front/util/ZipUtils.java +++ b/src/main/java/com/webank/webase/front/util/ZipUtils.java @@ -82,11 +82,9 @@ private static void generateFile(ZipOutputStream out, File file, String dir) thr if (file.isDirectory()) { //得到文件列表信息 File[] files = file.listFiles(); - - //将文件夹添加到下一级打包目录 - out.putNextEntry(new ZipEntry(dir + "/")); - dir = dir.length() == 0 ? "" : dir + "/"; + //将文件夹添加到下一级打包目录 + out.putNextEntry(new ZipEntry(dir)); //循环将文件夹中的文件打包 for (int i = 0; i < files.length; i++) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6fb538c42..344dd00c3 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ # server version -version: v1.5.1 +version: v1.5.2 spring: datasource: diff --git a/src/main/resources/conf/gm/gmsdk.publickey b/src/main/resources/conf/gm/gmsdk.publickey new file mode 100644 index 000000000..46d9c60f4 --- /dev/null +++ b/src/main/resources/conf/gm/gmsdk.publickey @@ -0,0 +1 @@ +7e95dc204b7f83e686cb6317becba3e3a83e9e88c08f28c17e20db479b1abdb4b0629e1c3d40d5e696c518e4c857eb8cc2063cba159868c5b9f6f4287482d891 diff --git a/src/main/resources/conf/sdk.publickey b/src/main/resources/conf/sdk.publickey new file mode 100644 index 000000000..0eddc3691 --- /dev/null +++ b/src/main/resources/conf/sdk.publickey @@ -0,0 +1 @@ +508ad0422c058db68ab6b36c62bb5ed6d41ec28bf3118a5de536877b4bd979d72d13b181aab08eb106ef6b2d55b9c4475021ed7c9ab9d0ee5e867a118b74d35c diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 5afb04103..7ac69c057 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -15,7 +15,7 @@ vertical-align: -0.15em; fill: currentColor; overflow: hidden; - }