diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..714ece5271 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,22 @@ +*.class +target/ + +# IDE files +.idea/ +*.iml +.classpath +.project +.settings/ +out/ + +logs/ + +velocity.log.* +*.log + +dependency-reduced-pom.xml + +.protegedata/ +.devdata/ + +.vscode/ diff --git a/.gitignore b/.gitignore index 1061d9f839..714ece5271 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,7 @@ velocity.log.* dependency-reduced-pom.xml -.protegedata/ \ No newline at end of file +.protegedata/ +.devdata/ + +.vscode/ diff --git a/docker-compose.yml b/docker-compose.yml index 34238c6fc1..afd3f4aae6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,23 +2,33 @@ version: "3" services: + ganache: + image: trufflesuite/ganache-cli:latest + ports: + - '8545:8545' + command: ganache-cli -s attestation -l 100000000000 + # mnemonic: endorse soccer immense wonder cheap crew hundred protect bunker lemon burden wash + wpmongo: container_name: webprotege-mongodb image: mongo:4.1-bionic restart: unless-stopped volumes: - ./.protegedata/mongodb:/data/db + ports: + - '27017:27017' - webprotege: - container_name: webprotege - image: protegeproject/webprotege + webprotege-attestation: + container_name: webprotege-attestation + image: curtys/webprotege-attestation:latest depends_on: - wpmongo + - ganache restart: unless-stopped environment: - webprotege.mongodb.host=wpmongo volumes: - ./.protegedata/protege:/srv/webprotege ports: - - 5000:8080 + - '5000:8080' diff --git a/docs/guide.md b/docs/guide.md new file mode 100644 index 0000000000..152e736ff7 --- /dev/null +++ b/docs/guide.md @@ -0,0 +1,31 @@ +# How to use the attestation extension + +Requirements (see the installation instructions): +- Running WebProtégé instance (either as Docker container or using Maven). +- Deployed contracts (either in a local test blockchain, e.g., in Ganache or on a public network). +- [Metamask](https://metamask.io/) plugin for your browser. + +## Setting up Metamask +1) Install the Metamask plugin for your browser. You may follow the [Metamask installation guide](https://metamask.zendesk.com/hc/en-us/articles/360015489531-Getting-started-with-MetaMask). +2) Open the extension and login to your account (if you have one) or create/import a new one by entering a Mnemonic (Secret Recovery Phrase). If you use the Ganache instance chose "Import wallet" and enter the Mnemonic phrase found in the `docker-compose.yml` file. The Mnemonic is a phrase of 12+ lower-case words. +3) If using a local blockchain, e.g., the Ganache instance configured in the `docker-compose.yml` file, you need to add a custom network as explained here: https://metamask.zendesk.com/hc/en-us/articles/360043227612-How-to-add-a-custom-network-RPC. For the Ganache instance, enter following values: +``` + RPC Url: localhost: + Chain ID: 1 +``` +4) Switch to the network where the contracts are deployed (e.g., localhost for Ganache) + +## Attesting to the provenance of an ontology in WebProtégé + +1. Log into WebProtégé (by default https://localhost:5000 when using docker or https://localhost:8080 in DevMode) and import an Ontology, e.g., download one from [BioPortal](https://bioportal.bioontology.org), by pressing "Create new project". +![webprotege1.png](webprotege1.png) +1. Open the project and add a new view by clicking the menu icon of a tab and selecting "Add new view". +![webprotege2.png](webprotege2.png) +A popup appears. Select the portlet named "Ontology Attestation". Then place the view on the screen. +![webprotege3.png](webprotege3.png) +1. In the attestation panel (here on the right) select the IRI of the ontology to attest (the IRIs of imported ontologies are shown as well) with the dropdown menu. +![webprotege4.png](webprotege4.png) +1. Once an IRI is selected an attestation may be started by clicking "Sign". Metamask will then prompt to log in. If the popup does not appear, click the Metamask icon on the Plugin bar of your browser. +![webprotege5.png](webprotege5.png) +1. After unlocking Metamask a transaction request is shown. Make sure you have selected the correct network (see previouse section). Authorizing the transaction closes the popup and the result is displayed in the attestation panel. +![webprotege5.png](webprotege6.png) diff --git a/docs/package_protege.png b/docs/package_protege.png new file mode 100644 index 0000000000..645d1a18dd Binary files /dev/null and b/docs/package_protege.png differ diff --git a/docs/webprotege1.png b/docs/webprotege1.png new file mode 100644 index 0000000000..f0109d4e47 Binary files /dev/null and b/docs/webprotege1.png differ diff --git a/docs/webprotege2.png b/docs/webprotege2.png new file mode 100644 index 0000000000..ebbe174a9f Binary files /dev/null and b/docs/webprotege2.png differ diff --git a/docs/webprotege3.png b/docs/webprotege3.png new file mode 100644 index 0000000000..5343a02009 Binary files /dev/null and b/docs/webprotege3.png differ diff --git a/docs/webprotege4.png b/docs/webprotege4.png new file mode 100644 index 0000000000..7a00a97905 Binary files /dev/null and b/docs/webprotege4.png differ diff --git a/docs/webprotege5.png b/docs/webprotege5.png new file mode 100644 index 0000000000..05577b270d Binary files /dev/null and b/docs/webprotege5.png differ diff --git a/docs/webprotege6.png b/docs/webprotege6.png new file mode 100644 index 0000000000..db01841c28 Binary files /dev/null and b/docs/webprotege6.png differ diff --git a/pom.xml b/pom.xml index 7d1c219213..18876d8db8 100644 --- a/pom.xml +++ b/pom.xml @@ -30,8 +30,8 @@ - scm:git:https://github.com/protegeproject/webprotege.git - https://github.com/webprotege/webprotege.git + scm:git:git://github.com:curtys/webprotege-attestation.git + https://github.com/curtys/webprotege-attestation.git @@ -444,6 +444,16 @@ + + dev + + false + + + ${project.basedir}/../.devdata + + + @@ -454,5 +464,6 @@ webprotege-client webprotege-shared-core webprotege-cli + webprotege-attestation-lib diff --git a/readme.md b/readme.md index 92ec6191c8..df4a7d960d 100644 --- a/readme.md +++ b/readme.md @@ -1,91 +1,101 @@ -WebProtégé +Fork of WebProtégé implementing ontology attestation and verification ========== -What is WebProtégé? -------------------- +Modification of the [WebProtégé ontology editor](https://github.com/protegeproject/webprotege) to support ontology attestation by implementing a custom portlet. See the original readme below for +instructions for WebProtégé in general. To run a pre-built docker image see the section ["Running from docker"](#running-from-docker). -WebProtégé is a free, open source collaborative ontology development environment. +## Relevant links +- For further documentation see the [Attestation library module](webprotege-attestation-lib) and its [readme](webprotege-attestation-lib/README.md) +- Attestation portlet [usage guide](docs/guide.md) +- [Dataset](webprotege-attestation-lib/dataset) and results used for publication -It provides the following features: -- Support for editing OWL 2 ontologies -- A default simple editing interface, which provides access to commonly used OWL constructs -- Full change tracking and revision history -- Collaboration tools such as, sharing and permissions, threaded notes and discussions, watches and email notifications -- Customizable user interface -- Support for editing OBO ontologies -- Multiple file formats for upload and download of ontologies (supported formats: RDF/XML, Turtle, OWL/XML, OBO, and others) +## Requirements -WebProtégé runs as a Web application. End users access it through their Web browsers. -They do not need to download or install any software. We encourage end-users to use +- Development requirements of the attestation module for compiling and deploying smart contracts: + - [solc 7.1.0+](https://docs.soliditylang.org/en/v0.8.10/installing-solidity.html#linux-packages) + - [web3j-cli](http://docs.web3j.io/4.8.7/command_line_tools/) + - [Node and NPM](https://nodejs.org/en/) + - [Metamask](metamask.io) (or other wallet plugin) for client blockchain interaction +- [Docker Compose](https://docs.docker.com/compose/install/) +- Java 8 and Maven -https://webprotege.stanford.edu - -If you have downloaded the webprotege war file from GitHub, and would like to deploy it on your own server, -please follow the instructions at: - -https://github.com/protegeproject/webprotege/wiki/WebProtégé-4.0.0-beta-x-Installation - -Building --------- +## Building for development To build WebProtégé from source -1) Clone the github repository - ``` - git clone https://github.com/protegeproject/webprotege.git - ``` -2) Open a terminal in the directory where you clone the repository to -3) Use maven to package WebProtégé +1. Clone the github repository +2. Open a terminal in the directory where you clone the repository +3. Use maven to package WebProtégé ``` mvn clean package ``` -5) The WebProtege .war file will be built into the webprotege-server directory + To ignore tests use + ``` + mvn clean package -DskipTests=True + ``` +5. The WebProtege .war file will be built into the webprotege-server directory -Running from Maven ------------------- +## Starting in DevMode -To run WebProtégé in SuperDev Mode using maven +- first, consider following the instructions of the **attestation module** to set up an Ethereum test network +- start the database with `docker-compose up -d wpmongo` +- start the GWT code server with `mvn gwt:codeserver` +- in a different terminal start a tomcat server instance with `mvn -P dev -Denv=dev tomcat7:run`. The maven profile `-P dev` will result in WebProtégé storing its data in `.devdata` instead of the default directory (`/srv/webprotege`). +- first time starting up (or after resetting the database) an admin user has to be created. + Executed the **webprotege-cli** JAR (compile it, if not already done). E.g., + `java -jar webprotege-cli/target/webprotege-cli-{version}.jar create-admin-account` +- by default, WebProtégé is available on [http://localhost:8080](http://localhost:8080). +- After the first start, some application settings need to be configured. Login to [localhost:8080/#application/settings](the settings page) with the previously created admin account. -1) Start the GWT code server in one terminal window - ``` - mvn gwt:codeserver - ``` -2) In a different terminal window start the tomcat server - ``` - mvn -Denv=dev tomcat7:run - ``` -3) Browse to WebProtégé in a Web browser by navigating to [http://localhost:8080](http://localhost:8080) +Detailed installation instructions can be found in the [official wiki](https://github.com/protegeproject/webprotege/wiki/WebProt%C3%A9g%C3%A9-4.0.0-Installation). -Running from Docker -------------------- +## Running from Docker -To run WebProtégé using Docker containers: +A pre-built docker image is available. To run the project stack from docker: -1. Enter this following command in the Terminal to start the docker container in the background +1. Enter this following command in the Terminal to start the docker container in the background. This will start containers for all dependand services as well, i.e., MongoDB and Ganache. ```bash docker-compose up -d ``` +1. Deploy the smart contracts (e.g., to Ganache). Follow the instructions [here](webprotege-attestation-lib/README.md). -2. Create the admin user (follow the questions prompted to provider username, email and password) +1. Create the admin user (follow the questions prompted to provider username, email and password) ```bash docker exec -it webprotege java -jar /webprotege-cli.jar create-admin-account ``` -3. Browse to WebProtégé Settings page in a Web browser by navigating to [http://localhost:5000/#application/settings](http://localhost:5000/#application/settings) - 1. Define the `System notification email address` and `application host URL` - 2. Enable `User creation`, `Project creation` and `Project import` +1. Browse to WebProtégé Settings page in a Web browser by navigating to [http://localhost:5000/#application/settings](http://localhost:5000/#application/settings) + 1. Define the `System notification email address` and `application host URL` + 2. Enable `User creation`, `Project creation` and `Project import` -To stop WebProtégé and MongoDB: +To stop WebProtégé, MongoDB and the Ganache test instance: ```bash docker-compose down ``` -Sharing the volumes used by the WebProtégé app and MongoDB allow to keep persistent data, even when the containers stop. Default shared data storage: +Sharing the volumes used by the WebProtégé app and MongoDB allows for keeping persistent data, even when the containers stop. Default shared data storage: * WebProtégé will store its data in the source code folder at `./.protegedata/protege` where you run `docker-compose` * MongoDB will store its data in the source code folder at `./.protegedata/mongodb` where you run `docker-compose` > Path to the shared volumes can be changed in the `docker-compose.yml` file. + +By default, a Ganache test blockchain will be started. WebProtégé is pre-configured to use this chain. It is possible to change the chain by setting environment variables in `docker-compose.yml` (of the servcie `webprotege-attestation`): +```yaml +environment: + - webprotege.mongodb.host=wpmongo + - ADDRESS_ATTESTATION= + - PROVIDER_HOST= + - PROVIDER_PORT= +``` + +## Changes made in this fork +Some key classes were altered to integrate an attestation +portlet in the editor. The portlet can be added by choosing 'Attestation' from the list of available portlets, +e.g. when adding a new tab. +In the graphic below the altered classes are marked in red and the added packages in green. + +![docs/package_protege.png](docs/package_protege.png) diff --git a/webprotege-attestation-lib/.gitignore b/webprotege-attestation-lib/.gitignore new file mode 100644 index 0000000000..23cc86eadc --- /dev/null +++ b/webprotege-attestation-lib/.gitignore @@ -0,0 +1,42 @@ +# Java (general) +*.class +bin/ + +# Maven +target/ +*.releaseBackup + +# Eclipse +.project +.classpath +.settings/ +/build + +# IntelliJ +.idea/ +*.iml +*.iws + +# VisualCode +**/.vscode/ + +# Netbeans +build.xml +manifest.mf +nbproject/ +/data + +# Subversion +.svn + +# Mac +.DS_Store + +# npm +**/node_modules/ + +/bin +/results +*.owl +*.rdf +*.ttl diff --git a/webprotege-attestation-lib/README.md b/webprotege-attestation-lib/README.md new file mode 100644 index 0000000000..9c7e13b3b3 --- /dev/null +++ b/webprotege-attestation-lib/README.md @@ -0,0 +1,56 @@ +## Ontology attestation and verification module for WebProtégé + +A module for WebProtégé, implementing an approach for ontology attestation. See also the [usage guide](../docs/guide.md). + +## Development requirements +* [solc 7.1.0+](https://docs.soliditylang.org/en/v0.8.10/installing-solidity.html#linux-packages) +* [web3j-cli](http://docs.web3j.io/4.8.7/command_line_tools/) +* [Node and NPM](https://nodejs.org/en/) +* [Ganache / Ganache CLI](https://trufflesuite.com/ganache/) +* [Metamask](metamask.io) (or other wallet plugin) for client blockchain interaction +* Java 8 + Maven + +## Building the module +The module can be compiled and installed locally with `mvn clean install`. The smart contracts need to be compiled and deployed separately. + +## Compiling and deploying the smart contracts +The `scripts` folder contains utilities for compiling and deploying the contracts. +1. Compile solidity contracts (requires `solc`): + ``` + sh ./compile-contracts.sh + ``` +2. Generate Java contract interfaces and wrappers (only needed for development purposes, requires `web3j-cli` and `solc`): + ``` + sh ./generate-contract-wrappers.sh + ``` +3. Start a local Ganache test blockchain with the docker-compose file in the [parent directory](../readme.md) (execute from the project root). + ``` + docker-compose up -d ganache + ``` +4. The seed is fixed, use the mnemonic indicated in the docker-compose file to access the test accounts (in Metamask this is the "Secret Recovery Phrase"). + +5. Deploy contracts (execute from the `scripts` folder, requires `node` and `npm`): + The connection to the chain is confiigured in the `.env` file in the same folder and is pre-configured for Ganache as started by `docker-compose.yml`. + ``` + npm install + npm run deploy + ``` + +## Configuration +The contract address must be made available to the application server. To do this, configure the address in `src/main/java/resources/configuration/config.properties`. +Alternatively, the address may be set n the environment with the key `ADDRESS_ATTESTATION`, the RPC provider host and port by `PROVIDER_HOST` and `PROVIDER_PORT` respectively. These can also be set inside the `docker-compose.yml` file as follows in the service definition of `webprotege-attestation`. + +```yaml +environment: + - webprotege.mongodb.host=wpmongo + - ADDRESS_ATTESTATION= + - PROVIDER_HOST= + - PROVIDER_PORT= +``` + +## Dataset & Running the tests +The evaluation dataset and test results can be found in the folder `dataset/`. +The tests require the ontologies to be placed in `src/test/resources/ontologies`. + +Configuration of the test blockchain provider are located in `src/test/resources/configuration`. The tests use the JUnit +framework and can thus be run manually by an appropriate runner, e.g., through Intellij. diff --git a/webprotege-attestation-lib/dataset/ESWC22/plot.zip b/webprotege-attestation-lib/dataset/ESWC22/plot.zip new file mode 100644 index 0000000000..952743c464 Binary files /dev/null and b/webprotege-attestation-lib/dataset/ESWC22/plot.zip differ diff --git a/webprotege-attestation-lib/dataset/ISWC21/plot.zip b/webprotege-attestation-lib/dataset/ISWC21/plot.zip new file mode 100644 index 0000000000..48496b49f3 Binary files /dev/null and b/webprotege-attestation-lib/dataset/ISWC21/plot.zip differ diff --git a/webprotege-attestation-lib/dataset/ISWC21/readme.txt b/webprotege-attestation-lib/dataset/ISWC21/readme.txt new file mode 100644 index 0000000000..d913efa2f8 --- /dev/null +++ b/webprotege-attestation-lib/dataset/ISWC21/readme.txt @@ -0,0 +1,17 @@ +This collection includes the raw measurment data, as well as the prepared data for plotting and the gnuplot scripts. +The test ontologies are listed in "ontologies.csv". + +ATTRIBUTION + +Historical gas price obtained from etherscan.io - https://etherscan.io/chart/gasprice +Historical Eth price obtained from etherscan.io - https://etherscan.io/chart/etherprice + +LICENSE + +Copyright 2021 Simon Curty, University of Fribourg + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/webprotege-attestation-lib/dataset/ISWC21/test-ontologies.csv b/webprotege-attestation-lib/dataset/ISWC21/test-ontologies.csv new file mode 100644 index 0000000000..84027a4e50 --- /dev/null +++ b/webprotege-attestation-lib/dataset/ISWC21/test-ontologies.csv @@ -0,0 +1,11 @@ +"id","name","classes","url","download-url" +"DOID","Human Disease Ontology",17198,"https://bioportal.bioontology.org/ontologies/DOID","https://data.bioontology.org/ontologies/DOID/submissions/605/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"FOODON","The FoodOn Food Ontology",29778,"https://bioportal.bioontology.org/ontologies/FOODON","https://data.bioontology.org/ontologies/FOODON/submissions/72/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"HOOM","ORDO Ontological Module",117828,"https://bioportal.bioontology.org/ontologies/HOOM","https://data.bioontology.org/ontologies/HOOM/submissions/4/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"NCIT","National Cancer Institute Thesaurus",164521,"https://bioportal.bioontology.org/ontologies/NCIT","https://data.bioontology.org/ontologies/NCIT/submissions/104/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"OBI","Ontology for Biomedical Investigations",3754,"https://bioportal.bioontology.org/ontologies/OBI","https://data.bioontology.org/ontologies/OBI/submissions/44/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"OBOREL","Relations Ontology",85,"https://bioportal.bioontology.org/ontologies/OBOREL","https://data.bioontology.org/ontologies/OBOREL/submissions/21/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"ORDO","Orphanet Rare Disease Ontology",14733,"https://bioportal.bioontology.org/ontologies/ORDO","https://data.bioontology.org/ontologies/ORDO/submissions/21/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"PATO","Phenotypic Quality Ontology",2809,"https://bioportal.bioontology.org/ontologies/PATO","https://data.bioontology.org/ontologies/PATO/submissions/181/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"UBERON","Uber Anatomy Ontology",20465,"https://bioportal.bioontology.org/ontologies/UBERON","https://data.bioontology.org/ontologies/UBERON/submissions/316/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" +"VTO","Vertebrate Taxonomy Ontology",107254,"https://bioportal.bioontology.org/ontologies/VTO","https://data.bioontology.org/ontologies/VTO/submissions/14/download?apikey=8b5b7825-538d-40e0-9e9e-5ab9274a9aeb" diff --git a/webprotege-attestation-lib/pom.xml b/webprotege-attestation-lib/pom.xml new file mode 100644 index 0000000000..e9272e2b4c --- /dev/null +++ b/webprotege-attestation-lib/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + + + edu.stanford.protege + webprotege + 5.0.0-SNAPSHOT + + + ch.unifr.digits.webprotege + webprotege-attestation-lib + gwt-lib + + + + + 2.8.2 + 1.8 + 1.8 + UTF-8 + + + + + + com.google.gwt + gwt + ${gwtVersion} + pom + import + + + org.junit + junit-bom + 5.7.0 + pom + import + + + + + + + com.google.gwt + gwt-dev + provided + + + com.google.gwt + gwt-user + provided + + + com.google.elemental2 + elemental2-promise + 1.1.0 + + + edu.stanford.protege + webprotege-shared + ${project.version} + compile + + + + org.web3j + core + 4.6.3 + + + + + org.junit.jupiter + junit-jupiter + test + + + junit + junit + 4.13.1 + test + + + net.sourceforge.owlapi + owlapi-apibinding + 4.5.13 + test + + + net.sourceforge.owlapi + owlapi-rio + 4.5.13 + compile + + + + + + + + src/main/resources + + + + + net.ltgt.gwt.maven + gwt-maven-plugin + 1.0.0 + true + + ch.unifr.digits.webprotege.attestation.Attestation + + + + + diff --git a/webprotege-attestation-lib/scripts/.env b/webprotege-attestation-lib/scripts/.env new file mode 100644 index 0000000000..05f801e3af --- /dev/null +++ b/webprotege-attestation-lib/scripts/.env @@ -0,0 +1,5 @@ +PROVIDER_HOST=http://localhost +PROVIDER_PORT=8545 +ADDRESS_ATTESTATION=0x6a8F5Ef06D06137b5aBDc14201343dF54dcfDBDC +ADDRESS_CHANGETRACKING=0x41c293160913d7cD816093D702e2dDA7391A3976 +SERVER_SECRET=0x2fe929a15797d2170c063b758dee33b55ad7c13313c110b675d3a9709fe83797 diff --git a/webprotege-attestation-lib/scripts/compile-contracts.sh b/webprotege-attestation-lib/scripts/compile-contracts.sh new file mode 100644 index 0000000000..6c0da9bd5f --- /dev/null +++ b/webprotege-attestation-lib/scripts/compile-contracts.sh @@ -0,0 +1 @@ +solc --evm-version istanbul --abi --bin --optimize --overwrite -o ./../build/ ../src/main/solidity/* \ No newline at end of file diff --git a/webprotege-attestation-lib/scripts/deploy-contracts.js b/webprotege-attestation-lib/scripts/deploy-contracts.js new file mode 100644 index 0000000000..8f68aa8c5c --- /dev/null +++ b/webprotege-attestation-lib/scripts/deploy-contracts.js @@ -0,0 +1,51 @@ +const Web3 = require('web3'); +const fs = require('fs'); +require('dotenv').config({ path: `.env` }); + +const buildPath = `${__dirname}/../build/`; +const contracts = ['OntologyAttestation', 'ChangeTracking']; +const buildPathTesting = `${__dirname}/../build/testing/`; +const contractsTesting = ['Storage']; + + +function load(contractName, basePath = buildPath) { + const abi = fs.readFileSync(`${basePath}${contractName}.abi`, 'UTF-8'); + const bin = fs.readFileSync(`${basePath}${contractName}.bin`, 'UTF-8'); + return { abi: JSON.parse(abi), bin: bin }; +} + +async function deploy(name, abi, bin) { + var contract = new web3.eth.Contract(abi); + return new Promise((resolve, reject) => { + contract.deploy({ data: bin }).send({ + from: account.address, + gas: '4700000' + }).then(newContractInstance => { + console.log(`Contract ${name} deployed. address: ${newContractInstance.options.address}`); + resolve(name); + }).catch(e => { + console.error(e); + reject(e); + }); + }); +} + +const provider = `${process.env.PROVIDER_HOST}:${process.env.PROVIDER_PORT}`; +console.log(`Using web3 provider: ${provider}`); + +const web3 = new Web3(provider); +const account = web3.eth.accounts.privateKeyToAccount(process.env.SERVER_SECRET); +console.log(`Using web3 account: ${account.address}`); + +(async function(){ + for (const c of contracts) { + console.log(`Deploying ${c} ...`); + const compileOut = load(c); + await deploy(c, compileOut.abi, compileOut.bin); + } + for (const c of contractsTesting) { + console.log(`Deploying ${c} ...`); + const compileOut = load(c, buildPathTesting); + await deploy(c, compileOut.abi, compileOut.bin); + } +})() \ No newline at end of file diff --git a/webprotege-attestation-lib/scripts/generate-contract-wrappers.sh b/webprotege-attestation-lib/scripts/generate-contract-wrappers.sh new file mode 100644 index 0000000000..4c22275a65 --- /dev/null +++ b/webprotege-attestation-lib/scripts/generate-contract-wrappers.sh @@ -0,0 +1,13 @@ +solc --evm-version istanbul --abi --bin --optimize --overwrite -o ./../build/ ../src/main/solidity/* +for f in ../build/*.abi; do + cp -- "$f" "../src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/interfaces/$(basename -- "$f" .abi).json" + epirus generate solidity generate -a "$f" -o ../build/wrapper/ -p ch.unifr.digits.webprotege.attestation.server.contracts +done +find ../build/wrapper -type f | grep -i java$ | xargs -i cp {} ../src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts + +# Testing contracts +solc --evm-version istanbul --abi --bin --optimize --overwrite -o ./../build/testing ../src/test/solidity/* +for f in ../build/testing/*.abi; do + epirus generate solidity generate -a "$f" -o ../build/wrapper/testing/ -p ch.unifr.digits.contracts +done +find ../build/wrapper/testing -type f | grep -i java$ | xargs -i cp {} ../src/test/java/ch/unifr/digits/contracts \ No newline at end of file diff --git a/webprotege-attestation-lib/scripts/package-lock.json b/webprotege-attestation-lib/scripts/package-lock.json new file mode 100644 index 0000000000..bdc7be5128 --- /dev/null +++ b/webprotege-attestation-lib/scripts/package-lock.json @@ -0,0 +1,3006 @@ +{ + "name": "webprotege-attestation", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@ethersproject/abi": { + "version": "5.0.0-beta.153", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz", + "integrity": "sha512-aXweZ1Z7vMNzJdLpR1CZUAIgnwjrZeUSvN9syCwlBaEBUFJmFY+HHnfuTI5vIhVs/mRkfJVrbEyl51JZQqyjAg==", + "dev": true, + "requires": { + "@ethersproject/address": ">=5.0.0-beta.128", + "@ethersproject/bignumber": ">=5.0.0-beta.130", + "@ethersproject/bytes": ">=5.0.0-beta.129", + "@ethersproject/constants": ">=5.0.0-beta.128", + "@ethersproject/hash": ">=5.0.0-beta.128", + "@ethersproject/keccak256": ">=5.0.0-beta.127", + "@ethersproject/logger": ">=5.0.0-beta.129", + "@ethersproject/properties": ">=5.0.0-beta.131", + "@ethersproject/strings": ">=5.0.0-beta.130" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.0.7.tgz", + "integrity": "sha512-NF16JGn6M0zZP5ZS8KtDL2Rh7yHxZbUjBIHLNHMm/0X0BephhjUWy8jqs/Zks6kDJRzNthgmPVy41Ec0RYWPYA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/networks": "^5.0.3", + "@ethersproject/properties": "^5.0.3", + "@ethersproject/transactions": "^5.0.5", + "@ethersproject/web": "^5.0.6" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.0.9.tgz", + "integrity": "sha512-CM5UNmXQaA03MyYARFDDRjHWBxujO41tVle7glf5kHcQsDDULgqSVpkliLJMtPzZjOKFeCVZBHybTZDEZg5zzg==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.0.4", + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3" + } + }, + "@ethersproject/address": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.0.8.tgz", + "integrity": "sha512-V87DHiZMZR6hmFYmoGaHex0D53UEbZpW75uj8AqPbjYUmi65RB4N2LPRcJXuWuN2R0Y2CxkvW6ArijWychr5FA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.0.10", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/keccak256": "^5.0.3", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/rlp": "^5.0.3" + } + }, + "@ethersproject/base64": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.0.6.tgz", + "integrity": "sha512-HwrGn8YMiUf7bcdVvB4NJ+eWT0BtEFpDtrYxVXEbR7p/XBSJjwiR7DEggIiRvxbualMKg+EZijQWJ3az2li0uw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.0.4" + } + }, + "@ethersproject/bignumber": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.0.12.tgz", + "integrity": "sha512-mbFZjwthx6vFlHG9owXP/C5QkNvsA+xHpDCkPPPdG2n1dS9AmZAL5DI0InNLid60rQWL3MXpEl19tFmtL7Q9jw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.0.8", + "@ethersproject/logger": "^5.0.5", + "bn.js": "^4.4.0" + } + }, + "@ethersproject/bytes": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.0.8.tgz", + "integrity": "sha512-O+sJNVGzzuy51g+EMK8BegomqNIg+C2RO6vOt0XP6ac4o4saiq69FnjlsrNslaiMFVO7qcEHBsWJ9hx1tj1lMw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.0.5" + } + }, + "@ethersproject/constants": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.0.7.tgz", + "integrity": "sha512-cbQK1UpE4hamB52Eg6DLhJoXeQ1plSzekh5Ujir1xdREdwdsZPPXKczkrWqBBR0KyywJZHN/o/hj0w8j7scSGg==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.0.7" + } + }, + "@ethersproject/hash": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.0.9.tgz", + "integrity": "sha512-e8/i2ZDeGSgCxXT0vocL54+pMbw5oX5fNjb2E3bAIvdkh5kH29M7zz1jHu1QDZnptIuvCZepIbhUH8lxKE2/SQ==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.0.6", + "@ethersproject/address": "^5.0.5", + "@ethersproject/bignumber": "^5.0.8", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/keccak256": "^5.0.3", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.4", + "@ethersproject/strings": "^5.0.4" + } + }, + "@ethersproject/keccak256": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.0.6.tgz", + "integrity": "sha512-eJ4Id/i2rwrf5JXEA7a12bG1phuxjj47mPZgDUbttuNBodhSuZF2nEO5QdpaRjmlphQ8Kt9PNqY/z7lhtJptZg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.0.4", + "js-sha3": "0.5.7" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", + "dev": true + } + } + }, + "@ethersproject/logger": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.0.8.tgz", + "integrity": "sha512-SkJCTaVTnaZ3/ieLF5pVftxGEFX56pTH+f2Slrpv7cU0TNpUZNib84QQdukd++sWUp/S7j5t5NW+WegbXd4U/A==", + "dev": true + }, + "@ethersproject/networks": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.0.6.tgz", + "integrity": "sha512-2Cg1N5109zzFOBfkyuPj+FfF7ioqAsRffmybJ2lrsiB5skphIAE72XNSCs4fqktlf+rwSh/5o/UXRjXxvSktZw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.0.5" + } + }, + "@ethersproject/properties": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.0.6.tgz", + "integrity": "sha512-a9DUMizYhJ0TbtuDkO9iYlb2CDlpSKqGPDr+amvlZhRspQ6jbl5Eq8jfu4SCcGlcfaTbguJmqGnyOGn1EFt6xA==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.0.5" + } + }, + "@ethersproject/rlp": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.0.6.tgz", + "integrity": "sha512-M223MTaydfmQSsvqAl0FJZDYFlSqt6cgbhnssLDwqCKYegAHE16vrFyo+eiOapYlt32XAIJm0BXlqSunULzZuQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5" + } + }, + "@ethersproject/signing-key": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.7.tgz", + "integrity": "sha512-JYndnhFPKH0daPcIjyhi+GMcw3srIHkQ40hGRe6DA0CdGrpMfgyfSYDQ2D8HL2lgR+Xm4SHfEB0qba6+sCyrvg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3", + "elliptic": "6.5.3" + } + }, + "@ethersproject/strings": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.0.7.tgz", + "integrity": "sha512-a+6T80LvmXGMOOWQTZHtGGQEg1z4v8rm8oX70KNs55YtPXI/5J3LBbVf5pyqCKSlmiBw5IaepPvs5XGalRUSZQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/constants": "^5.0.4", + "@ethersproject/logger": "^5.0.5" + } + }, + "@ethersproject/transactions": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.0.8.tgz", + "integrity": "sha512-i7NtOXVzUe+YSU6QufzlRrI2WzHaTmULAKHJv4duIZMLqzehCBXGA9lTpFgFdqGYcQJ7vOtNFC2BB2mSjmuXqg==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.0.4", + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/constants": "^5.0.4", + "@ethersproject/keccak256": "^5.0.3", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3", + "@ethersproject/rlp": "^5.0.3", + "@ethersproject/signing-key": "^5.0.4" + } + }, + "@ethersproject/web": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.0.11.tgz", + "integrity": "sha512-x03ihbPoN1S8Gsh9WSwxkYxUIumLi02ZEKJku1C43sxBfe+mdprWyvujzYlpuoRNfWRgNhdRDKMP8JbG6MwNGA==", + "dev": true, + "requires": { + "@ethersproject/base64": "^5.0.3", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3", + "@ethersproject/strings": "^5.0.4" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "12.19.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.8.tgz", + "integrity": "sha512-D4k2kNi0URNBxIRCb1khTnkWNHv8KSL1owPmS/K5e5t8B2GzMReY7AsJIY1BnP5KdlgC4rj9jk2IkDMasIE7xg==", + "dev": true + }, + "@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/secp256k1": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz", + "integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", + "dev": true + }, + "blakejs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", + "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", + "dev": true + } + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "bn.js": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "dev": true, + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "bufferutil": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.2.tgz", + "integrity": "sha512-AtnG3W6M8B2n4xDQ5R+70EXvOpnXsFYg/AK2yTZd+HQ/oxAdz+GI+DvjmhBw3L0ole+LJ0ngqY4JMbDzkfNzhA==", + "dev": true, + "requires": { + "node-gyp-build": "^4.2.0" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "dependencies": { + "multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + } + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "dev": true + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "requires": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha1-IprEbsqG1S4MmR58sq74P/D2i88=", + "dev": true, + "requires": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", + "dev": true + } + } + }, + "eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ethereum-bloom-filters": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz", + "integrity": "sha512-cDcJJSJ9GMAcURiAWO3DxIEhTL/uWqlQnvgKpuYQzYPrt/izuGU+1ntQmHt0IRq6ADoSYHFnB+aCEFIldjhkMQ==", + "dev": true, + "requires": { + "js-sha3": "^0.8.0" + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-common": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz", + "integrity": "sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA==", + "dev": true + }, + "ethereumjs-tx": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz", + "integrity": "sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==", + "dev": true, + "requires": { + "ethereumjs-common": "^1.5.0", + "ethereumjs-util": "^6.0.0" + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", + "dev": true + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "requires": { + "punycode": "2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", + "dev": true + } + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=", + "dev": true + }, + "is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "keccak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", + "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", + "dev": true, + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=", + "dev": true, + "requires": { + "mkdirp": "*" + } + }, + "mock-fs": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.13.0.tgz", + "integrity": "sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "dev": true, + "requires": { + "varint": "^5.0.0" + } + }, + "multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, + "nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", + "dev": true + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha1-VVQoTFQ6ImbXo48X4HOCH73jk80=", + "dev": true, + "requires": { + "http-https": "^1.0.0" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-headers": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", + "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==", + "dev": true + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + } + } + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rlp": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.6.tgz", + "integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==", + "dev": true, + "requires": { + "bn.js": "^4.11.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "secp256k1": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", + "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", + "dev": true, + "requires": { + "elliptic": "^6.5.2", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "requires": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", + "dev": true, + "requires": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "swarm-js": { + "version": "0.1.40", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.40.tgz", + "integrity": "sha512-yqiOCEoA4/IShXkY3WKwP5PvZhmoOOD8clsKA7EEcRILMkTEYHCQ21HDCAcVpmIxZq4LyZvWeRJ6quIyHk1caA==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^7.1.0", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + } + } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + } + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=", + "dev": true + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, + "utf-8-validate": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.3.tgz", + "integrity": "sha512-jtJM6fpGv8C1SoH4PtG22pGto6x+Y8uPprW0tw3//gGFhDDTiuksgradgFN6yRayDP4SyZZa6ZMGHLIa17+M8A==", + "dev": true, + "requires": { + "node-gyp-build": "^4.2.0" + } + }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "web3": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.3.0.tgz", + "integrity": "sha512-4q9dna0RecnrlgD/bD1C5S+81Untbd6Z/TBD7rb+D5Bvvc0Wxjr4OP70x+LlnwuRDjDtzBwJbNUblh2grlVArw==", + "dev": true, + "requires": { + "web3-bzz": "1.3.0", + "web3-core": "1.3.0", + "web3-eth": "1.3.0", + "web3-eth-personal": "1.3.0", + "web3-net": "1.3.0", + "web3-shh": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-bzz": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.3.0.tgz", + "integrity": "sha512-ibYAnKab+sgTo/UdfbrvYfWblXjjgSMgyy9/FHa6WXS14n/HVB+HfWqGz2EM3fok8Wy5XoKGMvdqvERQ/mzq1w==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "got": "9.6.0", + "swarm-js": "^0.1.40", + "underscore": "1.9.1" + } + }, + "web3-core": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.3.0.tgz", + "integrity": "sha512-BwWvAaKJf4KFG9QsKRi3MNoNgzjI6szyUlgme1qNPxUdCkaS3Rdpa0VKYNHP7M/YTk82/59kNE66mH5vmoaXjA==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.5", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-requestmanager": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-core-helpers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.3.0.tgz", + "integrity": "sha512-+MFb1kZCrRctf7UYE7NCG4rGhSXaQJ/KF07di9GVK1pxy1K0+rFi61ZobuV1ky9uQp+uhhSPts4Zp55kRDB5sw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-eth-iban": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-core-method": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.3.0.tgz", + "integrity": "sha512-h0yFDrYVzy5WkLxC/C3q+hiMnzxdWm9p1T1rslnuHgOp6nYfqzu/6mUIXrsS4h/OWiGJt+BZ0xVZmtC31HDWtg==", + "dev": true, + "requires": { + "@ethersproject/transactions": "^5.0.0-beta.135", + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0", + "web3-core-promievent": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-core-promievent": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.3.0.tgz", + "integrity": "sha512-blv69wrXw447TP3iPvYJpllkhW6B18nfuEbrfcr3n2Y0v1Jx8VJacNZFDFsFIcgXcgUIVCtOpimU7w9v4+rtaw==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4" + } + }, + "web3-core-requestmanager": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.3.0.tgz", + "integrity": "sha512-3yMbuGcomtzlmvTVqNRydxsx7oPlw3ioRL6ReF9PeNYDkUsZaUib+6Dp5eBt7UXh5X+SIn/xa1smhDHz5/HpAw==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0", + "web3-providers-http": "1.3.0", + "web3-providers-ipc": "1.3.0", + "web3-providers-ws": "1.3.0" + } + }, + "web3-core-subscriptions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.3.0.tgz", + "integrity": "sha512-MUUQUAhJDb+Nz3S97ExVWveH4utoUnsbPWP+q1HJH437hEGb4vunIb9KvN3hFHLB+aHJfPeStM/4yYTz5PeuyQ==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0" + } + }, + "web3-eth": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.3.0.tgz", + "integrity": "sha512-/bzJcxXPM9EM18JM5kO2JjZ3nEqVo3HxqU93aWAEgJNqaP/Lltmufl2GpvIB2Hvj+FXAjAXquxUdQ2/xP7BzHQ==", + "dev": true, + "requires": { + "underscore": "1.9.1", + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-eth-abi": "1.3.0", + "web3-eth-accounts": "1.3.0", + "web3-eth-contract": "1.3.0", + "web3-eth-ens": "1.3.0", + "web3-eth-iban": "1.3.0", + "web3-eth-personal": "1.3.0", + "web3-net": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-eth-abi": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.3.0.tgz", + "integrity": "sha512-1OrZ9+KGrBeBRd3lO8upkpNua9+7cBsQAgor9wbA25UrcUYSyL8teV66JNRu9gFxaTbkpdrGqM7J/LXpraXWrg==", + "dev": true, + "requires": { + "@ethersproject/abi": "5.0.0-beta.153", + "underscore": "1.9.1", + "web3-utils": "1.3.0" + } + }, + "web3-eth-accounts": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.3.0.tgz", + "integrity": "sha512-/Q7EVW4L2wWUbNRtOTwAIrYvJid/5UnKMw67x/JpvRMwYC+e+744P536Ja6SG4X3MnzFvd3E/jruV4qa6k+zIw==", + "dev": true, + "requires": { + "crypto-browserify": "3.12.0", + "eth-lib": "0.2.8", + "ethereumjs-common": "^1.3.2", + "ethereumjs-tx": "^2.1.1", + "scrypt-js": "^3.0.1", + "underscore": "1.9.1", + "uuid": "3.3.2", + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-utils": "1.3.0" + }, + "dependencies": { + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "web3-eth-contract": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.3.0.tgz", + "integrity": "sha512-3SCge4SRNCnzLxf0R+sXk6vyTOl05g80Z5+9/B5pERwtPpPWaQGw8w01vqYqsYBKC7zH+dxhMaUgVzU2Dgf7bQ==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.5", + "underscore": "1.9.1", + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-promievent": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-eth-abi": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-eth-ens": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.3.0.tgz", + "integrity": "sha512-WnOru+EcuM5dteiVYJcHXo/I7Wq+ei8RrlS2nir49M0QpYvUPGbCGgTbifcjJQTWamgORtWdljSA1s2Asdb74w==", + "dev": true, + "requires": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "underscore": "1.9.1", + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-promievent": "1.3.0", + "web3-eth-abi": "1.3.0", + "web3-eth-contract": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-eth-iban": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.3.0.tgz", + "integrity": "sha512-v9mZWhR4fPF17/KhHLiWir4YHWLe09O3B/NTdhWqw3fdAMJNztzMHGzgHxA/4fU+rhrs/FhDzc4yt32zMEXBZw==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "web3-utils": "1.3.0" + } + }, + "web3-eth-personal": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.3.0.tgz", + "integrity": "sha512-2czUhElsJdLpuNfun9GeLiClo5O6Xw+bLSjl3f4bNG5X2V4wcIjX2ygep/nfstLLtkz8jSkgl/bV7esANJyeRA==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "web3-core": "1.3.0", + "web3-core-helpers": "1.3.0", + "web3-core-method": "1.3.0", + "web3-net": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-net": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.3.0.tgz", + "integrity": "sha512-Xz02KylOyrB2YZzCkysEDrY7RbKxb7LADzx3Zlovfvuby7HBwtXVexXKtoGqksa+ns1lvjQLLQGb+OeLi7Sr7w==", + "dev": true, + "requires": { + "web3-core": "1.3.0", + "web3-core-method": "1.3.0", + "web3-utils": "1.3.0" + } + }, + "web3-providers-http": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.3.0.tgz", + "integrity": "sha512-cMKhUI6PqlY/EC+ZDacAxajySBu8AzW8jOjt1Pe/mbRQgS0rcZyvLePGTTuoyaA8C21F8UW+EE5jj7YsNgOuqA==", + "dev": true, + "requires": { + "web3-core-helpers": "1.3.0", + "xhr2-cookies": "1.1.0" + } + }, + "web3-providers-ipc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.3.0.tgz", + "integrity": "sha512-0CrLuRofR+1J38nEj4WsId/oolwQEM6Yl1sOt41S/6bNI7htdkwgVhSloFIMJMDFHtRw229QIJ6wIaKQz0X1Og==", + "dev": true, + "requires": { + "oboe": "2.1.5", + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0" + } + }, + "web3-providers-ws": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.3.0.tgz", + "integrity": "sha512-Im5MthhJnJst8nSoq0TgbyOdaiFQFa5r6sHPOVllhgIgViDqzbnlAFW9sNzQ0Q8VXPNfPIQKi9cOrHlSRNPjRw==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "underscore": "1.9.1", + "web3-core-helpers": "1.3.0", + "websocket": "^1.0.32" + } + }, + "web3-shh": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.3.0.tgz", + "integrity": "sha512-IZTojA4VCwVq+7eEIHuL1tJXtU+LJDhO8Y2QmuwetEWW1iBgWCGPHZasipWP+7kDpSm/5lo5GRxL72FF/Os/tA==", + "dev": true, + "requires": { + "web3-core": "1.3.0", + "web3-core-method": "1.3.0", + "web3-core-subscriptions": "1.3.0", + "web3-net": "1.3.0" + } + }, + "web3-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.3.0.tgz", + "integrity": "sha512-2mS5axFCbkhicmoDRuJeuo0TVGQDgC2sPi/5dblfVC+PMtX0efrb8Xlttv/eGkq7X4E83Pds34FH98TP2WOUZA==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "eth-lib": "0.2.8", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + }, + "dependencies": { + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + } + } + }, + "websocket": { + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.33.tgz", + "integrity": "sha512-XwNqM2rN5eh3G2CUQE3OHZj+0xfdH42+OFK6LdC2yqiC0YU8e5UK0nYre220T0IyyN031V/XOvtHvXozvJYFWA==", + "dev": true, + "requires": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "requires": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "requires": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "requires": { + "xhr-request": "^1.1.0" + } + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "dev": true, + "requires": { + "cookiejar": "^2.1.1" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } +} diff --git a/webprotege-attestation-lib/scripts/package.json b/webprotege-attestation-lib/scripts/package.json new file mode 100644 index 0000000000..17e47590d7 --- /dev/null +++ b/webprotege-attestation-lib/scripts/package.json @@ -0,0 +1,12 @@ +{ + "name": "webprotege-attestation", + "version": "1.0.0", + "description": "development scripts", + "scripts": { + "deploy": "npx ./deploy-contracts.js" + }, + "devDependencies": { + "dotenv": "^8.2.0", + "web3": "^1.3.0" + } +} diff --git a/webprotege-attestation-lib/scripts/test.js b/webprotege-attestation-lib/scripts/test.js new file mode 100644 index 0000000000..b879a940fc --- /dev/null +++ b/webprotege-attestation-lib/scripts/test.js @@ -0,0 +1,28 @@ +const Web3 = require('web3'); +const fs = require('fs'); +require('dotenv').config({ path: `.env` }); + +const buildPath = `${__dirname}/../build/`; +const contract_address = '0x41c293160913d7cD816093D702e2dDA7391A3976'; + +function load(contractName) { + const abi = fs.readFileSync(`${buildPath}${contractName}.abi`, 'UTF-8'); + const bin = fs.readFileSync(`${buildPath}${contractName}.bin`, 'UTF-8'); + return { abi: JSON.parse(abi), bin: bin }; +} + +const abi = load('ChangeTracking').abi; +const provider = `${process.env.PROVIDER_HOST}:${process.env.PROVIDER_PORT}`; +console.log(`Using web3 provider: ${provider}`); + +const web3 = new Web3(provider); +const account = web3.eth.accounts.privateKeyToAccount(process.env.SERVER_SECRET); +console.log(`Using web3 account: ${account.address}`); +console.log(`Using contract address: ${contract_address}`); + +const contract = new web3.eth.Contract(abi, contract_address, { + from: account.address +}); +contract.methods.attest("1", "2", "t", "3", []).send(); +contract.methods.verify("1", "2", "3").call(); +contract.methods.verifyEntity("1", "2", "3").call(); \ No newline at end of file diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ClientAttestationService.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ClientAttestationService.java new file mode 100644 index 0000000000..dbf1442f96 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ClientAttestationService.java @@ -0,0 +1,264 @@ +package ch.unifr.digits.webprotege.attestation.client; + + +import ch.unifr.digits.webprotege.attestation.client.contract.ChangeTrackingContract; +import ch.unifr.digits.webprotege.attestation.client.contract.OntologyAttestationContract; +import ch.unifr.digits.webprotege.attestation.client.contract.VerifyContractReturn; +import ch.unifr.digits.webprotege.attestation.client.ethereum.Connection; +import ch.unifr.digits.webprotege.attestation.client.ethereum.EthereumProvider; +import ch.unifr.digits.webprotege.attestation.client.web3.Web3; +import ch.unifr.digits.webprotege.attestation.client.web3.core.TransactionReceipt; +import ch.unifr.digits.webprotege.attestation.shared.VerifyResult; +import com.google.gwt.core.client.Callback; +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JsonUtils; +import com.google.gwt.http.client.*; +import edu.stanford.bmir.protege.web.shared.download.DownloadFormatExtension; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; +import edu.stanford.bmir.protege.web.shared.revision.RevisionNumber; +import elemental2.promise.Promise; +import org.semanticweb.owlapi.model.OWLEntity; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +public class ClientAttestationService { + + private static final String CONTRACT_ONTOLOGY_NAME = "OntologyAttestation"; + + public static void signProjectFile(ProjectId projectId, RevisionNumber revisionNumber, String ontologyIRI, + String versionIRI, String name, String address, Callback callback) { + DownloadFormatExtension extension = DownloadFormatExtension.owl; + ProjectDeflateDownloader downloader = new ProjectDeflateDownloader(projectId, revisionNumber, extension); + + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + Promise hashPromise = downloader.download().then(ontology -> { + byte[] bytes = digest.digest(ontology.getBytes()); + String hash = bytesToHex(bytes); + GWT.log("[attestation] Ontology hash: " + hash); + return Promise.resolve(hash); + }); + + hashPromise.then((hash) -> { + signOntology(ontologyIRI, versionIRI, name, address, hash, callback); + return null; + }); + } + + public static void verifyProjectFile(ProjectId projectId, RevisionNumber revisionNumber, String ontologyIRI, + String versionIRI, String address, Callback callback) { + DownloadFormatExtension extension = DownloadFormatExtension.owl; + ProjectDeflateDownloader downloader = new ProjectDeflateDownloader(projectId, revisionNumber, extension); + + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + Promise hashPromise = downloader.download().then(ontology -> { + byte[] bytes = digest.digest(ontology.getBytes()); + String hash = bytesToHex(bytes); + GWT.log("[attestation] Ontology hash: " + hash); + return Promise.resolve(hash); + }); + + hashPromise.then((hash) -> { + verifyOntology(ontologyIRI, versionIRI, address, hash, callback); + return null; + }); + } + + public static void signOntology(String ontologyIRI, String versionIRI, String name, String address, String hash, + Callback callback) { + Promise connectionPromise = connectToChain(); + Promise interfacePromise = getContractInterface(CONTRACT_ONTOLOGY_NAME); + Promise.all(connectionPromise, interfacePromise).then((args) -> { + Connection connection = (Connection) args[0]; + Object contractInterface = args[1]; + + OntologyAttestationContract contract = new OntologyAttestationContract(connection.getWeb3(), contractInterface, address); + Promise attestPromise = contract.attest(connection.getProvider().selectedAddress, + ontologyIRI, versionIRI, name, hash); + attestPromise.then(receipt -> { + GWT.log("[attestation] transaction result: " + receipt.status); + callback.onSuccess(receipt.status); + return null; + }).catch_(error -> { + callback.onFailure(error); + return null; + }); + + return null; + }); + } + + public static void verifyOntology(String ontologyIRI, String versionIRI, String address, String hash, + Callback callback) { + + Promise connectionPromise = connectToChain(); + Promise interfacePromise = getContractInterface(CONTRACT_ONTOLOGY_NAME); + + Promise.all(connectionPromise, interfacePromise).then((args) -> { + Connection connection = (Connection) args[0]; + Object contractInterface = args[1]; + + OntologyAttestationContract contract = new OntologyAttestationContract(connection.getWeb3(), contractInterface, address); + Promise resultPromise = contract.verify(connection.getProvider().selectedAddress, + ontologyIRI, versionIRI, hash); + resultPromise.then(contractReturn -> { + VerifyResult result = new VerifyResult(contractReturn.valid, contractReturn.signer, + contractReturn.signerName, contractReturn.timestamp); + GWT.log("[attestation] verify result: " + result.toString()); + callback.onSuccess(result); + return null; + }).catch_(error -> { + callback.onFailure(error); + return null; + }); + return null; + }); + + } + + public static void signChangeTracking(String ontologyIRI, String versionIRI, String name, String address, String hash, + List classHashes, Callback callback) { + Promise connectionPromise = connectToChain(); + Promise interfacePromise = getContractInterface(CONTRACT_ONTOLOGY_NAME); + Promise.all(connectionPromise, interfacePromise).then((args) -> { + Connection connection = (Connection) args[0]; + Object contractInterface = args[1]; + + ChangeTrackingContract contract = new ChangeTrackingContract(connection.getWeb3(), contractInterface, address); + Promise attestPromise = contract.attest(connection.getProvider().selectedAddress, + ontologyIRI, versionIRI, name, hash, classHashes); + attestPromise.then(receipt -> { + GWT.log("[attestation] transaction result: " + receipt.status); + callback.onSuccess(receipt.status); + return null; + }).catch_(error -> { + callback.onFailure(error); + return null; + }); + + return null; + }); + } + + public static void verifyChangeTracking(String ontologyIRI, String versionIRI, String address, String hash, + Callback callback) { + + Promise connectionPromise = connectToChain(); + Promise interfacePromise = getContractInterface(CONTRACT_ONTOLOGY_NAME); + + Promise.all(connectionPromise, interfacePromise).then((args) -> { + Connection connection = (Connection) args[0]; + Object contractInterface = args[1]; + + ChangeTrackingContract contract = new ChangeTrackingContract(connection.getWeb3(), contractInterface, address); + Promise resultPromise = contract.verify(connection.getProvider().selectedAddress, + ontologyIRI, versionIRI, hash); + resultPromise.then(contractReturn -> { + VerifyResult result = new VerifyResult(contractReturn.valid, contractReturn.signer, + contractReturn.signerName, contractReturn.timestamp); + GWT.log("[attestation] verify result: " + result.toString()); + callback.onSuccess(result); + return null; + }).catch_(error -> { + callback.onFailure(error); + return null; + }); + return null; + }); + + } + + public static String hashData(byte[] data) { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + byte[] hashBytes = digest.digest(data); + return bytesToHex(hashBytes); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + public static int hashEntity(OWLEntity entity) { + return entity.hashCode(); + } + + private static String bytesToHex(byte[] hash) { + StringBuffer hexString = new StringBuffer(); + for (int i = 0; i < hash.length; i++) { + String hex = Integer.toHexString(0xff & hash[i]); + if(hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } + + private static Promise connectToChain() { + Promise promise = new Promise<>((resolve, reject) -> { + EthereumProvider.detectEthereumProvider().then(p -> { + Web3 web3 = new Web3(p); + + web3.eth.requestAccounts().then(accounts -> { + GWT.log("[attestation] connected to chain."); + Connection connection = new Connection(p, web3); + resolve.onInvoke(connection); + return null; + }).catch_(error -> { + reject.onInvoke(error); + return null; + }); + return null; + }).catch_(error -> { + reject.onInvoke(error); + return null; + }); + }); + return promise; + } + + private static Promise getContractInterface(String contractName) { + String url = GWT.getModuleBaseForStaticFiles() + "attestation/interfaces/"+contractName+".json"; + RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url); + requestBuilder.setHeader("Accept", "application/json"); + requestBuilder.setRequestData(null); + + Promise promise = new Promise<>((resolve, reject) -> { + requestBuilder.setCallback(new RequestCallback() { + @Override + public void onResponseReceived(Request request, Response response) { + String json = response.getText(); + Object object = JsonUtils.unsafeEval(json); + GWT.log("[attestation] retrieved contract interface."); + resolve.onInvoke(object); + } + + @Override + public void onError(Request request, Throwable exception) { + reject.onInvoke(exception); + } + }); + try { + requestBuilder.send(); + } catch (RequestException e) { + reject.onInvoke(e); + } + }); + + return promise; + } + + +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ProjectDeflateDownloader.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ProjectDeflateDownloader.java new file mode 100644 index 0000000000..48ea8f7f1b --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ProjectDeflateDownloader.java @@ -0,0 +1,72 @@ +package ch.unifr.digits.webprotege.attestation.client; + +import ch.unifr.digits.webprotege.attestation.client.jszip.JSZip; +import ch.unifr.digits.webprotege.attestation.client.jszip.ZipObject; +import com.google.gwt.core.client.GWT; +import com.google.gwt.http.client.URL; +import com.google.gwt.regexp.shared.RegExp; +import com.google.gwt.typedarrays.shared.ArrayBuffer; +import com.google.gwt.xhr.client.XMLHttpRequest; +import edu.stanford.bmir.protege.web.shared.download.DownloadFormatExtension; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; +import edu.stanford.bmir.protege.web.shared.revision.RevisionNumber; +import elemental2.promise.Promise; + +import static edu.stanford.bmir.protege.web.shared.download.ProjectDownloadConstants.*; + +public class ProjectDeflateDownloader { + + private final ProjectId projectId; + private final RevisionNumber revisionNumber; + private final DownloadFormatExtension downloadFormatExtension; + + public ProjectDeflateDownloader(ProjectId projectId, RevisionNumber revisionNumber, DownloadFormatExtension downloadFormatExtension) { + this.projectId = projectId; + this.revisionNumber = revisionNumber; + this.downloadFormatExtension = downloadFormatExtension; + } + + public Promise download() { + String encodedProjectName = URL.encode(projectId.getId()); + String url = GWT.getHostPageBaseURL() + "download?" + + PROJECT + "=" + encodedProjectName + + "&" + REVISION + "=" + revisionNumber.getValue() + + "&" + FORMAT + "=" + downloadFormatExtension.getExtension(); + + final RegExp regex = RegExp.compile(".*" + downloadFormatExtension.getExtension()); + XMLHttpRequest request = XMLHttpRequest.create(); + request.setResponseType(XMLHttpRequest.ResponseType.ArrayBuffer); + + Promise promise = new Promise<>((resolve, reject) -> { + + request.setOnReadyStateChange(xhr -> { + if (xhr.getReadyState() != 4) return; + if (xhr.getStatus() >= 300) { + reject.onInvoke(xhr.getStatusText()); + return; + } + ArrayBuffer buffer = xhr.getResponseArrayBuffer(); + JSZip.loadAsync(buffer).then(jszip -> { + ZipObject[] files = jszip.file(regex); + ZipObject zip = files[0]; + zip.async("text", null).then(res -> { + resolve.onInvoke(res.toString()); + return null; + }).catch_(error -> { + reject.onInvoke(error); + return null; + }); + return null; + }).catch_(error -> { + reject.onInvoke(error); + return null; + }); + }); + }); + + request.open("GET", url); + request.send(); + return promise; + } + +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/ChangeTrackingContract.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/ChangeTrackingContract.java new file mode 100644 index 0000000000..e5d95588a9 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/ChangeTrackingContract.java @@ -0,0 +1,28 @@ +package ch.unifr.digits.webprotege.attestation.client.contract; + + +import ch.unifr.digits.webprotege.attestation.client.web3.Web3; +import ch.unifr.digits.webprotege.attestation.client.web3.core.TransactionReceipt; +import elemental2.promise.Promise; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +import java.util.List; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class ChangeTrackingContract { + + public ChangeTrackingContract(Web3 web3, Object jsonInterface, String address) {} + + @JsMethod + public native Promise verifyEntity(String from, String id, int entityHash); + + @JsMethod + public native Promise verify(String from, String ontologyIri, String versionIri, String hash); + + @JsMethod + public native Promise attest(String from, String ontologyIri, String versionIri, String name, + String hash, List classHashes); + +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/OntologyAttestationContract.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/OntologyAttestationContract.java new file mode 100644 index 0000000000..cc2d611204 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/OntologyAttestationContract.java @@ -0,0 +1,23 @@ +package ch.unifr.digits.webprotege.attestation.client.contract; + + +import ch.unifr.digits.webprotege.attestation.client.web3.Web3; +import ch.unifr.digits.webprotege.attestation.client.web3.core.TransactionReceipt; +import elemental2.promise.Promise; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class OntologyAttestationContract { + + public OntologyAttestationContract(Web3 web3, Object jsonInterface, String address) {} + + @JsMethod + public native Promise verify(String from, String ontologyIri, String versionIri, String hash); + + @JsMethod + public native Promise attest(String from, String ontologyIri, String versionIri, String name, + String hash); + +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/VerifyContractReturn.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/VerifyContractReturn.java new file mode 100644 index 0000000000..5429d2d939 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/contract/VerifyContractReturn.java @@ -0,0 +1,12 @@ +package ch.unifr.digits.webprotege.attestation.client.contract; + +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class VerifyContractReturn { + public boolean valid; + public String signer; + public String signerName; + public int timestamp; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ethereum/Connection.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ethereum/Connection.java new file mode 100644 index 0000000000..164eb58fae --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ethereum/Connection.java @@ -0,0 +1,22 @@ +package ch.unifr.digits.webprotege.attestation.client.ethereum; + + +import ch.unifr.digits.webprotege.attestation.client.web3.Web3; + +public class Connection { + private EthereumProvider provider; + private Web3 web3; + + public Connection(EthereumProvider provider, Web3 web3) { + this.provider = provider; + this.web3 = web3; + } + + public EthereumProvider getProvider() { + return provider; + } + + public Web3 getWeb3() { + return web3; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ethereum/EthereumProvider.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ethereum/EthereumProvider.java new file mode 100644 index 0000000000..3e7a9b9676 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/ethereum/EthereumProvider.java @@ -0,0 +1,17 @@ +package ch.unifr.digits.webprotege.attestation.client.ethereum; + +import ch.unifr.digits.webprotege.attestation.client.web3.core.Provider; +import elemental2.promise.Promise; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class EthereumProvider extends Provider { + @JsProperty + public String selectedAddress; + + @JsMethod(namespace = JsPackage.GLOBAL) + public static native Promise detectEthereumProvider(); +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/JSZip.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/JSZip.java new file mode 100644 index 0000000000..88ae4fb06a --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/JSZip.java @@ -0,0 +1,19 @@ +package ch.unifr.digits.webprotege.attestation.client.jszip; + +import com.google.gwt.regexp.shared.RegExp; +import elemental2.promise.Promise; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class JSZip { + + @JsProperty + public static Support support; + @JsMethod + public static native Promise loadAsync(Object data); + @JsMethod + public native ZipObject[] file(RegExp regex); +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/Support.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/Support.java new file mode 100644 index 0000000000..a94e1936ab --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/Support.java @@ -0,0 +1,26 @@ +package ch.unifr.digits.webprotege.attestation.client.jszip; + +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class Support { + @JsProperty + public boolean arraybuffer; + @JsProperty + public boolean uint8array; + @JsProperty + public boolean blob; + @JsProperty + public boolean nodebuffer; + @JsProperty + public boolean nodestream; + @JsProperty + public boolean base64; + @JsProperty + public boolean array; + @JsProperty + public boolean string; + +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/ZipObject.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/ZipObject.java new file mode 100644 index 0000000000..33259aeb7c --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/jszip/ZipObject.java @@ -0,0 +1,41 @@ +package ch.unifr.digits.webprotege.attestation.client.jszip; + +import com.google.gwt.core.client.JsDate; +import elemental2.promise.Promise; +import jsinterop.annotations.*; + +import javax.annotation.Nullable; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class ZipObject { + @JsProperty + public String name; + @JsProperty + public boolean dir; + @JsProperty + public JsDate date; + @JsProperty + public String comment; + @JsProperty + public short unixPermissions; + @JsProperty + public short dosPermissions; + @JsProperty + public Object options; + + @JsMethod + public native Promise async(String type, @Nullable OnUpdateCallback callback); + + @FunctionalInterface + @JsFunction + public interface OnUpdateCallback { + + void update(Metadata metadata); + + @JsType(isNative = true, namespace = JsPackage.GLOBAL) + class Metadata { + @JsProperty + public double percent; + } + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/module/AttestationModule.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/module/AttestationModule.java new file mode 100644 index 0000000000..2187cff7b2 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/module/AttestationModule.java @@ -0,0 +1,19 @@ +package ch.unifr.digits.webprotege.attestation.client.module; + +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.core.client.GWT; + +public class AttestationModule implements EntryPoint { + + /** + * The entry point method, called automatically by loading a module that + * declares an implementing class as an entry point. + */ + @Override + public void onModuleLoad() { + ScriptLoader loader = GWT.create(ScriptLoader.class); + loader.load("detect-provider.min.js"); + loader.load("jszip.min.js"); + loader.load("contracts.js"); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/module/ScriptLoader.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/module/ScriptLoader.java new file mode 100644 index 0000000000..291ff55e17 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/module/ScriptLoader.java @@ -0,0 +1,31 @@ +package ch.unifr.digits.webprotege.attestation.client.module; + +import com.google.gwt.core.client.Callback; +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.ScriptInjector; + +public class ScriptLoader { + + public void load(String script) {} + + public static class InjectingLoader extends ScriptLoader { + @Override + public void load(String script) { + ScriptInjector + .fromUrl(GWT.getModuleBaseForStaticFiles() + "attestation/" + script) + .setCallback( + new Callback() { + public void onFailure(Exception reason) { + GWT.log("[attestation] Could not load script " + script); + } + public void onSuccess(Void result) { + GWT.log("[attestation] Script " + script + " loaded successfully."); + } + }) + .setWindow(ScriptInjector.TOP_WINDOW) + .setRemoveTag(false) + .inject(); + } + } + +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/Web3.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/Web3.java new file mode 100644 index 0000000000..0e6b14dd7a --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/Web3.java @@ -0,0 +1,24 @@ +package ch.unifr.digits.webprotege.attestation.client.web3; + +import ch.unifr.digits.webprotege.attestation.client.web3.core.Provider; +import ch.unifr.digits.webprotege.attestation.client.web3.eth.Eth; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class Web3 { + + @JsProperty + public Eth eth; + @JsProperty + public Provider currentProvider; + + public Web3() {} + public Web3(String url) {} + public Web3(Provider provider) {} + + @JsMethod + public native boolean setProvider(String url); +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/Common.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/Common.java new file mode 100644 index 0000000000..d4f3f56ca6 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/Common.java @@ -0,0 +1,14 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.core; + +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true) +public class Common { + @JsProperty + public CustomChainParams customChain; + @JsProperty + public String baseChain; + @JsProperty + public String hardfork; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/CustomChainParams.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/CustomChainParams.java new file mode 100644 index 0000000000..dd28833429 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/CustomChainParams.java @@ -0,0 +1,15 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.core; + + +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true) +public class CustomChainParams { + @JsProperty + public String name; + @JsProperty + public int networkId; + @JsProperty + public int chainId; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/Provider.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/Provider.java new file mode 100644 index 0000000000..957d64631a --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/Provider.java @@ -0,0 +1,8 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.core; + +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "object") +public class Provider { +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/TransactionConfig.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/TransactionConfig.java new file mode 100644 index 0000000000..92913bbd75 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/TransactionConfig.java @@ -0,0 +1,30 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.core; + +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true) +public class TransactionConfig { + @JsProperty + public String from; + @JsProperty + public String to; + @JsProperty + public String value; + @JsProperty + public String gas; + @JsProperty + public String gasPrice; + @JsProperty + public String data; + @JsProperty + public int nonce; + @JsProperty + public int chainId; + @JsProperty + public Common common; + @JsProperty + public String chain; + @JsProperty + public String hardfork; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/TransactionReceipt.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/TransactionReceipt.java new file mode 100644 index 0000000000..0e5de9ee00 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/core/TransactionReceipt.java @@ -0,0 +1,28 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.core; + +import jsinterop.annotations.JsProperty; +import jsinterop.annotations.JsType; + +@JsType(isNative = true) +public class TransactionReceipt { + @JsProperty + public boolean status; + @JsProperty + public String transactionHash; + @JsProperty + public int transactionIndex; + @JsProperty + public String blockHash; + @JsProperty + public int blockNumber; + @JsProperty + public String from; + @JsProperty + public String to; + @JsProperty + public String contractAddress; + @JsProperty + public int cumulativeGasUsed; + @JsProperty + public int gasUsed; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/Eth.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/Eth.java new file mode 100644 index 0000000000..bd6f8f910e --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/Eth.java @@ -0,0 +1,26 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.eth; + + +import ch.unifr.digits.webprotege.attestation.client.web3.eth.contract.Contract; +import com.google.gwt.core.client.JsArrayString; +import elemental2.promise.Promise; +import jsinterop.annotations.JsMethod; +import jsinterop.annotations.JsPackage; +import jsinterop.annotations.JsType; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL) +public class Eth { + + @JsMethod(name = "Contract") + public native Contract newContract(Object jsonInterface, String address); + + @JsMethod + public native Promise getAccounts(); + + @JsMethod + public native Promise requestAccounts(); + + @JsMethod + public native Promise getBalance(String address); + +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/Contract.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/Contract.java new file mode 100644 index 0000000000..bca7f7c305 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/Contract.java @@ -0,0 +1,54 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.eth.contract; + +import ch.unifr.digits.webprotege.attestation.client.web3.core.Common; +import ch.unifr.digits.webprotege.attestation.client.web3.core.Provider; +import elemental2.promise.Promise; +import jsinterop.annotations.*; + +@JsType(isNative = true, namespace = "web3.eth.Contract") +public class Contract { + @JsProperty + public String defaultAccount; + @JsProperty + public String defaultBlock; + @JsProperty + public Common defaultCommon; + @JsProperty + public String defaultHardfork; + @JsProperty + public String defaultChain; + @JsProperty + public int transactionPollingTimeout; + @JsProperty + public int transactionConfirmationBlocks; + @JsProperty + public int transactionBlockTimeout; + @JsProperty + public boolean handleRevert; + @JsProperty + public Options options; + + public Contract(Object jsonInterface, String address) {} + + @JsOverlay + public static V contractFor(Object jsonInterface, String address) { + Contract contract = new Contract(jsonInterface, address); + return (V) contract; + } + + @JsMethod + public static native boolean setProvider(Provider provider); + + @JsMethod + public native Contract clone(); + + public static interface ContractMethods { + } + + public static interface ContractMethod { + @JsMethod + Promise call(); + @JsMethod + Promise send(); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/ContractOptions.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/ContractOptions.java new file mode 100644 index 0000000000..2ee20d6831 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/ContractOptions.java @@ -0,0 +1,18 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.eth.contract; + +import jsinterop.annotations.JsProperty; + +public class ContractOptions { + // Sender to use for contract calls + @JsProperty + public String from; + // Gas price to use for contract calls + @JsProperty + public String gasPrice; + // Gas to use for contract calls + @JsProperty + public int gas; + // Contract code + @JsProperty + public String data; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/DeployOptions.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/DeployOptions.java new file mode 100644 index 0000000000..d862e87b55 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/DeployOptions.java @@ -0,0 +1,5 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.eth.contract; + +public class DeployOptions { + public String data; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/Options.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/Options.java new file mode 100644 index 0000000000..925ff9d368 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/client/web3/eth/contract/Options.java @@ -0,0 +1,10 @@ +package ch.unifr.digits.webprotege.attestation.client.web3.eth.contract; + +import jsinterop.annotations.JsProperty; + +public class Options { + @JsProperty + public String address; + @JsProperty + public String[] jsonInterface; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/contracts.js b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/contracts.js new file mode 100644 index 0000000000..d30fe127dc --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/contracts.js @@ -0,0 +1,36 @@ +function OntologyAttestationContract(web3, jsonInterface, address) { + this.delegate = new web3.eth.Contract(jsonInterface, address); + this.verify = function(from, ontologyIri, versionIri, hash) { + return this.delegate.methods.verify(ontologyIri, versionIri, hash).call({from: from}); + } + this.attest = function(from, ontologyIri, versionIri, name, hash) { + return this.delegate.methods.attest(ontologyIri, versionIri, name, hash).send({from: from}); + } +} +function ChangeTrackingContract(web3, jsonInterface, address) { + this.delegate = new web3.eth.Contract(jsonInterface, address); + this.verifyEntity = function(from, ontologyIri, versionIri, entityHash) { + return this.delegate.methods.verifyEntity(ontologyIri, versionIri, entityHash).call({from: from}); + } + this.verify = function(from, ontologyIri, versionIri, hash) { + return this.delegate.methods.verify(ontologyIri, versionIri, hash).call({from: from}); + } + this.attest = function(from, ontologyIri, versionIri, name, hash, classHashes) { + var array = convertIntList(classHashes); + console.log(array); + return this.delegate.methods.attest(ontologyIri, versionIri, name, hash, array).send({from: from}); + } +} +function convertIntList(list) { + var array = []; + if ('java_util_ArrayList_array' in list && list['java_util_ArrayList_array']) { + var intObjArr = list['java_util_ArrayList_array']; + intObjArr.forEach(intObj => { + if ('java_lang_Integer_value' in intObj && intObj['java_lang_Integer_value']) { + var val = intObj['java_lang_Integer_value']; + array.push(val); + } + }) + } + return array; +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/detect-provider.min.js b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/detect-provider.min.js new file mode 100644 index 0000000000..7e2288e0d7 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/detect-provider.min.js @@ -0,0 +1,5 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.detectEthereumProvider = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i{function i(){if(n)return;n=!0,window.removeEventListener("ethereum#initialized",i);const{ethereum:o}=window;if(!o||e&&!o.isMetaMask){const n=e&&o?"Non-MetaMask window.ethereum detected.":"Unable to detect window.ethereum.";!t&&console.error("@metamask/detect-provider:",n),r(null)}else r(o)}window.ethereum?i():(window.addEventListener("ethereum#initialized",i,{once:!0}),setTimeout(()=>{i()},o))})}; + +},{}]},{},[1])(1) +}); diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/interfaces/ChangeTracking.json b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/interfaces/ChangeTracking.json new file mode 100644 index 0000000000..75ae4e2c7f --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/interfaces/ChangeTracking.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"ontologyIri","type":"string"},{"internalType":"string","name":"versionIri","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"hash","type":"string"},{"internalType":"int256[]","name":"classHashes","type":"int256[]"}],"name":"attest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ontologyIri","type":"string"},{"internalType":"string","name":"versionIri","type":"string"},{"internalType":"string","name":"hash","type":"string"}],"name":"verify","outputs":[{"internalType":"bool","name":"valid","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"string","name":"signerName","type":"string"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"ontologyIri","type":"string"},{"internalType":"string","name":"versionIri","type":"string"},{"internalType":"int256","name":"entityHash","type":"int256"}],"name":"verifyEntity","outputs":[{"internalType":"bool","name":"valid","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"string","name":"signerName","type":"string"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/interfaces/OntologyAttestation.json b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/interfaces/OntologyAttestation.json new file mode 100644 index 0000000000..f81d8abc4e --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/interfaces/OntologyAttestation.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"ontologyIri","type":"string"},{"internalType":"string","name":"versionIri","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"hash","type":"string"}],"name":"attest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ontologyIri","type":"string"},{"internalType":"string","name":"versionIri","type":"string"},{"internalType":"string","name":"hash","type":"string"}],"name":"verify","outputs":[{"internalType":"bool","name":"valid","type":"bool"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"string","name":"signerName","type":"string"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/jszip.min.js b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/jszip.min.js new file mode 100644 index 0000000000..bf7739ab96 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/public/attestation/jszip.min.js @@ -0,0 +1,13 @@ +/*! + +JSZip v3.5.0 - A JavaScript class for generating and reading zip files + + +(c) 2009-2016 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/master/LICENSE +*/ + +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=t()}}(function(){return function s(a,o,h){function u(r,t){if(!o[r]){if(!a[r]){var e="function"==typeof require&&require;if(!t&&e)return e(r,!0);if(l)return l(r,!0);var i=new Error("Cannot find module '"+r+"'");throw i.code="MODULE_NOT_FOUND",i}var n=o[r]={exports:{}};a[r][0].call(n.exports,function(t){var e=a[r][1][t];return u(e||t)},n,n.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,t=0;t>2,s=(3&e)<<4|r>>4,a=1>6:64,o=2>4,r=(15&n)<<4|(s=p.indexOf(t.charAt(o++)))>>2,i=(3&s)<<6|(a=p.indexOf(t.charAt(o++))),l[h++]=e,64!==s&&(l[h++]=r),64!==a&&(l[h++]=i);return l}},{"./support":30,"./utils":32}],2:[function(t,e,r){"use strict";var i=t("./external"),n=t("./stream/DataWorker"),s=t("./stream/DataLengthProbe"),a=t("./stream/Crc32Probe");s=t("./stream/DataLengthProbe");function o(t,e,r,i,n){this.compressedSize=t,this.uncompressedSize=e,this.crc32=r,this.compression=i,this.compressedContent=n}o.prototype={getContentWorker:function(){var t=new n(i.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new s("data_length")),e=this;return t.on("end",function(){if(this.streamInfo.data_length!==e.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),t},getCompressedWorker:function(){return new n(i.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(t,e,r){return t.pipe(new a).pipe(new s("uncompressedSize")).pipe(e.compressWorker(r)).pipe(new s("compressedSize")).withStreamInfo("compression",e)},e.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(t,e,r){"use strict";var i=t("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(t){return new i("STORE compression")},uncompressWorker:function(){return new i("STORE decompression")}},r.DEFLATE=t("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(t,e,r){"use strict";var i=t("./utils");var o=function(){for(var t,e=[],r=0;r<256;r++){t=r;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[r]=t}return e}();e.exports=function(t,e){return void 0!==t&&t.length?"string"!==i.getTypeOf(t)?function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a>>8^n[255&(t^e[a])];return-1^t}(0|e,t,t.length,0):function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a>>8^n[255&(t^e.charCodeAt(a))];return-1^t}(0|e,t,t.length,0):0}},{"./utils":32}],5:[function(t,e,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(t,e,r){"use strict";var i=null;i="undefined"!=typeof Promise?Promise:t("lie"),e.exports={Promise:i}},{lie:37}],7:[function(t,e,r){"use strict";var i="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,n=t("pako"),s=t("./utils"),a=t("./stream/GenericWorker"),o=i?"uint8array":"array";function h(t,e){a.call(this,"FlateWorker/"+t),this._pako=null,this._pakoAction=t,this._pakoOptions=e,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(t){this.meta=t.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,t.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new n[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var e=this;this._pako.onData=function(t){e.push({data:t,meta:e.meta})}},r.compressWorker=function(t){return new h("Deflate",t)},r.uncompressWorker=function(){return new h("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(t,e,r){"use strict";function A(t,e){var r,i="";for(r=0;r>>=8;return i}function i(t,e,r,i,n,s){var a,o,h=t.file,u=t.compression,l=s!==O.utf8encode,f=I.transformTo("string",s(h.name)),d=I.transformTo("string",O.utf8encode(h.name)),c=h.comment,p=I.transformTo("string",s(c)),m=I.transformTo("string",O.utf8encode(c)),_=d.length!==h.name.length,g=m.length!==c.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};e&&!r||(x.crc32=t.crc32,x.compressedSize=t.compressedSize,x.uncompressedSize=t.uncompressedSize);var S=0;e&&(S|=8),l||!_&&!g||(S|=2048);var z=0,C=0;w&&(z|=16),"UNIX"===n?(C=798,z|=function(t,e){var r=t;return t||(r=e?16893:33204),(65535&r)<<16}(h.unixPermissions,w)):(C=20,z|=function(t){return 63&(t||0)}(h.dosPermissions)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v=A(1,1)+A(B(f),4)+d,b+="up"+A(v.length,2)+v),g&&(y=A(1,1)+A(B(p),4)+m,b+="uc"+A(y.length,2)+y);var E="";return E+="\n\0",E+=A(S,2),E+=u.magic,E+=A(a,2),E+=A(o,2),E+=A(x.crc32,4),E+=A(x.compressedSize,4),E+=A(x.uncompressedSize,4),E+=A(f.length,2),E+=A(b.length,2),{fileRecord:R.LOCAL_FILE_HEADER+E+f+b,dirRecord:R.CENTRAL_FILE_HEADER+A(C,2)+E+A(p.length,2)+"\0\0\0\0"+A(z,4)+A(i,4)+f+b+p}}var I=t("../utils"),n=t("../stream/GenericWorker"),O=t("../utf8"),B=t("../crc32"),R=t("../signature");function s(t,e,r,i){n.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=e,this.zipPlatform=r,this.encodeFileName=i,this.streamFiles=t,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}I.inherits(s,n),s.prototype.push=function(t){var e=t.meta.percent||0,r=this.entriesCount,i=this._sources.length;this.accumulate?this.contentBuffer.push(t):(this.bytesWritten+=t.data.length,n.prototype.push.call(this,{data:t.data,meta:{currentFile:this.currentFile,percent:r?(e+100*(r-i-1))/r:100}}))},s.prototype.openedSource=function(t){this.currentSourceOffset=this.bytesWritten,this.currentFile=t.file.name;var e=this.streamFiles&&!t.file.dir;if(e){var r=i(t,e,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},s.prototype.closedSource=function(t){this.accumulate=!1;var e=this.streamFiles&&!t.file.dir,r=i(t,e,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(r.dirRecord),e)this.push({data:function(t){return R.DATA_DESCRIPTOR+A(t.crc32,4)+A(t.compressedSize,4)+A(t.uncompressedSize,4)}(t),meta:{percent:100}});else for(this.push({data:r.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},s.prototype.flush=function(){for(var t=this.bytesWritten,e=0;e=this.index;e--)r=(r<<8)+this.byteAt(e);return this.index+=t,r},readString:function(t){return i.transformTo("string",this.readData(t))},readData:function(t){},lastIndexOfSignature:function(t){},readAndCheckSignature:function(t){},readDate:function(){var t=this.readInt(4);return new Date(Date.UTC(1980+(t>>25&127),(t>>21&15)-1,t>>16&31,t>>11&31,t>>5&63,(31&t)<<1))}},e.exports=n},{"../utils":32}],19:[function(t,e,r){"use strict";var i=t("./Uint8ArrayReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.readData=function(t){this.checkOffset(t);var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(t,e,r){"use strict";var i=t("./DataReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.byteAt=function(t){return this.data.charCodeAt(this.zero+t)},n.prototype.lastIndexOfSignature=function(t){return this.data.lastIndexOf(t)-this.zero},n.prototype.readAndCheckSignature=function(t){return t===this.readData(4)},n.prototype.readData=function(t){this.checkOffset(t);var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./DataReader":18}],21:[function(t,e,r){"use strict";var i=t("./ArrayReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.readData=function(t){if(this.checkOffset(t),0===t)return new Uint8Array(0);var e=this.data.subarray(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./ArrayReader":17}],22:[function(t,e,r){"use strict";var i=t("../utils"),n=t("../support"),s=t("./ArrayReader"),a=t("./StringReader"),o=t("./NodeBufferReader"),h=t("./Uint8ArrayReader");e.exports=function(t){var e=i.getTypeOf(t);return i.checkSupport(e),"string"!==e||n.uint8array?"nodebuffer"===e?new o(t):n.uint8array?new h(i.transformTo("uint8array",t)):new s(i.transformTo("array",t)):new a(t)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(t,e,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(t,e,r){"use strict";var i=t("./GenericWorker"),n=t("../utils");function s(t){i.call(this,"ConvertWorker to "+t),this.destType=t}n.inherits(s,i),s.prototype.processChunk=function(t){this.push({data:n.transformTo(this.destType,t.data),meta:t.meta})},e.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(t,e,r){"use strict";var i=t("./GenericWorker"),n=t("../crc32");function s(){i.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}t("../utils").inherits(s,i),s.prototype.processChunk=function(t){this.streamInfo.crc32=n(t.data,this.streamInfo.crc32||0),this.push(t)},e.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(t,e,r){"use strict";var i=t("../utils"),n=t("./GenericWorker");function s(t){n.call(this,"DataLengthProbe for "+t),this.propName=t,this.withStreamInfo(t,0)}i.inherits(s,n),s.prototype.processChunk=function(t){if(t){var e=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=e+t.data.length}n.prototype.processChunk.call(this,t)},e.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(t,e,r){"use strict";var i=t("../utils"),n=t("./GenericWorker");function s(t){n.call(this,"DataWorker");var e=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,t.then(function(t){e.dataIsReady=!0,e.data=t,e.max=t&&t.length||0,e.type=i.getTypeOf(t),e.isPaused||e._tickAndRepeat()},function(t){e.error(t)})}i.inherits(s,n),s.prototype.cleanUp=function(){n.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!n.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,i.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(i.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var t=null,e=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":t=this.data.substring(this.index,e);break;case"uint8array":t=this.data.subarray(this.index,e);break;case"array":case"nodebuffer":t=this.data.slice(this.index,e)}return this.index=e,this.push({data:t,meta:{percent:this.max?this.index/this.max*100:0}})},e.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(t,e,r){"use strict";function i(t){this.name=t||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}i.prototype={push:function(t){this.emit("data",t)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(t){this.emit("error",t)}return!0},error:function(t){return!this.isFinished&&(this.isPaused?this.generatedError=t:(this.isFinished=!0,this.emit("error",t),this.previous&&this.previous.error(t),this.cleanUp()),!0)},on:function(t,e){return this._listeners[t].push(e),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(t,e){if(this._listeners[t])for(var r=0;r "+t:t}},e.exports=i},{}],29:[function(t,e,r){"use strict";var h=t("../utils"),n=t("./ConvertWorker"),s=t("./GenericWorker"),u=t("../base64"),i=t("../support"),a=t("../external"),o=null;if(i.nodestream)try{o=t("../nodejs/NodejsStreamOutputAdapter")}catch(t){}function l(t,o){return new a.Promise(function(e,r){var i=[],n=t._internalType,s=t._outputType,a=t._mimeType;t.on("data",function(t,e){i.push(t),o&&o(e)}).on("error",function(t){i=[],r(t)}).on("end",function(){try{var t=function(t,e,r){switch(t){case"blob":return h.newBlob(h.transformTo("arraybuffer",e),r);case"base64":return u.encode(e);default:return h.transformTo(t,e)}}(s,function(t,e){var r,i=0,n=null,s=0;for(r=0;r>>6:(r<65536?e[s++]=224|r>>>12:(e[s++]=240|r>>>18,e[s++]=128|r>>>12&63),e[s++]=128|r>>>6&63),e[s++]=128|63&r);return e}(t)},s.utf8decode=function(t){return h.nodebuffer?o.transformTo("nodebuffer",t).toString("utf-8"):function(t){var e,r,i,n,s=t.length,a=new Array(2*s);for(e=r=0;e>10&1023,a[r++]=56320|1023&i)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(t=o.transformTo(h.uint8array?"uint8array":"array",t))},o.inherits(a,i),a.prototype.processChunk=function(t){var e=o.transformTo(h.uint8array?"uint8array":"array",t.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=e;(e=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),e.set(r,this.leftOver.length)}else e=this.leftOver.concat(e);this.leftOver=null}var i=function(t,e){var r;for((e=e||t.length)>t.length&&(e=t.length),r=e-1;0<=r&&128==(192&t[r]);)r--;return r<0?e:0===r?e:r+u[t[r]]>e?r:e}(e),n=e;i!==e.length&&(h.uint8array?(n=e.subarray(0,i),this.leftOver=e.subarray(i,e.length)):(n=e.slice(0,i),this.leftOver=e.slice(i,e.length))),this.push({data:s.utf8decode(n),meta:t.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,i),l.prototype.processChunk=function(t){this.push({data:s.utf8encode(t.data),meta:t.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(t,e,a){"use strict";var o=t("./support"),h=t("./base64"),r=t("./nodejsUtils"),i=t("set-immediate-shim"),u=t("./external");function n(t){return t}function l(t,e){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==t&&(this.dosPermissions=63&this.externalFileAttributes),3==t&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(t){if(this.extraFields[1]){var e=i(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4))}},readExtraFields:function(t){var e,r,i,n=t.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});t.index+4>>6:(r<65536?e[s++]=224|r>>>12:(e[s++]=240|r>>>18,e[s++]=128|r>>>12&63),e[s++]=128|r>>>6&63),e[s++]=128|63&r);return e},r.buf2binstring=function(t){return l(t,t.length)},r.binstring2buf=function(t){for(var e=new h.Buf8(t.length),r=0,i=e.length;r>10&1023,o[i++]=56320|1023&n)}return l(o,i)},r.utf8border=function(t,e){var r;for((e=e||t.length)>t.length&&(e=t.length),r=e-1;0<=r&&128==(192&t[r]);)r--;return r<0?e:0===r?e:r+u[t[r]]>e?r:e}},{"./common":41}],43:[function(t,e,r){"use strict";e.exports=function(t,e,r,i){for(var n=65535&t|0,s=t>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:t>>>1;e[r]=t}return e}();e.exports=function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a>>8^n[255&(t^e[a])];return-1^t}},{}],46:[function(t,e,r){"use strict";var h,d=t("../utils/common"),u=t("./trees"),c=t("./adler32"),p=t("./crc32"),i=t("./messages"),l=0,f=4,m=0,_=-2,g=-1,b=4,n=2,v=8,y=9,s=286,a=30,o=19,w=2*s+1,k=15,x=3,S=258,z=S+x+1,C=42,E=113,A=1,I=2,O=3,B=4;function R(t,e){return t.msg=i[e],e}function T(t){return(t<<1)-(4t.avail_out&&(r=t.avail_out),0!==r&&(d.arraySet(t.output,e.pending_buf,e.pending_out,r,t.next_out),t.next_out+=r,e.pending_out+=r,t.total_out+=r,t.avail_out-=r,e.pending-=r,0===e.pending&&(e.pending_out=0))}function N(t,e){u._tr_flush_block(t,0<=t.block_start?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,F(t.strm)}function U(t,e){t.pending_buf[t.pending++]=e}function P(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function L(t,e){var r,i,n=t.max_chain_length,s=t.strstart,a=t.prev_length,o=t.nice_match,h=t.strstart>t.w_size-z?t.strstart-(t.w_size-z):0,u=t.window,l=t.w_mask,f=t.prev,d=t.strstart+S,c=u[s+a-1],p=u[s+a];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do{if(u[(r=e)+a]===p&&u[r+a-1]===c&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&sh&&0!=--n);return a<=t.lookahead?a:t.lookahead}function j(t){var e,r,i,n,s,a,o,h,u,l,f=t.w_size;do{if(n=t.window_size-t.lookahead-t.strstart,t.strstart>=f+(f-z)){for(d.arraySet(t.window,t.window,f,f,0),t.match_start-=f,t.strstart-=f,t.block_start-=f,e=r=t.hash_size;i=t.head[--e],t.head[e]=f<=i?i-f:0,--r;);for(e=r=f;i=t.prev[--e],t.prev[e]=f<=i?i-f:0,--r;);n+=f}if(0===t.strm.avail_in)break;if(a=t.strm,o=t.window,h=t.strstart+t.lookahead,u=n,l=void 0,l=a.avail_in,u=x)for(s=t.strstart-t.insert,t.ins_h=t.window[s],t.ins_h=(t.ins_h<=x&&(t.ins_h=(t.ins_h<=x)if(i=u._tr_tally(t,t.strstart-t.match_start,t.match_length-x),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=x){for(t.match_length--;t.strstart++,t.ins_h=(t.ins_h<=x&&(t.ins_h=(t.ins_h<=x&&t.match_length<=t.prev_length){for(n=t.strstart+t.lookahead-x,i=u._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-x),t.lookahead-=t.prev_length-1,t.prev_length-=2;++t.strstart<=n&&(t.ins_h=(t.ins_h<t.pending_buf_size-5&&(r=t.pending_buf_size-5);;){if(t.lookahead<=1){if(j(t),0===t.lookahead&&e===l)return A;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var i=t.block_start+r;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,N(t,!1),0===t.strm.avail_out))return A;if(t.strstart-t.block_start>=t.w_size-z&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):(t.strstart>t.block_start&&(N(t,!1),t.strm.avail_out),A)}),new M(4,4,8,4,Z),new M(4,5,16,8,Z),new M(4,6,32,32,Z),new M(4,4,16,16,W),new M(8,16,32,32,W),new M(8,16,128,128,W),new M(8,32,128,256,W),new M(32,128,258,1024,W),new M(32,258,258,4096,W)],r.deflateInit=function(t,e){return Y(t,e,v,15,8,0)},r.deflateInit2=Y,r.deflateReset=K,r.deflateResetKeep=G,r.deflateSetHeader=function(t,e){return t&&t.state?2!==t.state.wrap?_:(t.state.gzhead=e,m):_},r.deflate=function(t,e){var r,i,n,s;if(!t||!t.state||5>8&255),U(i,i.gzhead.time>>16&255),U(i,i.gzhead.time>>24&255),U(i,9===i.level?2:2<=i.strategy||i.level<2?4:0),U(i,255&i.gzhead.os),i.gzhead.extra&&i.gzhead.extra.length&&(U(i,255&i.gzhead.extra.length),U(i,i.gzhead.extra.length>>8&255)),i.gzhead.hcrc&&(t.adler=p(t.adler,i.pending_buf,i.pending,0)),i.gzindex=0,i.status=69):(U(i,0),U(i,0),U(i,0),U(i,0),U(i,0),U(i,9===i.level?2:2<=i.strategy||i.level<2?4:0),U(i,3),i.status=E);else{var a=v+(i.w_bits-8<<4)<<8;a|=(2<=i.strategy||i.level<2?0:i.level<6?1:6===i.level?2:3)<<6,0!==i.strstart&&(a|=32),a+=31-a%31,i.status=E,P(i,a),0!==i.strstart&&(P(i,t.adler>>>16),P(i,65535&t.adler)),t.adler=1}if(69===i.status)if(i.gzhead.extra){for(n=i.pending;i.gzindex<(65535&i.gzhead.extra.length)&&(i.pending!==i.pending_buf_size||(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending!==i.pending_buf_size));)U(i,255&i.gzhead.extra[i.gzindex]),i.gzindex++;i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),i.gzindex===i.gzhead.extra.length&&(i.gzindex=0,i.status=73)}else i.status=73;if(73===i.status)if(i.gzhead.name){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending===i.pending_buf_size)){s=1;break}s=i.gzindexn&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),0===s&&(i.gzindex=0,i.status=91)}else i.status=91;if(91===i.status)if(i.gzhead.comment){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending===i.pending_buf_size)){s=1;break}s=i.gzindexn&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),0===s&&(i.status=103)}else i.status=103;if(103===i.status&&(i.gzhead.hcrc?(i.pending+2>i.pending_buf_size&&F(t),i.pending+2<=i.pending_buf_size&&(U(i,255&t.adler),U(i,t.adler>>8&255),t.adler=0,i.status=E)):i.status=E),0!==i.pending){if(F(t),0===t.avail_out)return i.last_flush=-1,m}else if(0===t.avail_in&&T(e)<=T(r)&&e!==f)return R(t,-5);if(666===i.status&&0!==t.avail_in)return R(t,-5);if(0!==t.avail_in||0!==i.lookahead||e!==l&&666!==i.status){var o=2===i.strategy?function(t,e){for(var r;;){if(0===t.lookahead&&(j(t),0===t.lookahead)){if(e===l)return A;break}if(t.match_length=0,r=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,r&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}(i,e):3===i.strategy?function(t,e){for(var r,i,n,s,a=t.window;;){if(t.lookahead<=S){if(j(t),t.lookahead<=S&&e===l)return A;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=x&&0t.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=x?(r=u._tr_tally(t,1,t.match_length-x),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(r=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),r&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}(i,e):h[i.level].func(i,e);if(o!==O&&o!==B||(i.status=666),o===A||o===O)return 0===t.avail_out&&(i.last_flush=-1),m;if(o===I&&(1===e?u._tr_align(i):5!==e&&(u._tr_stored_block(i,0,0,!1),3===e&&(D(i.head),0===i.lookahead&&(i.strstart=0,i.block_start=0,i.insert=0))),F(t),0===t.avail_out))return i.last_flush=-1,m}return e!==f?m:i.wrap<=0?1:(2===i.wrap?(U(i,255&t.adler),U(i,t.adler>>8&255),U(i,t.adler>>16&255),U(i,t.adler>>24&255),U(i,255&t.total_in),U(i,t.total_in>>8&255),U(i,t.total_in>>16&255),U(i,t.total_in>>24&255)):(P(i,t.adler>>>16),P(i,65535&t.adler)),F(t),0=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new d.Buf8(r.w_size),d.arraySet(u,e,l-r.w_size,r.w_size,0),e=u,l=r.w_size),a=t.avail_in,o=t.next_in,h=t.input,t.avail_in=l,t.next_in=0,t.input=e,j(r);r.lookahead>=x;){for(i=r.strstart,n=r.lookahead-(x-1);r.ins_h=(r.ins_h<>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(c&(1<>>=y,p-=y),p<15&&(c+=z[i++]<>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(c&(1<>>=y,p-=y,(y=s-a)>3,c&=(1<<(p-=w<<3))-1,t.next_in=i,t.next_out=s,t.avail_in=i>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=P,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new I.Buf32(i),e.distcode=e.distdyn=new I.Buf32(n),e.sane=1,e.back=-1,N):U}function o(t){var e;return t&&t.state?((e=t.state).wsize=0,e.whave=0,e.wnext=0,a(t)):U}function h(t,e){var r,i;return t&&t.state?(i=t.state,e<0?(r=0,e=-e):(r=1+(e>>4),e<48&&(e&=15)),e&&(e<8||15=s.wsize?(I.arraySet(s.window,e,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(i<(n=s.wsize-s.wnext)&&(n=i),I.arraySet(s.window,e,r-i,n,s.wnext),(i-=n)?(I.arraySet(s.window,e,r-i,i,0),s.wnext=i,s.whave=s.wsize):(s.wnext+=n,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){t.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){t.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){t.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break t;o--,u+=i[s++]<>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break t;o--,u+=i[s++]<>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break t;o--,u+=i[s++]<>>8&255,r.check=B(r.check,E,2,0)),l=u=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(c=r.length)&&(c=o),c&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,i,s,c,k)),512&r.flags&&(r.check=B(r.check,i,c,s)),o-=c,s+=c,r.length-=c),r.length))break t;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break t;for(c=0;k=i[s+c++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&c>9&1,r.head.done=!0),t.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break t;o--,u+=i[s++]<>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break t;o--,u+=i[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==e)break;u>>>=2,l-=2;break t;case 2:r.mode=17;break;case 3:t.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break t;o--,u+=i[s++]<>>16^65535)){t.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===e)break t;case 15:r.mode=16;case 16:if(c=r.length){if(o>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){t.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l>>=_,l-=_,0===r.have){t.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],c=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l>>=_)),u>>>=3,l-=3}else{for(z=_+7;l>>=_)),u>>>=7,l-=7}if(r.have+c>r.nlen+r.ndist){t.msg="invalid bit length repeat",r.mode=30;break}for(;c--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){t.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){t.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){t.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===e)break t;case 20:r.mode=21;case 21:if(6<=o&&258<=h){t.next_out=a,t.avail_out=h,t.next_in=s,t.avail_in=o,r.hold=u,r.bits=l,R(t,d),a=t.next_out,n=t.output,h=t.avail_out,s=t.next_in,i=t.input,o=t.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){t.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){t.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){t.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break t;if(c=d-h,r.offset>c){if((c=r.offset-c)>r.whave&&r.sane){t.msg="invalid distance too far back",r.mode=30;break}p=c>r.wnext?(c-=r.wnext,r.wsize-c):r.wnext-c,c>r.length&&(c=r.length),m=r.window}else m=n,p=a-r.offset,c=r.length;for(hc?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=e[r+a[v]]}if(k>>7)]}function U(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function P(t,e,r){t.bi_valid>c-r?(t.bi_buf|=e<>c-t.bi_valid,t.bi_valid+=r-c):(t.bi_buf|=e<>>=1,r<<=1,0<--e;);return r>>>1}function Z(t,e,r){var i,n,s=new Array(g+1),a=0;for(i=1;i<=g;i++)s[i]=a=a+r[i-1]<<1;for(n=0;n<=e;n++){var o=t[2*n+1];0!==o&&(t[2*n]=j(s[o]++,o))}}function W(t){var e;for(e=0;e>1;1<=r;r--)G(t,s,r);for(n=h;r=t.heap[1],t.heap[1]=t.heap[t.heap_len--],G(t,s,1),i=t.heap[1],t.heap[--t.heap_max]=r,t.heap[--t.heap_max]=i,s[2*n]=s[2*r]+s[2*i],t.depth[n]=(t.depth[r]>=t.depth[i]?t.depth[r]:t.depth[i])+1,s[2*r+1]=s[2*i+1]=n,t.heap[1]=n++,G(t,s,1),2<=t.heap_len;);t.heap[--t.heap_max]=t.heap[1],function(t,e){var r,i,n,s,a,o,h=e.dyn_tree,u=e.max_code,l=e.stat_desc.static_tree,f=e.stat_desc.has_stree,d=e.stat_desc.extra_bits,c=e.stat_desc.extra_base,p=e.stat_desc.max_length,m=0;for(s=0;s<=g;s++)t.bl_count[s]=0;for(h[2*t.heap[t.heap_max]+1]=0,r=t.heap_max+1;r<_;r++)p<(s=h[2*h[2*(i=t.heap[r])+1]+1]+1)&&(s=p,m++),h[2*i+1]=s,u>=7;i>>=1)if(1&r&&0!==t.dyn_ltree[2*e])return o;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return h;for(e=32;e>>3,(s=t.static_len+3+7>>>3)<=n&&(n=s)):n=s=r+5,r+4<=n&&-1!==e?J(t,e,r,i):4===t.strategy||s===n?(P(t,2+(i?1:0),3),K(t,z,C)):(P(t,4+(i?1:0),3),function(t,e,r,i){var n;for(P(t,e-257,5),P(t,r-1,5),P(t,i-4,4),n=0;n>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&r,t.last_lit++,0===e?t.dyn_ltree[2*r]++:(t.matches++,e--,t.dyn_ltree[2*(A[r]+u+1)]++,t.dyn_dtree[2*N(e)]++),t.last_lit===t.lit_bufsize-1},r._tr_align=function(t){P(t,2,3),L(t,m,z),function(t){16===t.bi_valid?(U(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):8<=t.bi_valid&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}(t)}},{"../utils/common":41}],53:[function(t,e,r){"use strict";e.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(t,e,r){"use strict";e.exports="function"==typeof setImmediate?setImmediate:function(){var t=[].slice.apply(arguments);t.splice(1,0,0),setTimeout.apply(null,t)}},{}]},{},[10])(10)}); \ No newline at end of file diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/AttestationService.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/AttestationService.java new file mode 100644 index 0000000000..c865a01e88 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/AttestationService.java @@ -0,0 +1,48 @@ +package ch.unifr.digits.webprotege.attestation.server; + +import ch.unifr.digits.webprotege.attestation.shared.VerifyResult; +import okhttp3.OkHttpClient; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.Web3jService; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.protocol.http.HttpService; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static ch.unifr.digits.webprotege.attestation.server.SettingsManager.*; + +public abstract class AttestationService { + + protected static final Credentials CREDENTIALS = Credentials.create(SERVER_SECRET); + protected static final AtomicReference WEB3_REF = new AtomicReference<>(); + + public AttestationService() { + init(); + } + + public abstract String contractAddress(); + public abstract TransactionReceipt attest(String iri, String versionIri, String name, String hash, T params) throws Exception; + public abstract VerifyResult verify(String iri, String versionIri, String hash, T params) throws Exception; + + private static void init() { + if (WEB3_REF.compareAndSet(null, null)) { + Web3jService service = buildService(PROVIDER_HOST + ":" + PROVIDER_PORT); + Web3j web3 = Web3j.build(service); + boolean result = WEB3_REF.compareAndSet(null, web3); + if (!result) web3.shutdown(); + } + } + + private static Web3jService buildService(String url) { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + long tos = 300L; + builder.connectTimeout(tos, TimeUnit.SECONDS); + builder.readTimeout(tos, TimeUnit.SECONDS); + builder.writeTimeout(tos, TimeUnit.SECONDS); + return new HttpService(url, builder.build()); + } + + public static class NopParam {} +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/ChangeTrackingAttestationService.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/ChangeTrackingAttestationService.java new file mode 100644 index 0000000000..d18b37ce4a --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/ChangeTrackingAttestationService.java @@ -0,0 +1,87 @@ +package ch.unifr.digits.webprotege.attestation.server; + +import ch.unifr.digits.webprotege.attestation.server.contracts.ChangeTracking; +import ch.unifr.digits.webprotege.attestation.server.contracts.OntologyAttestation; +import ch.unifr.digits.webprotege.attestation.shared.VerifyResult; +import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLClass; +import org.semanticweb.owlapi.model.OWLOntology; +import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tuples.generated.Tuple4; +import org.web3j.tx.gas.DefaultGasProvider; + +import java.math.BigInteger; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static ch.unifr.digits.webprotege.attestation.server.SettingsManager.ADDRESS_CHANGETRACKING; + +public class ChangeTrackingAttestationService extends OntologyAttestationService { + + @Override + public String contractAddress() { + return ADDRESS_CHANGETRACKING; + } + + public VerifyResult verifyEntity(String iri, String versionIri, String entityHash) throws Exception { + ChangeTracking contract = ChangeTracking.load(contractAddress(), WEB3_REF.get(), CREDENTIALS, + DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT); + RemoteFunctionCall> remoteFunctionCall = + contract.verifyEntity(iri, versionIri, new BigInteger(entityHash)); + Tuple4 result = remoteFunctionCall.send(); + BigInteger bigInteger = result.component4(); + int time = (bigInteger == null) ? -1 : bigInteger.intValue(); + return new VerifyResult(result.component1(), result.component2(), result.component3(), time); + } + + @Override + public VerifyResult verify(String iri, String versionIri, String hash, EntitySet params) throws Exception { + ChangeTracking contract = ChangeTracking.load(contractAddress(), WEB3_REF.get(), CREDENTIALS, + DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT); + RemoteFunctionCall> remoteFunctionCall = + contract.verify(iri, versionIri, hash); + Tuple4 result = remoteFunctionCall.send(); + BigInteger bigInteger = result.component4(); + int time = (bigInteger == null) ? -1 : bigInteger.intValue(); + return new VerifyResult(result.component1(), result.component2(), result.component3(), time); + } + + @Override + public TransactionReceipt attest(OWLOntology ontology, String name) throws Exception { + String hash = ontologyHash(ontology); + String ontologyIri = ontology.getOntologyID().getOntologyIRI().get().toString(); + String versionIri = ontology.getOntologyID().getVersionIRI().transform(IRI::toString).or(""); + List classHashes = toBigInt(classHashes(ontology)); + return attest(ontologyIri, versionIri, name, hash, new EntitySet(classHashes)); + } + + @Override + public TransactionReceipt attest(String iri, String versionIri, String name, String hash, EntitySet params) throws Exception { + ChangeTracking contract = ChangeTracking.load(contractAddress(), WEB3_REF.get(), CREDENTIALS, + DefaultGasProvider.GAS_PRICE, new BigInteger("1000000000")); + RemoteFunctionCall call = contract.attest(iri, versionIri, name, hash, + params.hashes); + TransactionReceipt transactionReceipt = call.send(); + return transactionReceipt; + } + + public List toBigInt(List ints) { + List classHashes = ints.stream().map(BigInteger::valueOf).collect(Collectors.toList()); + return classHashes; + } + + public List classHashes(OWLOntology ontology) { + Set classesInSignature = ontology.getClassesInSignature(); + List classHashes = classesInSignature.stream().map(this::entityHash).collect(Collectors.toList()); + return classHashes; + } + + public static class EntitySet { + public EntitySet(List hashes) { + this.hashes = hashes; + } + public final List hashes; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/FileAttestationService.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/FileAttestationService.java new file mode 100644 index 0000000000..1b68453c10 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/FileAttestationService.java @@ -0,0 +1,64 @@ +package ch.unifr.digits.webprotege.attestation.server; + +import ch.unifr.digits.webprotege.attestation.server.contracts.OntologyAttestation; +import ch.unifr.digits.webprotege.attestation.shared.VerifyResult; +import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tuples.generated.Tuple4; +import org.web3j.tx.gas.DefaultGasProvider; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import static ch.unifr.digits.webprotege.attestation.server.SettingsManager.ADDRESS_ATTESTATION; + +public class FileAttestationService extends AttestationService { + + @Override + public String contractAddress() { + return ADDRESS_ATTESTATION; + } + + @Override + public TransactionReceipt attest(String iri, String versionIri, String name, String hash, T params) throws Exception { + OntologyAttestation contract = OntologyAttestation.load(contractAddress(), WEB3_REF.get(), CREDENTIALS, + DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT); + RemoteFunctionCall call = contract.attest(iri, versionIri, name, hash); + TransactionReceipt receipt = call.send(); + return receipt; + } + + @Override + public VerifyResult verify(String iri, String versionIri, String hash, T params) throws Exception { + OntologyAttestation contract = OntologyAttestation.load(contractAddress(), WEB3_REF.get(), CREDENTIALS, + DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT); + RemoteFunctionCall> remoteFunctionCall = + contract.verify(iri, versionIri, hash); + Tuple4 result = remoteFunctionCall.send(); + BigInteger bigInteger = result.component4(); + int time = (bigInteger == null) ? -1 : bigInteger.intValue(); + return new VerifyResult(result.component1(), result.component2(), result.component3(), time); + } + + public String hashFile(byte[] data) { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + byte[] hashBytes = digest.digest(data); + return bytesToHex(hashBytes); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + private String bytesToHex(byte[] hash) { + StringBuilder hexString = new StringBuilder(); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/HashStringUtils.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/HashStringUtils.java new file mode 100644 index 0000000000..537d0009fb --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/HashStringUtils.java @@ -0,0 +1,32 @@ +package ch.unifr.digits.webprotege.attestation.server; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class HashStringUtils { + + public static String boundedHex(int data) { + return bytesToHex(hash(BigInteger.valueOf(data).toByteArray())); + } + + public static byte[] hash(byte[] data) { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + return digest.digest(data); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + public static String bytesToHex(byte[] hash) { + StringBuilder hexString = new StringBuilder(); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/OntologyAttestationService.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/OntologyAttestationService.java new file mode 100644 index 0000000000..f2fdae5605 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/OntologyAttestationService.java @@ -0,0 +1,48 @@ +package ch.unifr.digits.webprotege.attestation.server; + +import ch.unifr.digits.webprotege.attestation.server.compression.tree.CompressionTree; +import ch.unifr.digits.webprotege.attestation.server.compression.tree.OWLToRDFTranslator; +import ch.unifr.digits.webprotege.attestation.server.compression.tree.RDFTriple; +import org.semanticweb.owlapi.model.*; +import org.semanticweb.owlapi.model.parameters.Imports; +import org.web3j.protocol.core.methods.response.TransactionReceipt; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +public class OntologyAttestationService extends FileAttestationService { + + public TransactionReceipt attest(OWLOntology ontology, String name) throws Exception { + String hash = ontologyHash(ontology); + String ontologyIri = ontology.getOntologyID().getOntologyIRI().get().toString(); + String versionIri = ontology.getOntologyID().getVersionIRI().transform(IRI::toString).or(""); + return attest(ontologyIri, versionIri, name, hash, null); + } + + public String ontologyHash(OWLOntology ontology) { + try { + OWLToRDFTranslator translator = new OWLToRDFTranslator(ontology); + RDFTriple[] triples = translator.getTriples(); + CompressionTree ct = new CompressionTree(triples); + return ct.getRoot(); + } catch (Exception e) { + return null; + } + } + + public String simpleOntologyHash(OWLOntology ontology) { + Set signature = ontology.getSignature(Imports.INCLUDED); + Set axioms = ontology.getAxioms(Imports.INCLUDED); + Set annotations = ontology.getAnnotations(); + Set all = new HashSet<>(); + all.addAll(signature); + all.addAll(annotations); + all.addAll(axioms); + return HashStringUtils.boundedHex(all.hashCode()); + } + + public int entityHash(OWLEntity entity) { + return entity.hashCode(); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/SettingsManager.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/SettingsManager.java new file mode 100644 index 0000000000..30884f9feb --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/SettingsManager.java @@ -0,0 +1,39 @@ +package ch.unifr.digits.webprotege.attestation.server; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; + +public class SettingsManager { + + public static final String PROVIDER_HOST; + public static final String PROVIDER_PORT; + public static final String ADDRESS_ATTESTATION; + public static final String ADDRESS_CHANGETRACKING; + public static final String SERVER_SECRET; + + private static final String PROVIDER_HOST_VARNAME = "PROVIDER_HOST"; + private static final String PROVIDER_PORT_VARNAME = "PROVIDER_PORT"; + private static final String ADDRESS_ATTESTATION_VARNAME = "ADDRESS_ATTESTATION"; + private static final String ADDRESS_CHANGETRACKING_VARNAME = "ADDRESS_CHANGETRACKING"; + private static final String SERVER_SECRET_VARNAME = "SERVER_SECRET"; + + static { + final Map env = System.getenv(); + final Properties properties = new Properties(); + try (InputStream stream = SettingsManager.class.getClassLoader() + .getResourceAsStream("configuration/config.properties")) { + properties.load(stream); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + PROVIDER_HOST = env.getOrDefault(PROVIDER_HOST_VARNAME, properties.getProperty(PROVIDER_HOST_VARNAME)); + PROVIDER_PORT = env.getOrDefault(PROVIDER_PORT_VARNAME, properties.getProperty(PROVIDER_PORT_VARNAME)); + ADDRESS_ATTESTATION = env.getOrDefault(ADDRESS_ATTESTATION_VARNAME, properties.getProperty(ADDRESS_ATTESTATION_VARNAME)); + ADDRESS_CHANGETRACKING = env.getOrDefault(ADDRESS_CHANGETRACKING_VARNAME, properties.getProperty(ADDRESS_CHANGETRACKING_VARNAME)); + SERVER_SECRET = env.getOrDefault(SERVER_SECRET_VARNAME, properties.getProperty(SERVER_SECRET_VARNAME)); + } + } + +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/CompressionTree.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/CompressionTree.java new file mode 100644 index 0000000000..d6baa48ee4 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/CompressionTree.java @@ -0,0 +1,677 @@ +package ch.unifr.digits.webprotege.attestation.server.compression.tree; + +import org.apache.commons.codec.digest.DigestUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Set; + +public class CompressionTree { + + private String root; + + private HashMap subject_layer; + private HashMap> predicate_tree_layer; + + private HashMap>> adjacency_lists; + + private int nb_triples; + private int initial_capacity; + + private RDFTriple[] triples; + + public CompressionTree(RDFTriple[] triples) { + nb_triples = triples.length; + initial_capacity = (int) ((0.2 * (double) nb_triples) / 0.75); + this.triples = triples; + + adjacency_lists = new HashMap<>(initial_capacity); + subject_layer = new HashMap<>(initial_capacity); + predicate_tree_layer = new HashMap<>(initial_capacity); + + generateAdjacencyLists(); + generateHashedAdjacencyLists(); + generateCompressionTree(); + deleteAdjacencyLists(); + } + + public CompressionTree(RDFTriple[] triples, boolean empty) { + nb_triples = triples.length; + initial_capacity = (int) ((0.2 * (double) nb_triples) / 0.75); + this.triples = triples; + + adjacency_lists = new HashMap<>(initial_capacity); + subject_layer = new HashMap<>(initial_capacity); + predicate_tree_layer = new HashMap<>(initial_capacity); + + if (!empty) { + generateAdjacencyLists(); + generateHashedAdjacencyLists(); + generateCompressionTree(); + deleteAdjacencyLists(); + } + } + + public void deleteAdjacencyLists() { + adjacency_lists = null; + } + + public void generateCompressionTree() { + for (String subject: adjacency_lists.keySet()) { + + HashMap> predicate_object_list_map = adjacency_lists.get(subject); + + ArrayList predicateTrees = new ArrayList<>(); + + for (String predicate: predicate_object_list_map.keySet()) { + // Update predicate trees + ObjectList objectList = new ObjectList(predicate_object_list_map.get(predicate)); + PredicateTree predicateTree = new PredicateTree(predicate, objectList); + predicateTrees.add(predicateTree); + } + + predicate_tree_layer.put(subject, predicateTrees); + + String subject_children_hash = getPredicateTreeDigest(predicate_tree_layer.get(subject)); + subject_layer.put(subject, subject_children_hash); + } + + updateRoot(); + } + + public void insertTriples(RDFTriple[] triples) { + for (int i = 0; i < triples.length; i++) { + insertTriple(triples[i]); + } + } + + public void insertHashedTriples(RDFTriple[] triples) { + for (int i = 0; i < triples.length; i++) { + insertHashedTriple(triples[i]); + } + } + + public void insertTriple(RDFTriple triple) { + insertTriple(triple.getSubject(), triple.getPredicate(), triple.getObject()); + } + + public void insertHashedTriple(RDFTriple hashed_triple) { + insertHashedTriple(hashed_triple.getSubject(), hashed_triple.getPredicate(), hashed_triple.getObject()); + } + + public void insertTriple(String subject, String predicate, String object) { + String hashed_subject = DigestUtils.sha256Hex(subject); + String hashed_predicate = DigestUtils.sha256Hex(predicate); + String hashed_object = DigestUtils.sha256Hex(object); + + insert(hashed_subject, hashed_predicate, hashed_object); + } + + public void insertHashedTriple(String hashed_subject, String hashed_predicate, String hashed_object) { + insert(hashed_subject, hashed_predicate, hashed_object); + } + + private void insert(String hashed_subject, String hashed_predicate, String hashed_object) { + boolean subject_exists = subject_layer.containsKey(hashed_subject); + + if (!subject_exists) { + ObjectList objectList = new ObjectList(hashed_object); + PredicateTree predicateTree = new PredicateTree(hashed_predicate, objectList); + ArrayList predicateTrees = new ArrayList<>(); + predicateTrees.add(predicateTree); + predicate_tree_layer.put(hashed_subject, predicateTrees); + } else { + boolean predicate_exists = predicateExists(hashed_subject, hashed_predicate); + + if (!predicate_exists) { + ObjectList objectList = new ObjectList(hashed_object); + PredicateTree predicateTree = new PredicateTree(hashed_predicate, objectList); + predicate_tree_layer.get(hashed_subject).add(predicateTree); + } else { + PredicateTree predicateTree = getPredicateTree(hashed_subject, hashed_predicate); + boolean object_exists = predicateTree.getObject_list().contains(hashed_object); + + if (!object_exists) { + predicateTree.getObject_list().getList().add(hashed_object); + predicateTree.updateChildrenHash(); + } + } + } + + String predicate_tree_digest = getPredicateTreeDigest(predicate_tree_layer.get(hashed_subject)); + subject_layer.put(hashed_subject, predicate_tree_digest); + + updateRoot(); + } + + private PredicateTree getPredicateTree(String hashed_subject, String hashed_predicate) { + for (PredicateTree predicateTree: predicate_tree_layer.get(hashed_subject)) { + if (predicateTree.getPredicate().equals(hashed_predicate)) { + return predicateTree; + } + } + + return null; + } + + private boolean predicateExists(String hashed_subject, String hashed_predicate) { + for (PredicateTree predicateTree: predicate_tree_layer.get(hashed_subject)) { + if (predicateTree.getPredicate().equals(hashed_predicate)) { + return true; + } + } + + return false; + } + + private void updateRoot() { + root = getDigest(subject_layer); + } + + private String getPredicateTreeDigest(ArrayList predicateTrees) { + StringBuilder sb = new StringBuilder(); + + for (PredicateTree predicateTree: predicateTrees) { + sb.append(predicateTree.getDigest()); + } + + return DigestUtils.sha256Hex(sb.toString()); + } + + public void generateAdjacencyLists() { + generateAdjacencyLists(this.triples); + } + + public void generateAdjacencyLists(RDFTriple[] triples) { + for (RDFTriple triple: triples) { + String subject = triple.getSubject(); + String predicate = triple.getPredicate(); + String object = triple.getObject(); + + HashMap> predicate_object_list_map = adjacency_lists.get(subject); + + if (predicate_object_list_map == null) { + adjacency_lists.put(subject, createPredicateObjectListMap(predicate, object)); + } else { + ArrayList object_list = predicate_object_list_map.get(predicate); + + if (object_list == null) { + predicate_object_list_map.put(predicate, createObjectList(object)); + } else { + boolean object_exists = object_list.contains(object); + + if (!object_exists) { + object_list.add(object); + } + } + } + } + } + + public void generateHashedAdjacencyLists() { + HashMap>> hashed_adjacency_list = new HashMap<>(); + + for (String subject: adjacency_lists.keySet()) { + HashMap> hashed_predicate_map = new HashMap<>(); + + for (String predicate: adjacency_lists.get(subject).keySet()) { + ArrayList hashed_object_list = new ArrayList<>(); + + for (String object: adjacency_lists.get(subject).get(predicate)) { + hashed_object_list.add(DigestUtils.sha256Hex(object)); + } + + hashed_predicate_map.put(DigestUtils.sha256Hex(predicate), hashed_object_list); + } + + hashed_adjacency_list.put(DigestUtils.sha256Hex(subject), hashed_predicate_map); + } + + adjacency_lists = hashed_adjacency_list; + } + + private HashMap> createPredicateObjectListMap(String p, String o) { + ArrayList object_list = new ArrayList<>(); + object_list.add(o); + + HashMap> predicate_tree = new HashMap<>(); + predicate_tree.put(p, object_list); + + return predicate_tree; + } + + private ArrayList createObjectList(String o) { + ArrayList object_list = new ArrayList<>(); + object_list.add(o); + return object_list; + } + + private String getDigest(HashMap map) { + StringBuilder sb = new StringBuilder(); + + for (String key: map.keySet()) { + String digest = DigestUtils.sha256Hex(key+map.get(key)); + sb.append(digest); + } + + return DigestUtils.sha256Hex(sb.toString()); + } + + + private String getDigest(ArrayList list) { + StringBuilder sb = new StringBuilder(); + + for (String element : list) { + sb.append(element); + } + + return DigestUtils.sha256Hex(sb.toString()); + } + + private String getDigest(Set set) { + StringBuilder sb = new StringBuilder(); + + for (String element : set) { + sb.append(element); + } + + return DigestUtils.sha256Hex(sb.toString()); + } + + private String getHashTupleListDigest(ArrayList hashTuples) { + StringBuilder sb = new StringBuilder(); + + for (HashTuple hashTuple: hashTuples) { + String digest = DigestUtils.sha256Hex(hashTuple.getElementHash()+hashTuple.getChildrenHash()); + sb.append(digest); + } + + return DigestUtils.sha256Hex(sb.toString()); + } + + public int numberOfUniqueSubjects() { + return subject_layer.size(); + } + + public int numberOfUniquePredicates() { + int number_of_unique_predicates = 0; + for (String subject: predicate_tree_layer.keySet()) { + number_of_unique_predicates += predicate_tree_layer.get(subject).size(); + } + + return number_of_unique_predicates; + } + + public int numberOfUniqueObjects() { + int number_of_unique_objects = 0; + for (String subject: predicate_tree_layer.keySet()) { + for (PredicateTree predicate_tree: predicate_tree_layer.get(subject)) { + number_of_unique_objects += predicate_tree.getObject_list().getList().size(); + } + } + return number_of_unique_objects; + } + + public float averageNumberOfPredicatesPerSubject() { + return (float) numberOfUniquePredicates()/ (float) numberOfUniqueSubjects(); + } + + public float averageNumberOfObjectsPerPredicate() { + return (float) numberOfUniqueObjects()/ (float) numberOfUniquePredicates(); + } + + public String getRoot() { + return root; + } + + private boolean containsHashedTriple(RDFTriple triple) { + String subject = triple.getSubject(); + String predicate = triple.getPredicate(); + String object = triple.getObject(); + + boolean subject_exists = subject_layer.containsKey(subject); + + if (subject_exists) { + ArrayList predicateTrees = predicate_tree_layer.get(subject); + + for (PredicateTree predicateTree: predicateTrees) { + if (predicateTree.getPredicate().equals(predicate)) { + return predicateTree.getObject_list().getList().contains(object); + } + } + } + + return false; + } + + public Path getPathForTriple(RDFTriple triple) { + String subject = triple.getSubject(); + String predicate = triple.getPredicate(); + String object = triple.getObject(); + + RDFTriple hashed_triple = new RDFTriple(DigestUtils.sha256Hex(subject), DigestUtils.sha256Hex(predicate), DigestUtils.sha256Hex(object)); + return getPath(hashed_triple); + } + + public ArrayList get(String subject, String predicate, String object) { + if (subject == null && predicate == null && object == null) { + return null; + } else if (subject != null && predicate == null && object == null) { + return getTriplesUsingSubject(subject); + } else if (subject != null && predicate == null && object != null) { + return getTriplesUsingSubjectAndObject(subject, object); + } else if (subject != null && predicate != null && object == null) { + return getTriplesUsingSubjectAndPredicate(subject, predicate); + } else if (subject == null && predicate != null && object == null) { + return getTriplesUsingPredicate(predicate); + } else if (subject == null && predicate != null && object != null) { + return getTriplesUsingPredicateAndObject(predicate, object); + } else if (subject == null && predicate == null && object != null) { + return getTriplesUsingObject(object); + } + + ArrayList triples = new ArrayList<>(); + RDFTriple triple = new RDFTriple(subject, predicate, object); + triples.add(triple); + return triples; + } + + private ArrayList getTriplesUsingSubjectAndObject(String subject, String object) { + ArrayList predicateTrees = predicate_tree_layer.get(subject); + + if (predicateTrees != null) { + ArrayList triples = new ArrayList<>(); + + for (PredicateTree predicateTree: predicateTrees) { + String predicate = predicateTree.getPredicate(); + + for (String current_object: predicateTree.getObject_list().getList()) { + if (current_object.equals(object)) { + RDFTriple triple = new RDFTriple(subject, predicate, object); + triples.add(triple); + break; + } + } + } + + return triples; + } + + return null; + } + + private ArrayList getTriplesUsingObject(String object) { + ArrayList triples = new ArrayList<>(); + + for (String subject: predicate_tree_layer.keySet()) { + for (PredicateTree predicateTree: predicate_tree_layer.get(subject)) { + for (String current_object: predicateTree.getObject_list().getList()) { + if (current_object.equals(object)) { + RDFTriple triple = new RDFTriple(subject, predicateTree.getPredicate(), object); + triples.add(triple); + break; + } + } + } + } + + return triples; + } + + private ArrayList getTriplesUsingPredicateAndObject(String predicate, String object) { + ArrayList triples = new ArrayList<>(); + + for (String subject: predicate_tree_layer.keySet()) { + for (PredicateTree predicateTree: predicate_tree_layer.get(subject)) { + String current_predicate = predicateTree.getPredicate(); + + if (current_predicate.equals(predicate)) { + for (String current_object: predicateTree.getObject_list().getList()) { + if (current_object.equals(object)) { + RDFTriple triple = new RDFTriple(subject, predicate, object); + triples.add(triple); + break; + } + } + break; + } + } + } + + return triples; + } + + private ArrayList getTriplesUsingPredicate(String predicate) { + ArrayList triples = new ArrayList<>(); + + for (String subject: predicate_tree_layer.keySet()) { + for (PredicateTree predicateTree: predicate_tree_layer.get(subject)) { + String current_predicate = predicateTree.getPredicate(); + + if (current_predicate.equals(predicate)) { + for (String object: predicateTree.getObject_list().getList()) { + RDFTriple triple = new RDFTriple(subject, predicate, object); + triples.add(triple); + } + break; + } + } + } + + return triples; + } + + private ArrayList getTriplesUsingSubjectAndPredicate(String subject, String predicate) { + ArrayList predicateTrees = predicate_tree_layer.get(subject); + + if (predicateTrees != null) { + ArrayList triples = new ArrayList<>(); + + for (PredicateTree predicateTree: predicateTrees) { + String current_predicate = predicateTree.getPredicate(); + + if (predicate.equals(current_predicate)) { + for (String object : predicateTree.getObject_list().getList()) { + RDFTriple triple = new RDFTriple(subject, predicate, object); + triples.add(triple); + } + + return triples; + } + } + } + + return null; + } + + private ArrayList getTriplesUsingSubject(String subject) { + ArrayList predicateTrees = predicate_tree_layer.get(subject); + + if (predicateTrees != null) { + ArrayList triples = new ArrayList<>(); + + for (PredicateTree predicateTree: predicateTrees) { + String predicate = predicateTree.getPredicate(); + + for (String object: predicateTree.getObject_list().getList()) { + RDFTriple triple = new RDFTriple(subject, predicate, object); + triples.add(triple); + } + } + + return triples; + } + + return null; + } + + public Path getPathForHashedTriple(RDFTriple triple) { + return getPath(triple); + } + + private Path getPath(RDFTriple triple) { + String subject = triple.getSubject(); + String predicate = triple.getPredicate(); + String object = triple.getObject(); + + if (containsHashedTriple(triple)) { + ArrayList subject_list = new ArrayList<>(subject_layer.keySet()); + ArrayList subject_children_hashes = new ArrayList<>(subject_layer.values()); + int index_of_subject = subject_list.indexOf(subject); + subject_list.remove(subject); + subject_children_hashes.remove(index_of_subject); + + ArrayList subject_siblings = new ArrayList<>(); + + for (int i = 0; i < subject_list.size(); i++) { + subject_siblings.add(new HashTuple(subject_list.get(i), subject_children_hashes.get(i))); + } + + ArrayList predicate_list = new ArrayList<>(); + ArrayList predicate_children_hashes = new ArrayList<>(); + ArrayList object_list = null; + + for (PredicateTree predicate_tree: predicate_tree_layer.get(subject)) { + predicate_list.add(predicate_tree.getPredicate()); + predicate_children_hashes.add(predicate_tree.getChildren_hash()); + if (predicate_tree.getPredicate().equals(predicate)) { + object_list = predicate_tree.getObject_list().getList(); + } + } + + int index_of_predicate = predicate_list.indexOf(predicate); + predicate_list.remove(predicate); + predicate_children_hashes.remove(index_of_predicate); + + ArrayList predicate_siblings = new ArrayList<>(); + for (int i = 0; i < predicate_list.size(); i++) { + predicate_siblings.add(new HashTuple(predicate_list.get(i), predicate_children_hashes.get(i))); + } + + int index_of_object = object_list.indexOf(object); + object_list.remove(object); + + return new Path(subject_siblings, predicate_siblings, object_list, index_of_subject, index_of_predicate, index_of_object); + } + + return null; + } + + public boolean doesTripleExist(RDFTriple triple, String root, Path path) { + String subject = triple.getSubject(); + String predicate = triple.getPredicate(); + String object = triple.getObject(); + + RDFTriple hashed_triple = new RDFTriple(DigestUtils.sha256Hex(subject), DigestUtils.sha256Hex(predicate), DigestUtils.sha256Hex(object)); + return doesHashedTripleExist(hashed_triple, root, path); + } + + public boolean doesHashedTripleExist(RDFTriple triple, String root, Path path) { + String subject = triple.getSubject(); + String predicate = triple.getPredicate(); + String object = triple.getObject(); + + ArrayList object_list = path.getObject_siblings(); + ArrayList predicate_list = path.getPredicate_siblings(); + ArrayList subject_list = path.getSubject_siblings(); + + object_list.add(path.getObject_index(), object); + String predicate_children_hash = getDigest(object_list); + predicate_list.add(path.getPredicate_index(), new HashTuple(predicate, predicate_children_hash)); + + String subject_children_hash = getHashTupleListDigest(predicate_list); + subject_list.add(path.getSubject_index(), new HashTuple(subject, subject_children_hash)); + + String reconstructed_root = getHashTupleListDigest(subject_list); + + return root.equals(reconstructed_root); + } + + public void printAdjacencyList() { + for (String subject: adjacency_lists.keySet()) { + System.out.println("Subject: " + subject); + + for (String predicate: adjacency_lists.get(subject).keySet()) { + System.out.println("\t\tPredicate: " + predicate); + + for (String object: adjacency_lists.get(subject).get(predicate)) { + System.out.println("\t\t\t\tObject: " + object); + } + } + } + } + + public void printTree(int start, int end) { + if (start == -1 || start > subject_layer.keySet().size()) { + start = subject_layer.keySet().size()-1; + } + + if (end == -1 || end > subject_layer.keySet().size()) { + end = subject_layer.keySet().size()-1; + } + + int index = 0; + System.out.println("Root: " + root); + for (String subject: subject_layer.keySet()) { + if (index >= start) { + printSubjectTree(subject, index); + } + if (index == end) { + break; + } + index++; + } + } + + public void printSubjectTree(String subject, int index) { + System.out.println("Subject " + index + ": (" + subject + ", " + subject_layer.get(subject) + ")"); + + for (int i = 0; i < predicate_tree_layer.get(subject).size(); i++) { + predicate_tree_layer.get(subject).get(i).print(2, i); + } + } + + public void setRoot(String root) { + this.root = root; + } + + public HashMap getSubject_layer() { + return subject_layer; + } + + public void setSubject_layer(HashMap subject_layer) { + this.subject_layer = subject_layer; + } + + public HashMap> getPredicate_tree_layer() { + return predicate_tree_layer; + } + + public void setPredicate_tree_layer(HashMap> predicate_tree_layer) { + this.predicate_tree_layer = predicate_tree_layer; + } + + public RDFTriple[] getTriples() { + return triples; + } + + public double getSubjectToTriplesRatio() { + return (double) numberOfUniqueSubjects()/ (double) nb_triples; + } + + public int getInitial_capacity() { + return initial_capacity; + } + + public int getNumberOfRedundantTriples() { + int i = 9; + + for (String subject: predicate_tree_layer.keySet()) { + for (PredicateTree predicate_tree: predicate_tree_layer.get(subject)) { + i+=predicate_tree.getObject_list().getList().size()-1; + } + } + + return i; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/HashTuple.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/HashTuple.java new file mode 100644 index 0000000000..10d8747cd9 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/HashTuple.java @@ -0,0 +1,35 @@ +package ch.unifr.digits.webprotege.attestation.server.compression.tree; + +public class HashTuple { + private String elementHash; + private String childrenHash; + + public HashTuple(String elementHash, String childrenHash) { + this.elementHash = elementHash; + this.childrenHash = childrenHash; + } + + public String getElementHash() { + return elementHash; + } + + public void setElementHash(String elementHash) { + this.elementHash = elementHash; + } + + public String getChildrenHash() { + return childrenHash; + } + + public void setChildrenHash(String childrenHash) { + this.childrenHash = childrenHash; + } + + @Override + public String toString() { + return "implementation.HashTuple{" + + "elementHash='" + elementHash + '\'' + + ", childrenHash='" + childrenHash + '\'' + + '}'; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/OWLToRDFTranslator.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/OWLToRDFTranslator.java new file mode 100644 index 0000000000..997beffbb8 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/OWLToRDFTranslator.java @@ -0,0 +1,95 @@ +package ch.unifr.digits.webprotege.attestation.server.compression.tree; + +import org.semanticweb.owlapi.formats.NTriplesDocumentFormat; +import org.semanticweb.owlapi.model.OWLOntology; +import org.semanticweb.owlapi.model.OWLOntologyStorageException; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.StringTokenizer; + +public class OWLToRDFTranslator { + + private RDFTriple[] triples; + + public OWLToRDFTranslator(OWLOntology ontology) throws OWLOntologyStorageException { + translate(ontology); + } + + private void translate(OWLOntology ontology) throws OWLOntologyStorageException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ontology.saveOntology(new NTriplesDocumentFormat(), out); + + byte[] buf = out.toByteArray(); + char[] file = byteArrayToCharArray(buf); + ArrayList lines = removeComments(getLines(file)); + + this.triples = linesToTriples(lines); + } + + private ArrayList getLines(char[] file) { + ArrayList lines = new ArrayList<>(); + String file_as_string = String.copyValueOf(file); + StringTokenizer tokenizer = new StringTokenizer(file_as_string, "\n"); + while (tokenizer.hasMoreTokens()) { + lines.add(tokenizer.nextToken()); + } + return lines; + } + + private ArrayList removeComments(ArrayList lines) { + ArrayList linesNoComments = new ArrayList<>(); + + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + if (line.charAt(0) != '#') { + linesNoComments.add(line); + } + } + + return linesNoComments; + } + + + private char[] byteArrayToCharArray(byte[] buf) { + char[] arr = new char[buf.length]; + for (int i = 0; i < buf.length; i++) { + arr[i] = (char) buf[i]; + } + return arr; + } + + private RDFTriple[] linesToTriples(ArrayList lines) { + RDFTriple[] triples = new RDFTriple[lines.size()]; + + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + StringTokenizer tokenizer = new StringTokenizer(line, " "); + String subject = tokenizer.nextToken(); + String predicate = tokenizer.nextToken(); + + // Compute the "object" as the rest of the string (without including the '.' at the end) + StringBuilder sb = new StringBuilder(); + + while (tokenizer.hasMoreTokens()) { + sb.append(tokenizer.nextToken()); + } + + sb.deleteCharAt(sb.length()-1); + String object = sb.toString(); + + RDFTriple triple = new RDFTriple(subject, predicate, object); + triples[i] = triple; + } + + return triples; + } + + public RDFTriple[] getTriples() { + return triples; + } + + public void setTriples(RDFTriple[] triples) { + this.triples = triples; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/ObjectList.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/ObjectList.java new file mode 100644 index 0000000000..e9cc3d6d75 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/ObjectList.java @@ -0,0 +1,56 @@ +package ch.unifr.digits.webprotege.attestation.server.compression.tree; + +import org.apache.commons.codec.digest.DigestUtils; + +import java.util.ArrayList; + +public class ObjectList { + private ArrayList list; + + + public ObjectList(ArrayList list) { + this.list = list; + } + + public ObjectList(String object) { + ArrayList object_list = new ArrayList<>(); + object_list.add(object); + this.list = object_list; + } + + public String getDigest() { + StringBuilder sb = new StringBuilder(); + + for (String element : list) { + sb.append(element); + } + + return DigestUtils.sha256Hex(sb.toString()); + } + + public ArrayList getList() { + return list; + } + + public void setList(ArrayList list) { + this.list = list; + } + + public boolean contains(String object) { + return list.contains(object); + } + + private String getIndentedString(int nb_indents) { + StringBuilder sb = new StringBuilder(); + + sb.append("\t".repeat(Math.max(0, nb_indents))); + + return sb.toString(); + } + + public void print(int nb_indents) { + for (int i = 0; i < list.size(); i++) { + System.out.println(getIndentedString(nb_indents) + "Object " + i + ": " + list.get(i)); + } + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/Path.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/Path.java new file mode 100644 index 0000000000..2253062127 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/Path.java @@ -0,0 +1,59 @@ +package ch.unifr.digits.webprotege.attestation.server.compression.tree; + +import java.util.ArrayList; + +public class Path { + + private ArrayList subject_siblings; + private ArrayList predicate_siblings; + private ArrayList object_siblings; + + private int subject_index; + private int predicate_index; + private int object_index; + + public Path(ArrayList subject_siblings, ArrayList predicate_siblings, ArrayList object_siblings, int subject_index, int predicate_index, int object_index) { + this.subject_siblings = subject_siblings; + this.predicate_siblings = predicate_siblings; + this.object_siblings = object_siblings; + this.subject_index = subject_index; + this.predicate_index = predicate_index; + this.object_index = object_index; + } + + public ArrayList getObject_siblings() { + return object_siblings; + } + + public int getObject_index() { + return object_index; + } + + public int getPredicate_index() { + return predicate_index; + } + + public int getSubject_index() { + return subject_index; + } + + public ArrayList getSubject_siblings() { + return subject_siblings; + } + + public ArrayList getPredicate_siblings() { + return predicate_siblings; + } + + @Override + public String toString() { + return "implementation.Path{" + + "subject_siblings=" + subject_siblings + + ", predicate_siblings=" + predicate_siblings + + ", object_siblings=" + object_siblings + + ", subject_index=" + subject_index + + ", predicate_index=" + predicate_index + + ", object_index=" + object_index + + '}'; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/PredicateTree.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/PredicateTree.java new file mode 100644 index 0000000000..afefccd052 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/PredicateTree.java @@ -0,0 +1,60 @@ +package ch.unifr.digits.webprotege.attestation.server.compression.tree; + +import org.apache.commons.codec.digest.DigestUtils; + +public class PredicateTree { + private String predicate; + private String children_hash; + private ObjectList object_list; + + public PredicateTree(String predicate, ObjectList object_list) { + this.predicate = predicate; + this.children_hash = object_list.getDigest(); + this.object_list = object_list; + } + + public void updateChildrenHash() { + children_hash = object_list.getDigest(); + } + + public String getDigest() { + return DigestUtils.sha256Hex(predicate+children_hash); + } + + public String getPredicate() { + return predicate; + } + + public void setPredicate(String predicate) { + this.predicate = predicate; + } + + public String getChildren_hash() { + return children_hash; + } + + public void setChildren_hash(String children_hash) { + this.children_hash = children_hash; + } + + public ObjectList getObject_list() { + return object_list; + } + + public void setObject_list(ObjectList object_list) { + this.object_list = object_list; + } + + private String getIndentationString(int nb_indents) { + StringBuilder sb = new StringBuilder(); + + sb.append("\t".repeat(Math.max(0, nb_indents))); + + return sb.toString(); + } + + public void print(int nb_indents, int index) { + System.out.println(getIndentationString(nb_indents) + "Predicate " + index + ": (" + predicate + ", " + children_hash + ")"); + object_list.print(nb_indents+2); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/RDFTriple.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/RDFTriple.java new file mode 100644 index 0000000000..dd4e4b7021 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/compression/tree/RDFTriple.java @@ -0,0 +1,46 @@ +package ch.unifr.digits.webprotege.attestation.server.compression.tree; + +public class RDFTriple { + private String subject; + private String predicate; + private String object; + + public RDFTriple(String subject, String predicate, String object) { + this.subject = subject; + this.predicate = predicate; + this.object = object; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getPredicate() { + return predicate; + } + + public void setPredicate(String predicate) { + this.predicate = predicate; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + @Override + public String toString() { + return "implementation.RDFTriple{" + + "subject='" + subject + '\'' + + ", predicate='" + predicate + '\'' + + ", object='" + object + '\'' + + '}'; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/ChangeTracking.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/ChangeTracking.java new file mode 100644 index 0000000000..ad499961da --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/ChangeTracking.java @@ -0,0 +1,132 @@ +package ch.unifr.digits.webprotege.attestation.server.contracts; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.Address; +import org.web3j.abi.datatypes.Bool; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.Utf8String; +import org.web3j.abi.datatypes.generated.Uint256; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tuples.generated.Tuple4; +import org.web3j.tx.Contract; +import org.web3j.tx.TransactionManager; +import org.web3j.tx.gas.ContractGasProvider; + +/** + *

Auto generated code. + *

Do not modify! + *

Please use the web3j command line tools, + * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the + * codegen module to update. + * + *

Generated with web3j version 4.7.0. + */ +@SuppressWarnings("rawtypes") +public class ChangeTracking extends Contract { + public static final String BINARY = "Bin file was not provided"; + + public static final String FUNC_ATTEST = "attest"; + + public static final String FUNC_VERIFY = "verify"; + + public static final String FUNC_VERIFYENTITY = "verifyEntity"; + + @Deprecated + protected ChangeTracking(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + protected ChangeTracking(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, credentials, contractGasProvider); + } + + @Deprecated + protected ChangeTracking(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + protected ChangeTracking(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); + } + + public RemoteFunctionCall attest(String ontologyIri, String versionIri, String name, String hash, List classHashes) { + final Function function = new Function( + FUNC_ATTEST, + Arrays.asList(new org.web3j.abi.datatypes.Utf8String(ontologyIri), + new org.web3j.abi.datatypes.Utf8String(versionIri), + new org.web3j.abi.datatypes.Utf8String(name), + new org.web3j.abi.datatypes.Utf8String(hash), + new org.web3j.abi.datatypes.DynamicArray( + org.web3j.abi.datatypes.generated.Int256.class, + org.web3j.abi.Utils.typeMap(classHashes, org.web3j.abi.datatypes.generated.Int256.class))), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall> verify(String ontologyIri, String versionIri, String hash) { + final Function function = new Function(FUNC_VERIFY, + Arrays.asList(new org.web3j.abi.datatypes.Utf8String(ontologyIri), + new org.web3j.abi.datatypes.Utf8String(versionIri), + new org.web3j.abi.datatypes.Utf8String(hash)), + Arrays.>asList(new TypeReference() {}, new TypeReference

() {}, new TypeReference() {}, new TypeReference() {})); + return new RemoteFunctionCall>(function, + new Callable>() { + @Override + public Tuple4 call() throws Exception { + List results = executeCallMultipleValueReturn(function); + return new Tuple4( + (Boolean) results.get(0).getValue(), + (String) results.get(1).getValue(), + (String) results.get(2).getValue(), + (BigInteger) results.get(3).getValue()); + } + }); + } + + public RemoteFunctionCall> verifyEntity(String ontologyIri, String versionIri, BigInteger entityHash) { + final Function function = new Function(FUNC_VERIFYENTITY, + Arrays.asList(new org.web3j.abi.datatypes.Utf8String(ontologyIri), + new org.web3j.abi.datatypes.Utf8String(versionIri), + new org.web3j.abi.datatypes.generated.Int256(entityHash)), + Arrays.>asList(new TypeReference() {}, new TypeReference
() {}, new TypeReference() {}, new TypeReference() {})); + return new RemoteFunctionCall>(function, + new Callable>() { + @Override + public Tuple4 call() throws Exception { + List results = executeCallMultipleValueReturn(function); + return new Tuple4( + (Boolean) results.get(0).getValue(), + (String) results.get(1).getValue(), + (String) results.get(2).getValue(), + (BigInteger) results.get(3).getValue()); + } + }); + } + + @Deprecated + public static ChangeTracking load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return new ChangeTracking(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static ChangeTracking load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new ChangeTracking(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static ChangeTracking load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + return new ChangeTracking(contractAddress, web3j, credentials, contractGasProvider); + } + + public static ChangeTracking load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new ChangeTracking(contractAddress, web3j, transactionManager, contractGasProvider); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/OntologyAttestation.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/OntologyAttestation.java new file mode 100644 index 0000000000..d02c6019bc --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/OntologyAttestation.java @@ -0,0 +1,107 @@ +package ch.unifr.digits.webprotege.attestation.server.contracts; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.Address; +import org.web3j.abi.datatypes.Bool; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.Utf8String; +import org.web3j.abi.datatypes.generated.Uint256; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tuples.generated.Tuple4; +import org.web3j.tx.Contract; +import org.web3j.tx.TransactionManager; +import org.web3j.tx.gas.ContractGasProvider; + +/** + *

Auto generated code. + *

Do not modify! + *

Please use the web3j command line tools, + * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the + * codegen module to update. + * + *

Generated with web3j version 4.7.0. + */ +@SuppressWarnings("rawtypes") +public class OntologyAttestation extends Contract { + public static final String BINARY = "Bin file was not provided"; + + public static final String FUNC_ATTEST = "attest"; + + public static final String FUNC_VERIFY = "verify"; + + @Deprecated + protected OntologyAttestation(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + protected OntologyAttestation(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, credentials, contractGasProvider); + } + + @Deprecated + protected OntologyAttestation(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + protected OntologyAttestation(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); + } + + public RemoteFunctionCall attest(String ontologyIri, String versionIri, String name, String hash) { + final Function function = new Function( + FUNC_ATTEST, + Arrays.asList(new org.web3j.abi.datatypes.Utf8String(ontologyIri), + new org.web3j.abi.datatypes.Utf8String(versionIri), + new org.web3j.abi.datatypes.Utf8String(name), + new org.web3j.abi.datatypes.Utf8String(hash)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall> verify(String ontologyIri, String versionIri, String hash) { + final Function function = new Function(FUNC_VERIFY, + Arrays.asList(new org.web3j.abi.datatypes.Utf8String(ontologyIri), + new org.web3j.abi.datatypes.Utf8String(versionIri), + new org.web3j.abi.datatypes.Utf8String(hash)), + Arrays.>asList(new TypeReference() {}, new TypeReference

() {}, new TypeReference() {}, new TypeReference() {})); + return new RemoteFunctionCall>(function, + new Callable>() { + @Override + public Tuple4 call() throws Exception { + List results = executeCallMultipleValueReturn(function); + return new Tuple4( + (Boolean) results.get(0).getValue(), + (String) results.get(1).getValue(), + (String) results.get(2).getValue(), + (BigInteger) results.get(3).getValue()); + } + }); + } + + @Deprecated + public static OntologyAttestation load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return new OntologyAttestation(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static OntologyAttestation load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new OntologyAttestation(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static OntologyAttestation load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + return new OntologyAttestation(contractAddress, web3j, credentials, contractGasProvider); + } + + public static OntologyAttestation load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new OntologyAttestation(contractAddress, web3j, transactionManager, contractGasProvider); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/Storage.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/Storage.java new file mode 100644 index 0000000000..aca4623704 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/server/contracts/Storage.java @@ -0,0 +1,85 @@ +package ch.unifr.digits.contracts; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.generated.Uint256; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tx.Contract; +import org.web3j.tx.TransactionManager; +import org.web3j.tx.gas.ContractGasProvider; + +/** + *

Auto generated code. + *

Do not modify! + *

Please use the web3j command line tools, + * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the + * codegen module to update. + * + *

Generated with web3j version 4.7.0. + */ +@SuppressWarnings("rawtypes") +public class Storage extends Contract { + public static final String BINARY = "Bin file was not provided"; + + public static final String FUNC_RETRIEVE = "retrieve"; + + public static final String FUNC_STORE = "store"; + + @Deprecated + protected Storage(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + protected Storage(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, credentials, contractGasProvider); + } + + @Deprecated + protected Storage(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + protected Storage(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); + } + + public RemoteFunctionCall retrieve() { + final Function function = new Function(FUNC_RETRIEVE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, BigInteger.class); + } + + public RemoteFunctionCall store(BigInteger num) { + final Function function = new Function( + FUNC_STORE, + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + @Deprecated + public static Storage load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return new Storage(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static Storage load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new Storage(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static Storage load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + return new Storage(contractAddress, web3j, credentials, contractGasProvider); + } + + public static Storage load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new Storage(contractAddress, web3j, transactionManager, contractGasProvider); + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetAttestationSettingsAction.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetAttestationSettingsAction.java new file mode 100644 index 0000000000..2931e34b43 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetAttestationSettingsAction.java @@ -0,0 +1,7 @@ +package ch.unifr.digits.webprotege.attestation.shared; + +import edu.stanford.bmir.protege.web.shared.dispatch.Action; + +public class GetAttestationSettingsAction implements Action { + public GetAttestationSettingsAction() {} +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetAttestationSettingsActionResult.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetAttestationSettingsActionResult.java new file mode 100644 index 0000000000..aedf1f1728 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetAttestationSettingsActionResult.java @@ -0,0 +1,24 @@ +package ch.unifr.digits.webprotege.attestation.shared; + +import edu.stanford.bmir.protege.web.shared.dispatch.Result; + +public class GetAttestationSettingsActionResult implements Result { + + private String addressChangeContract; + private String addressOntologyContract; + + public GetAttestationSettingsActionResult() {} + + public GetAttestationSettingsActionResult(String addressChangeContract, String addressOntologyContract) { + this.addressChangeContract = addressChangeContract; + this.addressOntologyContract = addressOntologyContract; + } + + public String getAddressChangeContract() { + return addressChangeContract; + } + + public String getAddressOntologyContract() { + return addressOntologyContract; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetProjectOntologyIdAction.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetProjectOntologyIdAction.java new file mode 100644 index 0000000000..08afe8d5f4 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetProjectOntologyIdAction.java @@ -0,0 +1,20 @@ +package ch.unifr.digits.webprotege.attestation.shared; + +import edu.stanford.bmir.protege.web.shared.dispatch.ProjectAction; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; + +public class GetProjectOntologyIdAction implements ProjectAction { + + private ProjectId projectId; + + protected GetProjectOntologyIdAction() { + } + + public GetProjectOntologyIdAction(ProjectId projectId) { + this.projectId = projectId; + } + + public ProjectId getProjectId() { + return projectId; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetProjectOntologyIdResult.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetProjectOntologyIdResult.java new file mode 100644 index 0000000000..67d6db408c --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/GetProjectOntologyIdResult.java @@ -0,0 +1,21 @@ +package ch.unifr.digits.webprotege.attestation.shared; + +import edu.stanford.bmir.protege.web.shared.dispatch.Result; +import org.semanticweb.owlapi.model.OWLOntologyID; + +import java.util.Set; + +public class GetProjectOntologyIdResult implements Result { + private Set ontologyIDs; + + protected GetProjectOntologyIdResult() { + } + + public GetProjectOntologyIdResult(Set ontologyIDs) { + this.ontologyIDs = ontologyIDs; + } + + public Set getOntologyIDs() { + return ontologyIDs; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/OntologyHashAction.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/OntologyHashAction.java new file mode 100644 index 0000000000..087b7893eb --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/OntologyHashAction.java @@ -0,0 +1,28 @@ +package ch.unifr.digits.webprotege.attestation.shared; + +import edu.stanford.bmir.protege.web.shared.dispatch.AbstractHasProjectAction; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; + +public class OntologyHashAction extends AbstractHasProjectAction { + private String iri; + + /** + * For serialization purposes only + */ + protected OntologyHashAction() { + + } + + public OntologyHashAction(ProjectId projectId, String iri) { + super(projectId); + this.iri = iri; + } + + public String getIri() { + return iri; + } + + public void setIri(String iri) { + this.iri = iri; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/OntologyHashResult.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/OntologyHashResult.java new file mode 100644 index 0000000000..4b5fbfab6a --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/OntologyHashResult.java @@ -0,0 +1,31 @@ +package ch.unifr.digits.webprotege.attestation.shared; + +import edu.stanford.bmir.protege.web.shared.dispatch.Result; + +import java.util.List; + +public class OntologyHashResult implements Result { + private String hash; + private List classHashes; + private int entitySetHash; + + public OntologyHashResult() {} + + public OntologyHashResult(String hash, int entitySetHash, List classHashes) { + this.hash = hash; + this.entitySetHash = entitySetHash; + this.classHashes = classHashes; + } + + public String getHash() { + return hash; + } + + public List getClassHashes() { + return classHashes; + } + + public int getEntitySetHash() { + return entitySetHash; + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/VerifyAction.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/VerifyAction.java new file mode 100644 index 0000000000..84eb3e85d3 --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/VerifyAction.java @@ -0,0 +1,81 @@ +package ch.unifr.digits.webprotege.attestation.shared; + +import edu.stanford.bmir.protege.web.shared.dispatch.ProjectAction; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; +import org.semanticweb.owlapi.model.OWLEntity; + +import javax.annotation.Nonnull; + +public class VerifyAction implements ProjectAction { + private ProjectId projectId; + private String iri; + private String versionIri; + private String hash; + private OWLEntity entity; + private Mode mode; + + /** + * For serialization purposes only + */ + public VerifyAction() { + } + + public VerifyAction(ProjectId projectId, String iri, String versionIri, String hash, OWLEntity entity, Mode mode) { + this.projectId = projectId; + this.iri = iri; + this.versionIri = versionIri; + this.hash = hash; + this.entity = entity; + this.mode = mode; + } + + public String getIri() { + return iri; + } + + public void setIri(String iri) { + this.iri = iri; + } + + public String getVersionIri() { + return versionIri; + } + + public void setVersionIri(String versionIri) { + this.versionIri = versionIri; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + @Override + public ProjectId getProjectId() { + return projectId; + } + + public OWLEntity getEntity() { + return entity; + } + + public void setEntity(OWLEntity entity) { + this.entity = entity; + } + + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + public enum Mode { + ONTOLOGY, + ENTITY + } +} diff --git a/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/VerifyResult.java b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/VerifyResult.java new file mode 100644 index 0000000000..d8e5e0f66e --- /dev/null +++ b/webprotege-attestation-lib/src/main/java/ch/unifr/digits/webprotege/attestation/shared/VerifyResult.java @@ -0,0 +1,45 @@ +package ch.unifr.digits.webprotege.attestation.shared; + +import edu.stanford.bmir.protege.web.shared.dispatch.Result; + +public class VerifyResult implements Result { + private boolean valid; + private String signer; + private String signerName; + private int timestamp; + + public VerifyResult() {} + + public VerifyResult(boolean valid, String signer, String signerName, int timestamp) { + this.valid = valid; + this.signer = signer; + this.signerName = signerName; + this.timestamp = timestamp; + } + + public boolean isValid() { + return valid; + } + + public String getSigner() { + return signer; + } + + public String getSignerName() { + return signerName; + } + + public int getTimestamp() { + return timestamp; + } + + @Override + public String toString() { + return "VerifyResult{" + + "valid=" + valid + + ", signer='" + signer + '\'' + + ", signerName='" + signerName + '\'' + + ", timestamp=" + timestamp + + '}'; + } +} diff --git a/webprotege-attestation-lib/src/main/module.gwt.xml b/webprotege-attestation-lib/src/main/module.gwt.xml new file mode 100644 index 0000000000..3eb877bf8e --- /dev/null +++ b/webprotege-attestation-lib/src/main/module.gwt.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webprotege-attestation-lib/src/main/resources/configuration/config.properties b/webprotege-attestation-lib/src/main/resources/configuration/config.properties new file mode 100644 index 0000000000..d274df7aac --- /dev/null +++ b/webprotege-attestation-lib/src/main/resources/configuration/config.properties @@ -0,0 +1,10 @@ +PROVIDER_HOST=http://localhost +PROVIDER_PORT=8545 +#Ganache +ADDRESS_ATTESTATION=0x6a8F5Ef06D06137b5aBDc14201343dF54dcfDBDC +#Roposten +#ADDRESS_ATTESTATION=0x7b5711E07213FD5e25b8D35ed64DD4c3525C454b +#Mainnet +#ADDRESS_ATTESTATION=0x7b5711e07213fd5e25b8d35ed64dd4c3525c454b +ADDRESS_CHANGETRACKING=0x41c293160913d7cD816093D702e2dDA7391A3976 +SERVER_SECRET=0x2fe929a15797d2170c063b758dee33b55ad7c13313c110b675d3a9709fe83797 diff --git a/webprotege-attestation-lib/src/main/solidity/change-tracking.sol b/webprotege-attestation-lib/src/main/solidity/change-tracking.sol new file mode 100644 index 0000000000..ed534bb7cc --- /dev/null +++ b/webprotege-attestation-lib/src/main/solidity/change-tracking.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >= 0.7.1; + +contract ChangeTracking { + + struct Attestation { + address signer; + string name; + uint timestamp; + string hash; + ClassSignatures classes; + } + + struct ClassSignatures { + int[] classHashes; + } + + mapping (string => Attestation) internal store; + + function attest(string calldata ontologyIri, string calldata versionIri, string calldata name, string calldata hash, int[] calldata classHashes) public { + require(bytes(ontologyIri).length > 0, "IRI required"); + require(bytes(name).length > 0, "Name required"); + require(bytes(hash).length > 0, "Ontology hash required"); + + string memory id = getId(ontologyIri, versionIri); + ClassSignatures memory classes = ClassSignatures(classHashes); + Attestation memory newAttestation = Attestation(msg.sender, name, block.timestamp, hash, classes); + store[id] = newAttestation; + } + + function verify(string calldata ontologyIri, string calldata versionIri, string calldata hash) public view + returns (bool valid, address signer, string memory signerName, uint timestamp) { + string memory id = getId(ontologyIri, versionIri); + Attestation memory attestation = store[id]; + if (attestation.signer != address(0x0) && strHashEqual(attestation.hash, hash)) { + return (true, attestation.signer, attestation.name, attestation.timestamp); + } + return (false, address(0x0), "", 0); + } + + function verifyEntity(string calldata ontologyIri, string calldata versionIri, int entityHash) public view + returns (bool valid, address signer, string memory signerName, uint timestamp) { + string memory id = getId(ontologyIri, versionIri); + Attestation memory attestation = store[id]; + int[] memory array = attestation.classes.classHashes; + for (uint i = 0; i < array.length; i++ ) { + if (array[i] == entityHash) return (true, attestation.signer, attestation.name, attestation.timestamp); + } + return (false, address(0x0), "", 0); + } + + function strHashEqual(string memory a, string calldata b) internal pure returns (bool) { + if(bytes(a).length != bytes(b).length) { + return false; + } else { + return keccak256(abi.encode(a)) == keccak256(abi.encode(b)); + } + } + + function getId(string calldata ontologyIri, string calldata versionIri) internal pure returns(string memory) { + return string(abi.encodePacked(ontologyIri, versionIri)); + } +} \ No newline at end of file diff --git a/webprotege-attestation-lib/src/main/solidity/ontology-attestation.sol b/webprotege-attestation-lib/src/main/solidity/ontology-attestation.sol new file mode 100644 index 0000000000..21d2e37fcf --- /dev/null +++ b/webprotege-attestation-lib/src/main/solidity/ontology-attestation.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >= 0.7.1; + +contract OntologyAttestation { + + struct Attestation { + address signer; + string name; + uint timestamp; + string hash; + } + + mapping (string => Attestation) internal store; + + function attest(string calldata ontologyIri, string calldata versionIri, string calldata name, string calldata hash) public { + require(bytes(ontologyIri).length > 0, "IRI required"); + require(bytes(name).length > 0, "Name required"); + require(bytes(hash).length > 0, "Ontology hash required"); + + string memory id = getId(ontologyIri, versionIri); + Attestation memory newAttestation = Attestation(msg.sender, name, block.timestamp, hash); + store[id] = newAttestation; + } + + function verify(string calldata ontologyIri, string calldata versionIri, string calldata hash) public view + returns (bool valid, address signer, string memory signerName, uint timestamp) { + string memory id = getId(ontologyIri, versionIri); + Attestation memory attestation = store[id]; + return verifyHash(attestation, attestation.hash, hash); + } + + function verifyHash(Attestation memory attestation, string memory hashExpected, string calldata hashActual) private pure + returns (bool valid, address signer, string memory signerName, uint timestamp) { + if (attestation.signer != address(0x0) && hashEqual(hashExpected, hashActual)) { + return (true, attestation.signer, attestation.name, attestation.timestamp); + } + return (false, attestation.signer, "", 0); + } + + function hashEqual(string memory a, string calldata b) internal pure returns (bool) { + if(bytes(a).length != bytes(b).length) { + return false; + } else { + return keccak256(abi.encode(a)) == keccak256(abi.encode(b)); + } +} + + function getId(string calldata ontologyIri, string calldata versionIri) internal pure returns(string memory) { + return string(abi.encodePacked(ontologyIri, versionIri)); + } +} \ No newline at end of file diff --git a/webprotege-attestation-lib/src/test/java/ch/unifr/digits/BaseLineTest.java b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/BaseLineTest.java new file mode 100644 index 0000000000..6925293b0a --- /dev/null +++ b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/BaseLineTest.java @@ -0,0 +1,64 @@ +package ch.unifr.digits; + +import ch.unifr.digits.contracts.Storage; +import ch.unifr.digits.webprotege.attestation.server.SettingsManager; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.Web3jService; +import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.protocol.http.HttpService; +import org.web3j.tx.gas.DefaultGasProvider; + +import java.math.BigInteger; +import java.time.Duration; +import java.util.concurrent.ThreadLocalRandom; + +import static ch.unifr.digits.FileSupport.saveMeasurementsSeries; +import static ch.unifr.digits.webprotege.attestation.server.SettingsManager.SERVER_SECRET; + +@Disabled +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class BaseLineTest { + + private static final String CONTRACT_ADDRESS = "0xc1Fb1Cb1A01C4F6B8456DdC3593A8CDA6b536c71"; + private static final int NUM_RUNS = 20; + private static final String RESULTS_DIR = "results/"; + private static final Measurements measurements = new Measurements(); + + private static Storage contract; + + @BeforeAll + public static void beforeAll() throws Exception { + Web3jService web3jService = new HttpService(SettingsManager.PROVIDER_HOST + ":" + SettingsManager.PROVIDER_PORT); + Web3j web3j = Web3j.build(web3jService); + contract = Storage.load(CONTRACT_ADDRESS, web3j, Credentials.create(SERVER_SECRET), + DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT); + } + + @Test + public void test() throws Exception { + for (int i = 0; i < NUM_RUNS; i++) { + BigInteger bigInteger = BigInteger.valueOf(ThreadLocalRandom.current().nextLong(Long.MAX_VALUE)); + int ticket = measurements.begin(); + RemoteFunctionCall call = contract.store(bigInteger); + TransactionReceipt receipt = call.send(); + measurements.finish("transact", ticket); + // gas cost is constant, except for first call + measurements.manualMeasurement("gas", receipt.getGasUsed().longValue()); + System.out.println(receipt.getGasUsed()); + } + + saveMeasurementsSeries(RESULTS_DIR+"baseline-transact.csv", "baseline", + measurements.getSeries("transact") + .stream().map(Duration::toNanos).map(String::valueOf), NUM_RUNS); + saveMeasurementsSeries(RESULTS_DIR+"baseline-gas.csv", "baseline", + measurements.getManualSeries("gas") + .stream().map(String::valueOf), NUM_RUNS); + } + +} diff --git a/webprotege-attestation-lib/src/test/java/ch/unifr/digits/FileSupport.java b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/FileSupport.java new file mode 100644 index 0000000000..c8872b2c18 --- /dev/null +++ b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/FileSupport.java @@ -0,0 +1,43 @@ +package ch.unifr.digits; + +import org.semanticweb.owlapi.apibinding.OWLManager; +import org.semanticweb.owlapi.model.OWLOntology; +import org.semanticweb.owlapi.model.OWLOntologyCreationException; +import org.semanticweb.owlapi.model.OWLOntologyManager; + +import java.io.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class FileSupport { + public static OWLOntology loadOntologyFromResources(String filename) throws OWLOntologyCreationException { + try (InputStream inputStream = FileSupport.class.getClassLoader().getResourceAsStream(filename)) { + OWLOntologyManager ontologyManager = OWLManager.createOWLOntologyManager(); + OWLOntology owlOntology = ontologyManager.loadOntologyFromOntologyDocument(inputStream); + return owlOntology; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void saveMeasurementsSeries(String fname, String id, Stream series, int numRuns) throws Exception { + File file = new File(fname); + String head = null; + if (!file.exists()) { + StringBuffer buffer = new StringBuffer(); + buffer.append("id").append(","); + for (int i = 1; i <= numRuns; i++) { + buffer.append("run_").append(i).append(","); + } + head = buffer.toString(); + } + FileWriter fileWriter = new FileWriter(file, true); + PrintWriter writer = new PrintWriter(fileWriter); + if (head != null) writer.println(head); + + String line = id+","; + line += series.collect(Collectors.joining(",")); + writer.println(line); + writer.close(); + } +} diff --git a/webprotege-attestation-lib/src/test/java/ch/unifr/digits/Measurements.java b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/Measurements.java new file mode 100644 index 0000000000..149ed2633e --- /dev/null +++ b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/Measurements.java @@ -0,0 +1,58 @@ +package ch.unifr.digits; + +import java.time.Duration; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.atomic.AtomicInteger; + +public class Measurements { + + private final AtomicInteger counter = new AtomicInteger(0); + private final Map> series = new HashMap<>(); + private final Map> manualSeries = new HashMap<>(); + private final Map map = new HashMap<>(); + + public int begin() { + int i = counter.getAndIncrement(); + Instant now = Instant.now(); + map.put(i, now); + return i; + } + + public void finish(String seriesName, int measurementId) { + Instant now = Instant.now(); + Instant then = map.remove(measurementId); + if (then == null) return; + Duration duration = Duration.between(then, now); + series.compute(seriesName, (key, list) -> { + if (list == null) list = new ArrayList<>(); + list.add(duration); + return list; + }); + } + + public void manualMeasurement(String seriesName, Long value) { + manualSeries.compute(seriesName, (key, list) -> { + if (list == null) list = new ArrayList<>(); + list.add(value); + return list; + }); + } + + public List getSeries(String seriesName) { + List values = series.get(seriesName); + List list = new ArrayList<>(); + if (values == null) return list; + return Collections.unmodifiableList(values); + } + + public List getManualSeries(String seriesName) { + List values = manualSeries.get(seriesName); + List list = new ArrayList<>(); + if (values == null) return list; + return Collections.unmodifiableList(values); + } + + +} diff --git a/webprotege-attestation-lib/src/test/java/ch/unifr/digits/OntologyLoadTest.java b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/OntologyLoadTest.java new file mode 100644 index 0000000000..bc0fab6830 --- /dev/null +++ b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/OntologyLoadTest.java @@ -0,0 +1,165 @@ +package ch.unifr.digits; + +import ch.unifr.digits.webprotege.attestation.server.OntologyAttestationService; +import org.apache.jasper.tagplugins.jstl.core.Import; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLAnnotation; +import org.semanticweb.owlapi.model.OWLAxiom; +import org.semanticweb.owlapi.model.OWLOntology; +import org.semanticweb.owlapi.model.parameters.Imports; +import org.web3j.protocol.core.methods.response.TransactionReceipt; + +import java.time.Duration; +import java.util.*; + +import static ch.unifr.digits.FileSupport.saveMeasurementsSeries; + +@Disabled +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class OntologyLoadTest { + + private static final int NUM_RUNS = 20; + private static final String RESULTS_DIR = "results/"; + private static final Map testOntologyFiles = new HashMap<>(); + private static final Map loadedOntologies = new HashMap<>(); + private static final Measurements measurements = new Measurements(); + private static final List serviceRunners = new ArrayList<>(); + + static { + testOntologyFiles.put("biomodels", "ontologies/biomodels-21.owl"); + testOntologyFiles.put("dron", "ontologies/dron-full.owl"); + testOntologyFiles.put("gexo", "ontologies/gexo.rdf"); + testOntologyFiles.put("iobc", "ontologies/IOBC_1_4_0.ttl"); + testOntologyFiles.put("rh-mesh", "ontologies/mesh.owl"); + testOntologyFiles.put("ncit", "ontologies/ncit.owl"); + testOntologyFiles.put("nifstd", "ontologies/nif.ttl"); + testOntologyFiles.put("reto", "ontologies/reto.rdf"); + testOntologyFiles.put("rexo", "ontologies/rexo.rdf"); + testOntologyFiles.put("upheno", "ontologies/upheno.owl"); + + serviceRunners.add(new Runner.HashRunner(new OntologyAttestationService(), measurements)); +// serviceRunners.add(new Runner.OntologyAttest(new OntologyAttestationService(), measurements, false)); + } + +// @BeforeAll +// public static void beforeAll() throws Exception { +// for (Map.Entry entry : testOntologyFiles.entrySet()) { +// OWLOntology owlOntology = FileSupport.loadOntologyFromResources(entry.getValue()); +// loadedOntologies.put(entry.getKey(), owlOntology); +// int entities = owlOntology.getSignature(Imports.INCLUDED).size(); +// int classes = owlOntology.getClassesInSignature(Imports.INCLUDED).size(); +// System.out.println(entry.getKey() + "[numEntities="+ entities +"][numClasses=" + classes + "]"); +// } +// } + + @Test + public void batch() throws Exception { + + for (Map.Entry entry : testOntologyFiles.entrySet()) { + OWLOntology owlOntology = loadOntology(entry.getKey(), entry.getValue()); + for (Runner runner : serviceRunners) { + for (int i = 0; i < NUM_RUNS; i++) { + runner.execute(entry.getKey(), owlOntology); + } + saveMeasurementsSeries(RESULTS_DIR+runner.name()+".csv", entry.getKey(), + measurements.getSeries(constructSeriesName(entry.getKey(), runner.name(), "hash")) + .stream().map(Duration::toNanos).map(String::valueOf), NUM_RUNS); +// saveMeasurementsSeries(RESULTS_DIR+runner.name()+"-attest.csv", entry.getKey(), +// measurements.getSeries(constructSeriesName(entry.getKey(), runner.name(), "attest")) +// .stream().map(Duration::toNanos).map(String::valueOf), NUM_RUNS); +// saveMeasurementsSeries(RESULTS_DIR+runner.name()+"-gas.csv", entry.getKey(), +// measurements.getManualSeries(constructSeriesName(entry.getKey(), runner.name(), "gas")) +// .stream().map(String::valueOf), NUM_RUNS); + } + System.gc(); + } + + } + + private static final String constructSeriesName(String id, String serviceName, String tag) { + return id + "-" + serviceName + "-" + tag; + } + + private static OWLOntology loadOntology(String key, String path) throws Exception { + OWLOntology owlOntology = FileSupport.loadOntologyFromResources(path); + int signature = owlOntology.getSignature(Imports.INCLUDED).size(); + int classes = owlOntology.getClassesInSignature(Imports.INCLUDED).size(); + int axioms = owlOntology.getAxioms(Imports.INCLUDED).size(); + int annotations = owlOntology.getAnnotations().size(); + int all = signature+annotations+axioms; + System.out.println(key + "[numAxioms="+ axioms +"][numAnnotations="+ annotations +"][numSignature="+ signature +"][numClasses=" + classes + "][numEntities=" + all + "]"); + return owlOntology; + } + + private interface Runner { + void execute(String id, OWLOntology ontology) throws Exception; + String name(); + + class OntologyAttest implements Runner { + + private final OntologyAttestationService service; + private final Measurements measurements; + private final boolean skipBlc; + + OntologyAttest(OntologyAttestationService service, Measurements measurements, boolean skipBlc) { + this.service = service; + this.measurements = measurements; + this.skipBlc = skipBlc; + } + + @Override + public void execute(String id, OWLOntology ontology) throws Exception { + String iri = ontology.getOntologyID().getOntologyIRI().get().toString(); + String versionIri = ontology.getOntologyID().getVersionIRI().or(IRI.create("")).toString(); + int ticket = measurements.begin(); + String ontologyHash = service.ontologyHash(ontology); + measurements.finish(constructSeriesName(id, name(), "hash"), ticket); + + if (skipBlc) return; + System.out.println("attest " + name() + " " + iri + " " + versionIri + " " + ontologyHash); + + ticket = measurements.begin(); + TransactionReceipt receipt = service.attest(iri, versionIri, "John doe", String.valueOf(ontologyHash), null); + measurements.finish(constructSeriesName(id, name(), "attest"), ticket); + // gas cost is depends on set of call parameters and state of contract, first call is more expensive + measurements.manualMeasurement("attest-gas", receipt.getGasUsed().longValue()); + System.out.println(receipt.getGasUsed()); + } + + @Override + public String name() { + return service.getClass().getSimpleName().toLowerCase(); + } + } + + class HashRunner implements Runner { + + private final OntologyAttestationService service; + private final Measurements measurements; + + HashRunner(OntologyAttestationService service, Measurements measurements) { + this.service = service; + this.measurements = measurements; + } + + @Override + public void execute(String id, OWLOntology ontology) throws Exception { +// String iri = ontology.getOntologyID().getOntologyIRI().get().toString(); +// String versionIri = ontology.getOntologyID().getVersionIRI().or(IRI.create("")).toString(); + int ticket = measurements.begin(); + String ontologyHash = service.ontologyHash(ontology); + measurements.finish(constructSeriesName(id, name(), "hash"), ticket); + } + + @Override + public String name() { + return "hashing"; + } + } + } +} + diff --git a/webprotege-attestation-lib/src/test/java/ch/unifr/digits/contracts/Storage.java b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/contracts/Storage.java new file mode 100644 index 0000000000..aca4623704 --- /dev/null +++ b/webprotege-attestation-lib/src/test/java/ch/unifr/digits/contracts/Storage.java @@ -0,0 +1,85 @@ +package ch.unifr.digits.contracts; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.Type; +import org.web3j.abi.datatypes.generated.Uint256; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.response.TransactionReceipt; +import org.web3j.tx.Contract; +import org.web3j.tx.TransactionManager; +import org.web3j.tx.gas.ContractGasProvider; + +/** + *

Auto generated code. + *

Do not modify! + *

Please use the web3j command line tools, + * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the + * codegen module to update. + * + *

Generated with web3j version 4.7.0. + */ +@SuppressWarnings("rawtypes") +public class Storage extends Contract { + public static final String BINARY = "Bin file was not provided"; + + public static final String FUNC_RETRIEVE = "retrieve"; + + public static final String FUNC_STORE = "store"; + + @Deprecated + protected Storage(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + protected Storage(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, credentials, contractGasProvider); + } + + @Deprecated + protected Storage(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + protected Storage(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); + } + + public RemoteFunctionCall retrieve() { + final Function function = new Function(FUNC_RETRIEVE, + Arrays.asList(), + Arrays.>asList(new TypeReference() {})); + return executeRemoteCallSingleValueReturn(function, BigInteger.class); + } + + public RemoteFunctionCall store(BigInteger num) { + final Function function = new Function( + FUNC_STORE, + Arrays.asList(new org.web3j.abi.datatypes.generated.Uint256(num)), + Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + @Deprecated + public static Storage load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { + return new Storage(contractAddress, web3j, credentials, gasPrice, gasLimit); + } + + @Deprecated + public static Storage load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { + return new Storage(contractAddress, web3j, transactionManager, gasPrice, gasLimit); + } + + public static Storage load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { + return new Storage(contractAddress, web3j, credentials, contractGasProvider); + } + + public static Storage load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { + return new Storage(contractAddress, web3j, transactionManager, contractGasProvider); + } +} diff --git a/webprotege-attestation-lib/src/test/resources/configuration/config.properties b/webprotege-attestation-lib/src/test/resources/configuration/config.properties new file mode 100644 index 0000000000..05f801e3af --- /dev/null +++ b/webprotege-attestation-lib/src/test/resources/configuration/config.properties @@ -0,0 +1,5 @@ +PROVIDER_HOST=http://localhost +PROVIDER_PORT=8545 +ADDRESS_ATTESTATION=0x6a8F5Ef06D06137b5aBDc14201343dF54dcfDBDC +ADDRESS_CHANGETRACKING=0x41c293160913d7cD816093D702e2dDA7391A3976 +SERVER_SECRET=0x2fe929a15797d2170c063b758dee33b55ad7c13313c110b675d3a9709fe83797 diff --git a/webprotege-attestation-lib/src/test/solidity/simple-storage.sol b/webprotege-attestation-lib/src/test/solidity/simple-storage.sol new file mode 100644 index 0000000000..2958b798d7 --- /dev/null +++ b/webprotege-attestation-lib/src/test/solidity/simple-storage.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title Storage + * @dev Store & retrieve value in a variable + */ +contract Storage { + + uint256 number; + + /** + * @dev Store value in variable + * @param num value to store + */ + function store(uint256 num) public { + number = num; + } + + /** + * @dev Return value + * @return value of 'number' + */ + function retrieve() public view returns (uint256){ + return number; + } +} \ No newline at end of file diff --git a/webprotege-client/pom.xml b/webprotege-client/pom.xml index f35e346aa4..5b32f71fb9 100644 --- a/webprotege-client/pom.xml +++ b/webprotege-client/pom.xml @@ -37,6 +37,18 @@ sources + + ch.unifr.digits.webprotege + webprotege-attestation-lib + ${project.version} + gwt-lib + + + + com.google.elemental2 + elemental2-promise + 1.1.0 + com.google.gwt gwt-user diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/editor/EditorPortletPresenter.java b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/editor/EditorPortletPresenter.java index c76938e3f4..dd32d620c9 100644 --- a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/editor/EditorPortletPresenter.java +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/editor/EditorPortletPresenter.java @@ -7,13 +7,13 @@ import edu.stanford.bmir.protege.web.client.app.ForbiddenView; import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager; import edu.stanford.bmir.protege.web.client.lang.DisplayNameRenderer; +import edu.stanford.bmir.protege.web.client.ontology.attestation.EditorPaneAttestationPresenter; import edu.stanford.bmir.protege.web.client.permissions.LoggedInUserProjectPermissionChecker; import edu.stanford.bmir.protege.web.client.portlet.AbstractWebProtegePortletPresenter; import edu.stanford.bmir.protege.web.client.portlet.PortletUi; import edu.stanford.bmir.protege.web.client.tag.TagListPresenter; import edu.stanford.bmir.protege.web.client.ui.ElementalUtil; import edu.stanford.bmir.protege.web.client.viz.VizPanePresenter; -import edu.stanford.bmir.protege.web.shared.dispatch.DispatchService; import edu.stanford.bmir.protege.web.shared.event.ClassFrameChangedEvent; import edu.stanford.bmir.protege.web.shared.event.NamedIndividualFrameChangedEvent; import edu.stanford.bmir.protege.web.shared.event.WebProtegeEventBus; @@ -67,7 +67,8 @@ public EditorPortletPresenter( @Nonnull LoggedInUserProjectPermissionChecker permissionChecker, @Nonnull VizPanePresenter vizPresenter, @Nonnull Provider forbiddenViewProvider, - @Nonnull DispatchServiceManager dispatch) { + @Nonnull DispatchServiceManager dispatch, + @Nonnull EditorPaneAttestationPresenter attestationPortletPresenter) { super(selectionModel, projectId, displayNameRenderer); this.view = checkNotNull(view); this.tagListPresenter = checkNotNull(tagListPresenter); @@ -76,7 +77,8 @@ public EditorPortletPresenter( panePresenters = ImmutableList.of( checkNotNull(editorPresenter), checkNotNull(vizPresenter), - checkNotNull(changesPresenter) + checkNotNull(changesPresenter), + checkNotNull(attestationPortletPresenter) ); displayedTypes.addAll(Arrays.asList( CLASS, diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationPortletPresenter.java b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationPortletPresenter.java new file mode 100644 index 0000000000..48f9e96302 --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationPortletPresenter.java @@ -0,0 +1,112 @@ +package edu.stanford.bmir.protege.web.client.ontology.attestation; + +import ch.unifr.digits.webprotege.attestation.client.ClientAttestationService; +import ch.unifr.digits.webprotege.attestation.shared.*; +import com.google.gwt.core.client.Callback; +import com.google.gwt.core.client.GWT; +import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager; +import edu.stanford.bmir.protege.web.client.lang.DisplayNameRenderer; +import edu.stanford.bmir.protege.web.client.portlet.AbstractWebProtegePortletPresenter; +import edu.stanford.bmir.protege.web.client.portlet.PortletUi; +import edu.stanford.bmir.protege.web.client.selection.SelectionModel; +import edu.stanford.bmir.protege.web.client.user.LoggedInUser; +import edu.stanford.bmir.protege.web.shared.dispatch.actions.GetRootOntologyIdAction; +import edu.stanford.bmir.protege.web.shared.event.WebProtegeEventBus; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; +import edu.stanford.bmir.protege.web.shared.revision.*; +import edu.stanford.protege.widgetmap.client.HasFixedPrimaryAxisSize; +import edu.stanford.webprotege.shared.annotations.Portlet; + +import javax.inject.Inject; +import java.util.function.Consumer; + +@Portlet(id = "portlets.OntologyAttestation", title = "Ontology Attestation") +public class AttestationPortletPresenter extends AbstractWebProtegePortletPresenter implements AttestationPresenter { + + private final DispatchServiceManager dispatchServiceManager; + + private AttestationView editor; + private final LoggedInUser loggedInUser; + private final ProjectId projectId; + private GetAttestationSettingsActionResult attestationSettings; + + @Inject + public AttestationPortletPresenter(SelectionModel selectionModel, DispatchServiceManager dispatchServiceManager, + ProjectId projectId, DisplayNameRenderer displayNameRenderer, LoggedInUser loggedInUser) { + super(selectionModel, projectId, displayNameRenderer); + this.dispatchServiceManager = dispatchServiceManager; + this.projectId = projectId; + this.loggedInUser = loggedInUser; + editor = new AttestationViewImpl(projectId, this); + editor.setEnabled(false); + } + + @Override + public void startPortlet(PortletUi portletUi, WebProtegeEventBus eventBus) { + portletUi.setWidget(editor.asWidget()); +// dispatchServiceManager.execute(new GetRootOntologyIdAction(getProjectId()), +// result -> editor.setValue(result.getObject())); + dispatchServiceManager.execute(new GetAttestationSettingsAction(), + result -> { + attestationSettings = result; + editor.setContractAddress(result.getAddressOntologyContract()); + }); + dispatchServiceManager.execute(new GetProjectOntologyIdAction(getProjectId()), + result -> editor.setIDs(result.getOntologyIDs())); + } + + @Override + public void fileSign(String ontologyIri, String versionIri, Callback callback) { + RevisionNumber head = RevisionNumber.getHeadRevisionNumber(); + ClientAttestationService.signProjectFile(projectId, head, ontologyIri, versionIri, + getUserName(), attestationSettings.getAddressOntologyContract(), callback); + } + + @Override + public void fileVerify(String ontologyIri, String versionIri, Callback callback) { + RevisionNumber head = RevisionNumber.getHeadRevisionNumber(); + GWT.log("Revision " + head.toString()); + ClientAttestationService.verifyProjectFile(projectId, head, ontologyIri, versionIri, + attestationSettings.getAddressOntologyContract(), callback); + } + + @Override + public void owlSign(String ontologyIri, String versionIri, Callback callback) { + Consumer consumer = (OntologyHashResult result) -> { + ClientAttestationService.signOntology(ontologyIri, versionIri, getUserName(), attestationSettings.getAddressOntologyContract(), + result.getHash(), callback); + }; + dispatchServiceManager.execute(new OntologyHashAction(projectId, ontologyIri), consumer); + } + + @Override + public void owlVerify(String ontologyIri, String versionIri, Callback callback) { + Consumer consumer = (OntologyHashResult result) -> { + ClientAttestationService.verifyOntology(ontologyIri, versionIri, attestationSettings.getAddressOntologyContract(), + result.getHash(), callback); + }; + dispatchServiceManager.execute(new OntologyHashAction(projectId, ontologyIri), consumer); + } + + @Override + public void changetrackingSign(String ontologyIri, String versionIri, Callback callback) { + Consumer consumer = (OntologyHashResult result) -> { + ClientAttestationService.signChangeTracking(ontologyIri, versionIri, getUserName(), attestationSettings.getAddressChangeContract(), + result.getHash(), result.getClassHashes(), callback); + }; + dispatchServiceManager.execute(new OntologyHashAction(projectId, ontologyIri), consumer); + } + + @Override + public void changetrackingVerify(String ontologyIri, String versionIri, Callback callback) { + Consumer consumer = (OntologyHashResult result) -> { + ClientAttestationService.verifyChangeTracking(ontologyIri, versionIri, attestationSettings.getAddressChangeContract(), + result.getHash(), callback); + }; + dispatchServiceManager.execute(new OntologyHashAction(projectId, ontologyIri), consumer); + } + + private String getUserName() { + return loggedInUser.getCurrentUserId().getUserName(); + } +} diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationPresenter.java b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationPresenter.java new file mode 100644 index 0000000000..2e1d1c98ce --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationPresenter.java @@ -0,0 +1,13 @@ +package edu.stanford.bmir.protege.web.client.ontology.attestation; + +import ch.unifr.digits.webprotege.attestation.shared.VerifyResult; +import com.google.gwt.core.client.Callback; + +public interface AttestationPresenter { + void fileSign(String iri, String versionIri, Callback callback); + void fileVerify(String iri, String versionIri, Callback callback); + void owlSign(String iri, String versionIri, Callback callback); + void owlVerify(String iri, String versionIri, Callback callback); + void changetrackingSign(String iri, String versionIri, Callback callback); + void changetrackingVerify(String iri, String versionIri, Callback callback); +} diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationView.java b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationView.java new file mode 100644 index 0000000000..b67a3cf94a --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationView.java @@ -0,0 +1,13 @@ +package edu.stanford.bmir.protege.web.client.ontology.attestation; + +import ch.unifr.digits.webprotege.attestation.shared.GetProjectOntologyIdResult; +import com.google.gwt.user.client.ui.HasEnabled; +import edu.stanford.bmir.protege.web.client.editor.ValueEditor; +import org.semanticweb.owlapi.model.OWLOntologyID; + +import java.util.Set; + +public interface AttestationView extends ValueEditor, HasEnabled { + void setContractAddress(String caddress); + void setIDs(Set ids); +} diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationViewImpl.java b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationViewImpl.java new file mode 100644 index 0000000000..95e6fc435a --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationViewImpl.java @@ -0,0 +1,251 @@ +package edu.stanford.bmir.protege.web.client.ontology.attestation; + +import ch.unifr.digits.webprotege.attestation.shared.VerifyResult; +import com.google.gwt.core.client.Callback; +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JsDate; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.i18n.client.DateTimeFormat; +import com.google.gwt.text.client.DateTimeFormatRenderer; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.*; +import edu.stanford.bmir.protege.web.shared.DirtyChangedEvent; +import edu.stanford.bmir.protege.web.shared.DirtyChangedHandler; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; +import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLOntologyID; + +import java.util.*; +import java.util.stream.Collectors; + +public class AttestationViewImpl extends Composite implements AttestationView { + interface AttestationViewImplUiBinder extends UiBinder {} + private static AttestationViewImplUiBinder ourUiBinder = GWT.create(AttestationViewImplUiBinder.class); + + private final ProjectId projectId; + private final AttestationPresenter presenter; + private Set projectOntologyIDs; + + @UiField + protected Label versionIRIField; +// @UiField +// protected Button fileSignButton; +// @UiField +// protected Label fileSignResult; +// @UiField +// protected Button fileVerifyButton; +// @UiField +// protected Label fileVerifyResult; + @UiField + protected Button owlSignButton; + @UiField + protected Label owlSignResult; + @UiField + protected Button owlVerifyButton; + @UiField + protected Label owlVerifyResult; + @UiField + protected Label address; + @UiField + protected Label status; + @UiField + protected Label signer; + @UiField + protected ValueListBox projectIRIs; + @UiField + protected Label timestamp; + + private boolean dirty = false; + + public AttestationViewImpl(ProjectId projectId, AttestationPresenter presenter) { + this.projectId = projectId; + this.presenter = presenter; + HTMLPanel rootElement = ourUiBinder.createAndBindUi(this); + + +// Callback fileSignCallback = new Callback() { +// @Override +// public void onFailure(Object reason) { +// GWT.log(reason.toString()); +// fileSignResult.setText("Error while attesting ontology!"); +// } +// +// @Override +// public void onSuccess(Boolean result) { +// GWT.log("Attestation result: " + result.toString()); +// if (result) { +// fileSignResult.setText("Successfully attested ontology!"); +// } else { +// fileSignResult.setText("Failed to attested ontology!"); +// } +// } +// }; + +// Callback fileVerifyCallback = new Callback() { +// @Override +// public void onFailure(Object reason) { +// GWT.log(reason.toString()); +// fileVerifyResult.setText("Error while verifying ontology!"); +// } +// +// @Override +// public void onSuccess(VerifyResult result) { +// if (!result.isValid()) { +// fileVerifyResult.setText("Ontology was not attested!"); +// } else { +// fileVerifyResult.setText(result.toString()); +// } +// } +// }; + + Callback owlSignCallback = new Callback() { + @Override + public void onFailure(Object reason) { + GWT.log(reason.toString()); + owlSignResult.setText("Error while attesting ontology!"); + } + + @Override + public void onSuccess(Boolean result) { + GWT.log("Attestation result: " + result.toString()); + if (result) { + owlSignResult.setText("Successfully attested ontology!"); + } else { + owlSignResult.setText("Failed to attested ontology!"); + } + } + }; + + Callback owlVerifyCallback = new Callback() { + @Override + public void onFailure(Object reason) { + GWT.log(reason.toString()); +// owlVerifyResult.setText("Error while verifying ontology!"); + status.setText("Error while verifying ontology!"); + status.getElement().setAttribute("data-attest", "false"); + signer.setText(""); + } + + @Override + public void onSuccess(VerifyResult result) { + if (!result.isValid()) { +// owlVerifyResult.setText("Ontology was not attested!"); + status.setText("Current ontology revision not attested"); + status.getElement().setAttribute("data-attest", "false"); + signer.setText(""); + } else { +// owlVerifyResult.setText(result.toString()); + status.setText("Attested"); + status.getElement().setAttribute("data-attest", "true"); + signer.setText("Signed by " + result.getSignerName() + " (" + result.getSigner() +")"); + + JsDate jsDate = JsDate.create(result.getTimestamp() * 1000); + GWT.log("timestamp " + result.getTimestamp() + " " + jsDate.toString()); + timestamp.setText(jsDate.toString()); + } + } + }; + + projectIRIs.addValueChangeHandler(event -> versionIRIField.setText(getVersionIRI(event.getValue()).toString())); +// fileSignButton.addClickHandler((event -> { +// presenter.fileSign(projectIRIs.getValue(), versionIRIField.getText(), fileSignCallback); +// })); +// fileVerifyButton.addClickHandler((event -> { +// presenter.fileVerify(projectIRIs.getValue(), versionIRIField.getText(), fileVerifyCallback); +// })); + owlSignButton.addClickHandler((event -> { + GWT.log("Signing: IRI " + projectIRIs.getValue()); + presenter.owlSign(projectIRIs.getValue(), versionIRIField.getText(), owlSignCallback); + })); + owlVerifyButton.addClickHandler((event -> { + GWT.log("Verify: IRI " + projectIRIs.getValue()); + presenter.owlVerify(projectIRIs.getValue(), versionIRIField.getText(), owlVerifyCallback); + })); + + initWidget(rootElement); + } + + public void setContractAddress(String caddress) { + address.setText(caddress); + } + + @Override + public void setIDs(Set ids) { + projectOntologyIDs = ids; + List list = ids.stream().map(OWLOntologyID::getOntologyIRI).filter(com.google.common.base.Optional::isPresent) + .map(com.google.common.base.Optional::get).map(IRI::toString).collect(Collectors.toList()); + projectIRIs.setAcceptableValues(list); + String def = list.get(list.size()-1); + projectIRIs.setValue(def); + versionIRIField.setText(getVersionIRI(def).toString()); + } + + @Override + public Widget getWidget() { + return this; + } + + @Override + public void clearValue() { + versionIRIField.setText(""); + dirty = false; + } + + @Override + public void setValue(OWLOntologyID object) { + dirty = false; + versionIRIField.setText(""); + if(object.isAnonymous()) { + return; + } + } + + @Override + public Optional getValue() { + return getIdForIRI(projectIRIs.getValue()); + } + + @Override + public boolean isEnabled() { + return owlSignButton.isEnabled(); + } + + @Override + public void setEnabled(boolean enabled) {} + + @Override + public boolean isDirty() { + return dirty; + } + + @Override + public HandlerRegistration addDirtyChangedHandler(DirtyChangedHandler handler) { + return addHandler(handler, DirtyChangedEvent.TYPE); + } + + @Override + public HandlerRegistration addValueChangeHandler(ValueChangeHandler> handler) { + return addHandler(handler, ValueChangeEvent.getType()); + } + + @Override + public boolean isWellFormed() { + return true; + } + + private Optional getIdForIRI(String iri) { + return projectOntologyIDs.stream().filter(id -> + id.getOntologyIRI().isPresent() && id.getOntologyIRI().get().toString().equals(iri) + ).findFirst(); + } + + private IRI getVersionIRI(String iri) { + Optional ontologyID = getIdForIRI(iri); + return ontologyID.map(owlOntologyID -> owlOntologyID.getVersionIRI().or(IRI.create(""))).orElseGet(() -> IRI.create("")); + } + + +} diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationViewImpl.ui.xml b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationViewImpl.ui.xml new file mode 100644 index 0000000000..f09d146afa --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/AttestationViewImpl.ui.xml @@ -0,0 +1,67 @@ + + + + + + .main {} + .status::before { + padding-right: 10px; + } + .status[data-attest=true] { + color: green; + } + .status[data-attest=true]::before { + content: '\2713'; + } + .status[data-attest=false] { + color: red; + } + .status[data-attest=false]::before { + content: '\292C'; + } + + + +

+ + +
+ + + + + +
+ + +
+
+ + +
+ + + + + + + + +
+
+ + + + +
+
+
+ + + + + +
+ + diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorAttestationPane.java b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorAttestationPane.java new file mode 100644 index 0000000000..441ea95d9c --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorAttestationPane.java @@ -0,0 +1,156 @@ +package edu.stanford.bmir.protege.web.client.ontology.attestation; + +import ch.unifr.digits.webprotege.attestation.client.ClientAttestationService; +import ch.unifr.digits.webprotege.attestation.shared.VerifyAction; +import ch.unifr.digits.webprotege.attestation.shared.VerifyResult; +import com.google.common.collect.ImmutableSet; +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.http.client.URL; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.*; +import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager; +import edu.stanford.bmir.protege.web.resources.WebProtegeClientBundle; +import edu.stanford.bmir.protege.web.shared.DirtyChangedEvent; +import edu.stanford.bmir.protege.web.shared.DirtyChangedHandler; +import edu.stanford.bmir.protege.web.shared.entity.EntityDisplay; +import edu.stanford.bmir.protege.web.shared.entity.OWLClassData; +import edu.stanford.bmir.protege.web.shared.frame.ClassFrame; +import edu.stanford.bmir.protege.web.shared.frame.PropertyValue; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; +import org.semanticweb.owlapi.model.IRI; +import org.semanticweb.owlapi.model.OWLEntity; +import org.semanticweb.owlapi.model.OWLOntologyID; + +import javax.annotation.Nonnull; +import javax.inject.Inject; +import java.util.*; +import java.util.function.Consumer; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class EditorAttestationPane extends SimplePanel implements EditorPaneAttestationView { + + private final ProjectId projectId; + private final DispatchServiceManager dispatchServiceManager; + + @UiField + protected HasText iriField; + @UiField + protected Label attest; + @UiField + protected Label signer; + + + + private OWLClassData currentSubject; + + private ClassFrame currentFrame; + + private EntityDisplay entityDisplay = entityData -> {}; + private OWLOntologyID ontologyID; + + interface EditorAttestationPane2UiBinder extends UiBinder { + } + + private static EditorAttestationPane2UiBinder ourUiBinder = GWT.create(EditorAttestationPane2UiBinder.class); + + @Inject + public EditorAttestationPane(ProjectId projectId, DispatchServiceManager dispatchServiceManager) { + this.projectId = projectId; + this.dispatchServiceManager = dispatchServiceManager; + WebProtegeClientBundle.BUNDLE.style().ensureInjected(); + HTMLPanel rootElement = ourUiBinder.createAndBindUi(this); + setWidget(rootElement); + attest.getElement().setAttribute("data-attest", "false"); + } + + @Override + public HandlerRegistration addDirtyChangedHandler(DirtyChangedHandler handler) { + return addHandler(handler, DirtyChangedEvent.TYPE); + } + + @Override + public Optional getValue() { + if(currentSubject == null) { + return Optional.empty(); + } + else { + return Optional.of(ClassFrame.get(currentSubject, ImmutableSet.builder().build(), + ImmutableSet.builder().build())); + } + } + + @Override + public boolean isDirty() { + return false; + } + + @Override + public boolean isWellFormed() { + return true; + } + + @Override + public void setEntityDisplay(@Nonnull EntityDisplay entityDisplay) { + this.entityDisplay = entityDisplay; + } + + @Override + public void setValue(ClassFrame frame) { + this.currentFrame = frame; + this.currentSubject = frame.getSubject(); + + String decodedIri = URL.decode(currentSubject.getEntity().getIRI().toString()); + iriField.setText(decodedIri); + dispatch(); + } + + @Override + public void clearValue() { + entityDisplay.setDisplayedEntity(Optional.empty()); + } + + @Override + public HandlerRegistration addValueChangeHandler(ValueChangeHandler> handler) { + return addHandler(handler, ValueChangeEvent.getType()); + } + + @Override + public Widget getWidget() { + return this; + } + + + public void setOntologyID(OWLOntologyID object) { + this.ontologyID = object; + } + + private void dispatch() { + int hashEntity = ClientAttestationService.hashEntity(currentSubject.getEntity()); + String ontologyIri = ontologyID.getOntologyIRI().or(IRI.create("")).toString(); + String versionIri = ontologyID.getVersionIRI().or(IRI.create("")).toString(); + + GWT.log("[attestation] verify " + iriField.getText()); + GWT.log("[attestation] hash " + hashEntity); + VerifyAction action = new VerifyAction(projectId, ontologyIri, versionIri, String.valueOf(hashEntity), currentSubject.getEntity(), + VerifyAction.Mode.ENTITY); + Consumer consumer = res -> { + if (res == null) GWT.log("oh no"); + boolean resultBool = Objects.requireNonNull(res).isValid(); + if (resultBool) { + attest.setText("Attested"); + attest.getElement().setAttribute("data-attest", "true"); + signer.setText("Signed by " + res.getSignerName() + " (" + res.getSigner() +")"); + } else { + attest.setText("Not attested"); + attest.getElement().setAttribute("data-attest", "false"); + signer.setText(""); + } + }; + dispatchServiceManager.execute(action, consumer); + } +} diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorAttestationPane.ui.xml b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorAttestationPane.ui.xml new file mode 100644 index 0000000000..56a23c809a --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorAttestationPane.ui.xml @@ -0,0 +1,40 @@ + + + + + + + .attest::before { + padding-right: 10px; + } + .attest[data-attest=true] { + color: green; + } + .attest[data-attest=true]::before { + content: '\2713'; + } + .attest[data-attest=false] { + color: red; + } + .attest[data-attest=false]::before { + content: '\292C'; + } + + + + +
+ + +
+
+ +
+
+ +
+ + +
+
diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorPaneAttestationPresenter.java b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorPaneAttestationPresenter.java new file mode 100644 index 0000000000..dc43567b60 --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorPaneAttestationPresenter.java @@ -0,0 +1,105 @@ +package edu.stanford.bmir.protege.web.client.ontology.attestation; + +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager; +import edu.stanford.bmir.protege.web.client.editor.EditorPanePresenter; +import edu.stanford.bmir.protege.web.client.editor.EditorPresenter; +import edu.stanford.bmir.protege.web.client.editor.OWLEntityContext; +import edu.stanford.bmir.protege.web.client.progress.HasBusy; +import edu.stanford.bmir.protege.web.client.ui.ElementalUtil; +import edu.stanford.bmir.protege.web.resources.WebProtegeClientBundle; +import edu.stanford.bmir.protege.web.shared.access.BuiltInAction; +import edu.stanford.bmir.protege.web.shared.dispatch.actions.GetClassFrameAction; +import edu.stanford.bmir.protege.web.shared.dispatch.actions.GetRootOntologyIdAction; +import edu.stanford.bmir.protege.web.shared.entity.EntityDisplay; +import edu.stanford.bmir.protege.web.shared.event.WebProtegeEventBus; +import edu.stanford.bmir.protege.web.shared.project.ProjectId; +import org.semanticweb.owlapi.model.OWLEntity; + +import javax.annotation.Nonnull; +import javax.inject.Inject; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class EditorPaneAttestationPresenter implements EditorPanePresenter { + @Nonnull + private final ProjectId projectId; + @Nonnull + private final EditorPresenter editorPresenter; + @Nonnull + private final WebProtegeClientBundle clientBundle; + @Nonnull + private final DispatchServiceManager dispatchServiceManager; + private final EditorAttestationPane view; + + @Inject + public EditorPaneAttestationPresenter(@Nonnull ProjectId projectId, + @Nonnull EditorPresenter editorPresenter, + @Nonnull WebProtegeClientBundle clientBundle, + @Nonnull DispatchServiceManager dispatchServiceManager) { + + this.projectId = checkNotNull(projectId); + this.editorPresenter = checkNotNull(editorPresenter); + this.clientBundle = checkNotNull(clientBundle); + this.dispatchServiceManager = dispatchServiceManager; + + WebProtegeClientBundle.BUNDLE.style().ensureInjected(); + view = new EditorAttestationPane(projectId, dispatchServiceManager); + } + + @Nonnull + @Override + public String getCaption() { + return "Attestation"; + } + + @Nonnull + @Override + public String getAdditionalStyles() { + return clientBundle.buttons().cross(); + } + + @Nonnull + @Override + public BuiltInAction getRequiredAction() { + return BuiltInAction.VIEW_PROJECT; + } + + @Override + public void start(@Nonnull AcceptsOneWidget container, WebProtegeEventBus eventBus) { +// editorPresenter.start(container, eventBus); +// editorPresenter.updatePermissionBasedItems(); + container.setWidget(view); + } + + @Override + public void setEntity(@Nonnull OWLEntity entity) { + editorPresenter.setEditorContext(Optional.of(new OWLEntityContext(projectId, entity))); + GetClassFrameAction action = new GetClassFrameAction(entity.asOWLClass(), projectId); + GetRootOntologyIdAction ontologyIdAction = new GetRootOntologyIdAction(projectId); + dispatchServiceManager.execute(ontologyIdAction, (r) -> view.setOntologyID(r.getObject())); + dispatchServiceManager.execute(action, (r) -> view.setValue(r.getFrame())); + } + + @Override + public void setHasBusy(@Nonnull HasBusy hasBusy) { + editorPresenter.setHasBusy(hasBusy); + } + + @Override + public void setEntityDisplay(@Nonnull EntityDisplay entityDisplay) { + editorPresenter.setEntityDisplay(entityDisplay); + } + + @Override + public void dispose() { + editorPresenter.dispose(); + } + + @Override + public boolean isActive() { + return ElementalUtil.isWidgetOrDescendantWidgetActive(editorPresenter.getView()); + } +} diff --git a/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorPaneAttestationView.java b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorPaneAttestationView.java new file mode 100644 index 0000000000..d47517a4ce --- /dev/null +++ b/webprotege-client/src/main/java/edu/stanford/bmir/protege/web/client/ontology/attestation/EditorPaneAttestationView.java @@ -0,0 +1,9 @@ +package edu.stanford.bmir.protege.web.client.ontology.attestation; + +import com.google.gwt.user.client.ui.IsWidget; +import edu.stanford.bmir.protege.web.client.editor.EditorView; +import edu.stanford.bmir.protege.web.client.editor.OWLEntityContext; +import edu.stanford.bmir.protege.web.shared.frame.ClassFrame; + +public interface EditorPaneAttestationView extends IsWidget, EditorView { +} diff --git a/webprotege-client/src/main/module-dev.gwt.xml b/webprotege-client/src/main/module-dev.gwt.xml index 1a36537a31..36cef33488 100644 --- a/webprotege-client/src/main/module-dev.gwt.xml +++ b/webprotege-client/src/main/module-dev.gwt.xml @@ -35,8 +35,9 @@ - + +