diff --git a/Cargo.lock b/Cargo.lock index c16b67c87cb..54b3bff97ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,8 +1,3 @@ -[[package]] -name = "adler32" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "aho-corasick" version = "0.6.4" @@ -40,14 +35,6 @@ name = "assert_matches" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "aster" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "atty" version = "0.2.8" @@ -84,11 +71,6 @@ name = "base-x" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "base32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "base64" version = "0.6.0" @@ -135,11 +117,6 @@ name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "0.9.1" @@ -170,11 +147,6 @@ dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.2.1" @@ -267,14 +239,6 @@ dependencies = [ "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crc" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam" version = "0.3.2" @@ -1119,15 +1083,6 @@ name = "fixedbitset" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "flate2" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fnv" version = "1.0.5" @@ -1182,11 +1137,6 @@ name = "getopts" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "globset" version = "0.2.1" @@ -1743,26 +1693,6 @@ dependencies = [ "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "miniz_oxide" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miniz_oxide_c_api" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "mio" version = "0.6.14" @@ -1821,15 +1751,6 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "msdos_time" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "multibase" version = "0.6.0" @@ -2072,7 +1993,6 @@ dependencies = [ "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", - "parity-dapps 1.12.0", "parity-hash-fetch 1.12.0", "parity-ipfs-api 1.12.0", "parity-local-store 0.1.0", @@ -2127,55 +2047,6 @@ dependencies = [ "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parity-dapps" -version = "1.12.0" -dependencies = [ - "base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-devtools 1.12.0", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fetch 0.1.0", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", - "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", - "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", - "node-health 0.1.0", - "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", - "parity-dapps-glue 1.9.1", - "parity-hash-fetch 1.12.0", - "parity-reactor 0.1.0", - "parity-version 1.12.0", - "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "registrar 0.0.1", - "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zip 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parity-dapps-glue" -version = "1.9.1" -dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parity-hash-fetch" version = "1.12.0" @@ -2547,11 +2418,6 @@ dependencies = [ "hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)", ] -[[package]] -name = "podio" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "pretty_assertions" version = "0.1.2" @@ -2663,34 +2529,6 @@ dependencies = [ "parity-wasm 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quasi" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quasi_codegen" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quasi_macros" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quick-error" version = "1.2.2" @@ -3132,48 +2970,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syntex" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_errors" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_pos" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_syntax" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "take" version = "0.1.0" @@ -3204,15 +3000,6 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "term" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term_size" version = "0.3.1" @@ -3619,11 +3406,6 @@ name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.1.0" @@ -3846,41 +3628,25 @@ dependencies = [ "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "zip" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum assert_matches 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "664470abf00fae0f31c0eb6e1ca12d82961b2a2541ef898bc9dd51a9254d218b" -"checksum aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfdf7355d9db158df68f976ed030ab0f6578af811f5a7bb6dcf221ec24e0e0" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" "checksum backtrace-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c63ea141ef8fdb10409d0f5daf30ac51f84ef43bff66f16627773d2a292cd189" "checksum base-x 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f59103b47307f76e03bef1633aec7fa9e29bfb5aa6daf5a334f94233c71f6c1" -"checksum base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9605ba46d61df0410d8ac686b0007add8172eba90e8e909c347856fe794d8c" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "229d032f1a99302697f10b27167ae6d03d49d032e6a8e2550e8d3fc13356d2b4" "checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bn 0.4.4 (git+https://github.com/paritytech/bn)" = "" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" "checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d" @@ -3889,7 +3655,6 @@ dependencies = [ "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2" @@ -3922,7 +3687,6 @@ dependencies = [ "checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum fixed-hash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18d6fd718fb4396e7a9c93ac59ba7143501467ca7a143c145b5555a571d5576" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" -"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" "checksum fs-swap 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67f816b2a5f8a6628764a4323d1a8d9ad5303266c4e4e4486ba680f477ba7e62" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -3931,7 +3695,6 @@ dependencies = [ "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "464627f948c3190ae3d04b1bc6d7dca2f785bda0ac01278e6db129ad383dbeb6" "checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1" "checksum hashdb 0.2.0 (git+https://github.com/paritytech/parity-common)" = "" @@ -3986,14 +3749,11 @@ dependencies = [ "checksum memorydb 0.2.0 (git+https://github.com/paritytech/parity-common)" = "" "checksum mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e3d709ffbb330e1566dc2f2a3c9b58a5ad4a381f740b810cd305dc3f089bc160" "checksum mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27a5e6679a0614e25adc14c6434ba84e41632b765a6d9cb2031a0cca682699ae" -"checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398" -"checksum miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92d98fdbd6145645828069b37ea92ca3de225e000d80702da25c20d3584b38a5" "checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" "checksum mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)" = "" "checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" -"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" "checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" "checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3" "checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f" @@ -4029,7 +3789,6 @@ dependencies = [ "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" "checksum plain_hasher 0.1.0 (git+https://github.com/paritytech/parity-common)" = "" -"checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0" "checksum pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2412f3332a07c7a2a50168988dcc184f32180a9758ad470390e5f55e089f6b6e" "checksum primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0e31b86efadeaeb1235452171a66689682783149a6249ff334a2c5d8218d00a4" "checksum primal-bit 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "686a64e2f50194c64942992af5799e6b6e8775b8f88c607d72ed0a2fd58b9b21" @@ -4040,9 +3799,6 @@ dependencies = [ "checksum protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40e2484e639dcae0985fc483ad76ce7ad78ee5aa092751d7d538f0b20d76486b" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum pwasm-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "90d2b3c5bf24275fc77db6b14ec00a7a085d8ff9d1c4215fb6f6263e8d7b01bc" -"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3" -"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4" -"checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" "checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" @@ -4093,15 +3849,10 @@ dependencies = [ "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" -"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e" -"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" -"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047" -"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791" "checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" "checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" @@ -4139,7 +3890,6 @@ dependencies = [ "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" @@ -4163,4 +3913,3 @@ dependencies = [ "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" "checksum xmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9cfb54ca6b8f17d2377219ce485b134d53561b77e1393c7ea416f543a527431" -"checksum zip 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "10931e278527cea65682696481e6d840371d581079df529ebfee186e0eaad719" diff --git a/Cargo.toml b/Cargo.toml index a92fe35eb2f..f84b2080c09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ ethcore-transaction = { path = "ethcore/transaction" } ethereum-types = "0.3" node-filter = { path = "ethcore/node_filter" } ethkey = { path = "ethkey" } -node-health = { path = "dapps/node-health" } +node-health = { path = "node-health" } rlp = { git = "https://github.com/paritytech/parity-common" } rpc-cli = { path = "rpc_cli" } parity-hash-fetch = { path = "hash-fetch" } @@ -68,7 +68,6 @@ kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common" } journaldb = { path = "util/journaldb" } mem = { path = "util/mem" } -parity-dapps = { path = "dapps", optional = true } ethcore-secretstore = { path = "secret_store", optional = true } registrar = { path = "registrar" } @@ -89,8 +88,6 @@ winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] } daemonize = { git = "https://github.com/paritytech/daemonize" } [features] -default = ["dapps"] -dapps = ["parity-dapps"] json-tests = ["ethcore/json-tests"] test-heavy = ["ethcore/test-heavy"] evm-debug = ["ethcore/evm-debug"] @@ -126,7 +123,6 @@ debug = false [workspace] members = [ "chainspec", - "dapps/js-glue", "ethcore/wasm/run", "ethcore/types", "ethkey/cli", diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml deleted file mode 100644 index b32fdb4a32c..00000000000 --- a/dapps/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -description = "Parity Dapps crate" -name = "parity-dapps" -version = "1.12.0" -license = "GPL-3.0" -authors = ["Parity Technologies "] - -[lib] - -[dependencies] -base32 = "0.3" -futures = "0.1" -futures-cpupool = "0.1" -linked-hash-map = "0.5" -log = "0.3" -parking_lot = "0.6" -mime_guess = "2.0.0-alpha.2" -rand = "0.4" -rustc-hex = "1.0" -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" -unicase = "1.4" -zip = { version = "0.3", default-features = false, features = ["deflate"] } -itertools = "0.5" - -jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } -jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } - -parity-bytes = { git = "https://github.com/paritytech/parity-common" } -ethereum-types = "0.3" -fetch = { path = "../util/fetch" } -node-health = { path = "./node-health" } -parity-dapps-glue = { path = "./js-glue" } -parity-hash-fetch = { path = "../hash-fetch" } -parity-reactor = { path = "../util/reactor" } -keccak-hash = { git = "https://github.com/paritytech/parity-common" } -parity-version = { path = "../util/version" } -registrar = { path = "../registrar" } - -[dev-dependencies] -env_logger = "0.4" -ethcore-devtools = { path = "../devtools" } diff --git a/dapps/js-glue/Cargo.toml b/dapps/js-glue/Cargo.toml deleted file mode 100644 index efe92bbda6a..00000000000 --- a/dapps/js-glue/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -description = "Base Package for all Parity built-in dapps" -name = "parity-dapps-glue" -version = "1.9.1" -license = "GPL-3.0" -authors = ["Parity Technologies "] -build = "build.rs" - -[build-dependencies] -quasi_codegen = { version = "0.32", optional = true } -syntex = { version = "0.58", optional = true } - -[dependencies] -glob = { version = "0.2.11" } -mime_guess = { version = "2.0.0-alpha.2" } -aster = { version = "0.41", default-features = false } -quasi = { version = "0.32", default-features = false } -quasi_macros = { version = "0.32", optional = true } -syntex = { version = "0.58", optional = true } -syntex_syntax = { version = "0.58", optional = true } - -[features] -default = ["with-syntex"] -nightly = ["quasi_macros"] -with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"] -use-precompiled-js = [] - - diff --git a/dapps/js-glue/README.md b/dapps/js-glue/README.md deleted file mode 100644 index 3363da9b222..00000000000 --- a/dapps/js-glue/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# Parity Dapps (JS-glue) - -Code generator to simplify creating a built-in Parity Dapp - -# How to create new builtin Dapp. -1. Clone this repository. - - ```bash - $ git clone https://github.com/paritytech/parity.git - ``` - -1. Create a new directory for your Dapp. (`./myapp`) - - ```bash - $ mkdir -p ./parity/dapps/myapp/src/web - ``` - -1. Copy your frontend files to `./dapps/myapp/src/web` (bundled ones) - - ```bash - $ cp -r ./myapp-src/* ./parity/dapps/myapp/src/web - ``` - -1. Instead of creating `web3` in your app. Load (as the first script tag in `head`): - - ```html - - ``` - - The `inject.js` script will create global `web3` instance with proper provider that should be used by your dapp. - -1. Create `./parity/dapps/myapp/Cargo.toml` with you apps details. See example here: [parity-status Cargo.toml](https://github.com/paritytech/parity-ui/blob/master/status/Cargo.toml). - - ```bash - $ git clone https://github.com/paritytech/parity-ui.git - $ cd ./parity-ui/ - $ cp ./home/Cargo.toml ../parity/dapps/myapp/Cargo.toml - $ cp ./home/build.rs ../parity/dapps/myapp/build.rs - $ cp ./home/src/lib.rs ../parity/dapps/myapp/src/lib.rs - $ cp ./home/src/lib.rs.in ../parity/dapps/myapp/src/lib.rs.in - # And edit the details of your app - $ vim ../parity/dapps/myapp/Cargo.toml # Edit the details - $ vim ./parity/dapps/myapp/src/lib.rs.in # Edit the details - ``` -# How to include your Dapp into `Parity`? -1. Edit `dapps/Cargo.toml` and add dependency to your application (it can be optional) - - ```toml - # Use git repo and version - parity-dapps-myapp = { path="./myapp" } - ``` - -1. Edit `dapps/src/apps.rs` and add your application to `all_pages` (if it's optional you need to specify two functions - see `parity-dapps-wallet` example) - -1. Compile parity. - - ```bash - $ cargo build --release # While inside `parity` - ``` - -1. Commit the results. - - ```bash - $ git add myapp && git commit -am "My first Parity Dapp". - ``` diff --git a/dapps/js-glue/build.rs b/dapps/js-glue/build.rs deleted file mode 100644 index 19d422ab231..00000000000 --- a/dapps/js-glue/build.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -#[cfg(feature = "with-syntex")] -mod inner { - extern crate syntex; - extern crate quasi_codegen; - - use std::env; - use std::path::Path; - - pub fn main() { - let out_dir = env::var_os("OUT_DIR").unwrap(); - - let src = Path::new("src/lib.rs.in"); - let dst = Path::new(&out_dir).join("lib.rs"); - - quasi_codegen::expand(&src, &dst).unwrap(); - } -} - -#[cfg(not(feature = "with-syntex"))] -mod inner { - pub fn main() {} -} - -fn main() { - inner::main(); -} diff --git a/dapps/js-glue/src/build.rs b/dapps/js-glue/src/build.rs deleted file mode 100644 index 76b0a8714ce..00000000000 --- a/dapps/js-glue/src/build.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -#[cfg(feature = "with-syntex")] -pub mod inner { - use syntex; - use codegen; - use syntax::{ast, fold}; - use std::env; - use std::path::Path; - - fn strip_attributes(krate: ast::Crate) -> ast::Crate { - /// Helper folder that strips the serde attributes after the extensions have been expanded. - struct StripAttributeFolder; - - impl fold::Folder for StripAttributeFolder { - fn fold_attribute(&mut self, attr: ast::Attribute) -> Option { - if &*attr.value.name.as_str() == "webapp" { - return None; - } - - Some(attr) - } - - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) - } - } - - fold::Folder::fold_crate(&mut StripAttributeFolder, krate) - } - - pub fn register(reg: &mut syntex::Registry) { - reg.add_attr("feature(custom_derive)"); - reg.add_attr("feature(custom_attribute)"); - - reg.add_decorator("derive_WebAppFiles", codegen::expand_webapp_implementation); - reg.add_post_expansion_pass(strip_attributes); - } - - pub fn generate() { - let out_dir = env::var_os("OUT_DIR").unwrap(); - let mut registry = syntex::Registry::new(); - register(&mut registry); - - let src = Path::new("src/lib.rs.in"); - let dst = Path::new(&out_dir).join("lib.rs"); - - registry.expand("", &src, &dst).unwrap(); - } -} - -#[cfg(not(feature = "with-syntex"))] -pub mod inner { - use codegen; - - pub fn register(reg: &mut rustc_plugin::Registry) { - reg.register_syntax_extension( - syntax::parse::token::intern("derive_WebAppFiles"), - syntax::ext::base::MultiDecorator( - Box::new(codegen::expand_webapp_implementation))); - - reg.register_attribute("webapp".to_owned(), AttributeType::Normal); - } - - pub fn generate() {} -} diff --git a/dapps/js-glue/src/codegen.rs b/dapps/js-glue/src/codegen.rs deleted file mode 100644 index 4b6c4445d74..00000000000 --- a/dapps/js-glue/src/codegen.rs +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -extern crate aster; -extern crate glob; -extern crate mime_guess; - -use self::mime_guess::guess_mime_type; -use std::path::{self, Path, PathBuf}; -use std::ops::Deref; - -use syntax::attr; -use syntax::ast::{self, MetaItem, Item}; -use syntax::codemap::Span; -use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::print::pprust::lit_to_string; -use syntax::symbol::InternedString; - -pub fn expand_webapp_implementation( - cx: &mut ExtCtxt, - span: Span, - meta_item: &MetaItem, - annotatable: &Annotatable, - push: &mut FnMut(Annotatable) -) { - let item = match *annotatable { - Annotatable::Item(ref item) => item, - _ => { - cx.span_err(meta_item.span, "`#[derive(WebAppFiles)]` may only be applied to struct implementations"); - return; - }, - }; - let builder = aster::AstBuilder::new().span(span); - implement_webapp(cx, &builder, item, push); -} - -fn implement_webapp(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) { - let static_files_dir = extract_path(cx, item); - - let src = Path::new("src"); - let static_files = { - let mut buf = src.to_path_buf(); - buf.push(static_files_dir.deref()); - buf - }; - - let search_location = { - let mut buf = static_files.to_path_buf(); - buf.push("**"); - buf.push("*"); - buf - }; - - let files = glob::glob(search_location.to_str().expect("Valid UTF8 path")) - .expect("The sources directory is missing.") - .collect::, glob::GlobError>>() - .expect("There should be no error when reading a list of files."); - - let statements = files - .iter() - .filter(|path_buf| path_buf.is_file()) - .map(|path_buf| { - let path = path_buf.as_path(); - let filename = path.file_name().and_then(|s| s.to_str()).expect("Only UTF8 paths."); - let mime_type = guess_mime_type(filename).to_string(); - let file_path = as_uri(path.strip_prefix(&static_files).ok().expect("Prefix is always there, cause it's absolute path;qed")); - let file_path_in_source = path.to_str().expect("Only UTF8 paths."); - - let path_lit = builder.expr().str(file_path.as_str()); - let mime_lit = builder.expr().str(mime_type.as_str()); - let web_path_lit = builder.expr().str(file_path_in_source); - let separator_lit = builder.expr().str(path::MAIN_SEPARATOR.to_string().as_str()); - let concat_id = builder.id("concat!"); - let env_id = builder.id("env!"); - let macro_id = builder.id("include_bytes!"); - - let content = quote_expr!( - cx, - $macro_id($concat_id($env_id("CARGO_MANIFEST_DIR"), $separator_lit, $web_path_lit)) - ); - quote_stmt!( - cx, - files.insert($path_lit, File { path: $path_lit, content_type: $mime_lit, content: $content }); - ).expect("The statement is always ok, because it just uses literals.") - }).collect::>(); - - let type_name = item.ident; - - let files_impl = quote_item!(cx, - impl $type_name { - #[allow(unused_mut)] - fn files() -> ::std::collections::HashMap<&'static str, File> { - let mut files = ::std::collections::HashMap::new(); - $statements - files - } - } - ).unwrap(); - - push(Annotatable::Item(files_impl)); -} - -fn extract_path(cx: &ExtCtxt, item: &Item) -> String { - for meta_items in item.attrs.iter().filter_map(webapp_meta_items) { - for meta_item in meta_items { - let is_path = &*meta_item.name.as_str() == "path"; - match meta_item.node { - ast::MetaItemKind::NameValue(ref lit) if is_path => { - if let Some(s) = get_str_from_lit(cx, lit) { - return s.deref().to_owned(); - } - }, - _ => {}, - } - } - } - - // default - "web".to_owned() -} - -fn webapp_meta_items(attr: &ast::Attribute) -> Option> { - let is_webapp = &*attr.value.name.as_str() == "webapp"; - match attr.value.node { - ast::MetaItemKind::List(ref items) if is_webapp => { - attr::mark_used(&attr); - Some( - items.iter() - .map(|item| item.node.clone()) - .filter_map(|item| match item { - ast::NestedMetaItemKind::MetaItem(item) => Some(item), - _ => None, - }) - .collect() - ) - } - _ => None - } -} - -fn get_str_from_lit(cx: &ExtCtxt, lit: &ast::Lit) -> Option { - match lit.node { - ast::LitKind::Str(ref s, _) => Some(s.clone().as_str()), - _ => { - cx.span_err( - lit.span, - &format!("webapp annotation path must be a string, not `{}`", - lit_to_string(lit) - ) - ); - return None; - } - } -} - -fn as_uri(path: &Path) -> String { - let mut s = String::new(); - for component in path.iter() { - s.push_str(component.to_str().expect("Only UTF-8 filenames are supported.")); - s.push('/'); - } - s[0..s.len()-1].into() -} - -#[test] -fn should_convert_path_separators_on_all_platforms() { - // given - let p = { - let mut p = PathBuf::new(); - p.push("web"); - p.push("src"); - p.push("index.html"); - p - }; - - // when - let path = as_uri(&p); - - // then - assert_eq!(path, "web/src/index.html".to_owned()); -} diff --git a/dapps/js-glue/src/js.rs b/dapps/js-glue/src/js.rs deleted file mode 100644 index 906b238ec72..00000000000 --- a/dapps/js-glue/src/js.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -#![cfg_attr(feature = "use-precompiled-js", allow(dead_code))] -#![cfg_attr(feature = "use-precompiled-js", allow(unused_imports))] - -use std::fmt; -use std::process::Command; - -#[cfg(not(windows))] -mod platform { - use std::process::Command; - - pub static NPM_CMD: &'static str = "npm"; - pub fn handle_cmd(cmd: &mut Command) -> &mut Command { - cmd - } -} - -#[cfg(windows)] -mod platform { - use std::process::{Command, Stdio}; - - pub static NPM_CMD: &'static str = "cmd.exe"; - // NOTE [ToDr] For some reason on windows - // The command doesn't have %~dp0 set properly - // and it cannot load globally installed node.exe - pub fn handle_cmd(cmd: &mut Command) -> &mut Command { - cmd.stdin(Stdio::null()) - .arg("/c") - .arg("npm.cmd") - } -} - -fn die(s: &'static str, e: T) -> ! { - panic!("Error: {}: {:?}", s, e); -} - -#[cfg(feature = "use-precompiled-js")] -pub fn test(_path: &str) { -} -#[cfg(feature = "use-precompiled-js")] -pub fn build(_path: &str, _dest: &str) { -} - -#[cfg(not(feature = "use-precompiled-js"))] -pub fn build(path: &str, dest: &str) { - let child = platform::handle_cmd(&mut Command::new(platform::NPM_CMD)) - .arg("install") - .arg("--no-progress") - .current_dir(path) - .status() - .unwrap_or_else(|e| die("Installing node.js dependencies with npm", e)); - assert!(child.success(), "There was an error installing dependencies."); - - let child = platform::handle_cmd(&mut Command::new(platform::NPM_CMD)) - .arg("run") - .arg("build") - .env("NODE_ENV", "production") - .env("BUILD_DEST", dest) - .current_dir(path) - .status() - .unwrap_or_else(|e| die("Building JS code", e)); - assert!(child.success(), "There was an error build JS code."); -} - -#[cfg(not(feature = "use-precompiled-js"))] -pub fn test(path: &str) { - let child = Command::new(platform::NPM_CMD) - .arg("run") - .arg("test") - .current_dir(path) - .status() - .unwrap_or_else(|e| die("Running test command", e)); - assert!(child.success(), "There was an error while running JS tests."); -} diff --git a/dapps/js-glue/src/lib.rs b/dapps/js-glue/src/lib.rs deleted file mode 100644 index f8ada2541e9..00000000000 --- a/dapps/js-glue/src/lib.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))] -#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))] - -#[cfg(feature = "with-syntex")] -extern crate syntex; - -#[cfg(feature = "with-syntex")] -extern crate syntex_syntax as syntax; - -#[cfg(feature = "with-syntex")] -include!(concat!(env!("OUT_DIR"), "/lib.rs")); - -#[cfg(not(feature = "with-syntex"))] -#[macro_use] -extern crate syntax; - -#[cfg(not(feature = "with-syntex"))] -extern crate rustc_plugin; - -#[cfg(not(feature = "with-syntex"))] -include!("lib.rs.in"); diff --git a/dapps/js-glue/src/lib.rs.in b/dapps/js-glue/src/lib.rs.in deleted file mode 100644 index b78eae10984..00000000000 --- a/dapps/js-glue/src/lib.rs.in +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - - -extern crate quasi; - -mod codegen; -mod build; -pub mod js; -pub use build::inner::generate; - -use std::default::Default; - -#[derive(Clone)] -pub struct File { - pub path: &'static str, - pub content: &'static [u8], - // TODO: use strongly-typed MIME. - pub content_type: &'static str, -} - -#[derive(Clone, Debug)] -pub struct Info { - pub name: &'static str, - pub version: &'static str, - pub author: &'static str, - pub description: &'static str, - pub icon_url: &'static str, -} - -pub trait WebApp : Default + Send + Sync { - fn file(&self, path: &str) -> Option<&File>; - fn info(&self) -> Info; -} diff --git a/dapps/res/gavcoin.zip b/dapps/res/gavcoin.zip deleted file mode 100644 index 3ced8c5c1d8..00000000000 Binary files a/dapps/res/gavcoin.zip and /dev/null differ diff --git a/dapps/src/api/api.rs b/dapps/src/api/api.rs deleted file mode 100644 index e6bba899f9a..00000000000 --- a/dapps/src/api/api.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::sync::Arc; - -use hyper::{Method, StatusCode}; - -use api::response; -use apps::fetcher::Fetcher; -use endpoint::{Endpoint, Request, Response, EndpointPath}; -use futures::{future, Future}; -use node_health::{NodeHealth, HealthStatus}; - -#[derive(Clone)] -pub struct RestApi { - fetcher: Arc, - health: NodeHealth, -} - -impl Endpoint for RestApi { - fn respond(&self, mut path: EndpointPath, req: Request) -> Response { - if let Method::Options = *req.method() { - return Box::new(future::ok(response::empty())); - } - - let endpoint = path.app_params.get(0).map(String::to_owned); - let hash = path.app_params.get(1).map(String::to_owned); - - // at this point path.app_id contains 'api', adjust it to the hash properly, otherwise - // we will try and retrieve 'api' as the hash when doing the /api/content route - if let Some(ref hash) = hash { - path.app_id = hash.to_owned(); - } - - trace!(target: "dapps", "Handling /api request: {:?}/{:?}", endpoint, hash); - match endpoint.as_ref().map(String::as_str) { - Some("ping") => Box::new(future::ok(response::ping(req))), - Some("health") => self.health(), - Some("content") => self.resolve_content(hash.as_ref().map(String::as_str), path, req), - _ => Box::new(future::ok(response::not_found())), - } - } -} - -impl RestApi { - pub fn new( - fetcher: Arc, - health: NodeHealth, - ) -> Box { - Box::new(RestApi { - fetcher, - health, - }) - } - - fn resolve_content(&self, hash: Option<&str>, path: EndpointPath, req: Request) -> Response { - trace!(target: "dapps", "Resolving content: {:?} from path: {:?}", hash, path); - match hash { - Some(hash) if self.fetcher.contains(hash) => { - self.fetcher.respond(path, req) - }, - _ => Box::new(future::ok(response::not_found())), - } - } - - fn health(&self) -> Response { - Box::new(self.health.health() - .then(|health| { - let status = match health { - Ok(ref health) => { - if [&health.peers.status, &health.sync.status].iter().any(|x| *x != &HealthStatus::Ok) { - StatusCode::PreconditionFailed // HTTP 412 - } else { - StatusCode::Ok // HTTP 200 - } - }, - _ => StatusCode::ServiceUnavailable, // HTTP 503 - }; - - Ok(response::as_json(status, &health).into()) - }) - ) - } -} diff --git a/dapps/src/api/mod.rs b/dapps/src/api/mod.rs deleted file mode 100644 index c18eb189ea5..00000000000 --- a/dapps/src/api/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! REST API - -mod api; -mod response; -mod types; - -pub use self::api::RestApi; diff --git a/dapps/src/api/response.rs b/dapps/src/api/response.rs deleted file mode 100644 index 5fe81eaa19d..00000000000 --- a/dapps/src/api/response.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use serde::Serialize; -use serde_json; -use hyper::{self, mime, StatusCode}; - -use handlers::{ContentHandler, EchoHandler}; - -pub fn empty() -> hyper::Response { - ContentHandler::ok("".into(), mime::TEXT_PLAIN).into() -} - -pub fn as_json(status: StatusCode, val: &T) -> hyper::Response { - let json = serde_json::to_string(val) - .expect("serialization to string is infallible; qed"); - ContentHandler::new(status, json, mime::APPLICATION_JSON).into() -} - -pub fn ping(req: hyper::Request) -> hyper::Response { - EchoHandler::new(req).into() -} - -pub fn not_found() -> hyper::Response { - as_json(StatusCode::NotFound, &::api::types::ApiError { - code: "404".into(), - title: "Not Found".into(), - detail: "Resource you requested has not been found.".into(), - }) -} diff --git a/dapps/src/api/types.rs b/dapps/src/api/types.rs deleted file mode 100644 index 8bc451a849d..00000000000 --- a/dapps/src/api/types.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -/// A structure representing any error in REST API. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct ApiError { - /// Error code. - pub code: String, - /// Human-readable error summary. - pub title: String, - /// More technical error details. - pub detail: String, -} diff --git a/dapps/src/apps/app.rs b/dapps/src/apps/app.rs deleted file mode 100644 index 15468b4f1d6..00000000000 --- a/dapps/src/apps/app.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct App { - pub id: Option, - pub name: String, - pub description: String, - pub version: String, - pub author: String, - #[serde(rename="iconUrl")] - pub icon_url: String, - #[serde(rename="localUrl")] - pub local_url: Option, - #[serde(rename="allowJsEval")] - pub allow_js_eval: Option, -} - -impl App { - pub fn with_id(&self, id: &str) -> Self { - let mut app = self.clone(); - app.id = Some(id.into()); - app - } -} diff --git a/dapps/src/apps/cache.rs b/dapps/src/apps/cache.rs deleted file mode 100644 index b93acfaece1..00000000000 --- a/dapps/src/apps/cache.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Fetchable Dapps support. - -use std::fs; - -use linked_hash_map::LinkedHashMap; -use page::local; -use handlers::FetchControl; - -pub enum ContentStatus { - Fetching(FetchControl), - Ready(local::Dapp), -} - -#[derive(Default)] -pub struct ContentCache { - cache: LinkedHashMap, -} - -impl ContentCache { - pub fn insert(&mut self, content_id: String, status: ContentStatus) -> Option { - self.cache.insert(content_id, status) - } - - pub fn remove(&mut self, content_id: &str) -> Option { - self.cache.remove(content_id) - } - - pub fn get(&mut self, content_id: &str) -> Option<&mut ContentStatus> { - self.cache.get_refresh(content_id) - } - - pub fn clear_garbage(&mut self, expected_size: usize) -> Vec<(String, ContentStatus)> { - let len = self.cache.len(); - - if len <= expected_size { - return Vec::new(); - } - - let mut removed = Vec::with_capacity(len - expected_size); - - while self.cache.len() > expected_size { - let entry = self.cache.pop_front().expect("expected_size bounded at 0, len is greater; qed"); - - match entry.1 { - ContentStatus::Fetching(ref fetch) => { - trace!(target: "dapps", "Aborting {} because of limit.", entry.0); - // Mark as aborted - fetch.abort() - }, - ContentStatus::Ready(ref endpoint) => { - trace!(target: "dapps", "Removing {} because of limit.", entry.0); - // Remove path (dir or file) - let res = fs::remove_dir_all(&endpoint.path()).or_else(|_| fs::remove_file(&endpoint.path())); - if let Err(e) = res { - warn!(target: "dapps", "Unable to remove dapp/content from cache: {:?}", e); - } - } - } - - removed.push(entry); - } - removed - } - - #[cfg(test)] - pub fn len(&self) -> usize { - self.cache.len() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn only_keys(data: Vec<(String, ContentStatus)>) -> Vec { - data.into_iter().map(|x| x.0).collect() - } - - #[test] - fn should_remove_least_recently_used() { - // given - let mut cache = ContentCache::default(); - cache.insert("a".into(), ContentStatus::Fetching(Default::default())); - cache.insert("b".into(), ContentStatus::Fetching(Default::default())); - cache.insert("c".into(), ContentStatus::Fetching(Default::default())); - - // when - let res = cache.clear_garbage(2); - - // then - assert_eq!(cache.len(), 2); - assert_eq!(only_keys(res), vec!["a"]); - } - - #[test] - fn should_update_lru_if_accessed() { - // given - let mut cache = ContentCache::default(); - cache.insert("a".into(), ContentStatus::Fetching(Default::default())); - cache.insert("b".into(), ContentStatus::Fetching(Default::default())); - cache.insert("c".into(), ContentStatus::Fetching(Default::default())); - - // when - cache.get("a"); - let res = cache.clear_garbage(2); - - // then - assert_eq!(cache.len(), 2); - assert_eq!(only_keys(res), vec!["b"]); - } - -} diff --git a/dapps/src/apps/fetcher/installers.rs b/dapps/src/apps/fetcher/installers.rs deleted file mode 100644 index 9fba80aabec..00000000000 --- a/dapps/src/apps/fetcher/installers.rs +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use zip; -use std::{fs, fmt}; -use std::io::{self, Read, Write}; -use std::path::PathBuf; -use ethereum_types::H256; -use fetch; -use futures_cpupool::CpuPool; -use hash::keccak_pipe; -use mime_guess::Mime; - -use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; -use handlers::{ContentValidator, ValidatorResponse}; -use page::{local, PageCache}; - -type OnDone = Box) + Send>; - -fn write_response_and_check_hash( - id: &str, - mut content_path: PathBuf, - filename: &str, - response: fetch::Response -) -> Result<(fs::File, PathBuf), ValidationError> { - // try to parse id - let id = id.parse().map_err(|_| ValidationError::InvalidContentId)?; - - // check if content exists - if content_path.exists() { - warn!(target: "dapps", "Overwriting existing content at 0x{:?}", id); - fs::remove_dir_all(&content_path)? - } - - // create directory - fs::create_dir_all(&content_path)?; - - // append filename - content_path.push(filename); - - // Now write the response - let mut file = io::BufWriter::new(fs::File::create(&content_path)?); - let mut reader = io::BufReader::new(fetch::BodyReader::new(response)); - let hash = keccak_pipe(&mut reader, &mut file)?; - let mut file = file.into_inner()?; - file.flush()?; - - // Validate hash - if id == hash { - // The writing above changed the file Read position, which we need later. So we just create a new file handle - // here. - Ok((fs::File::open(&content_path)?, content_path)) - } else { - Err(ValidationError::HashMismatch { - expected: id, - got: hash, - }) - } -} - -pub struct Content { - id: String, - mime: Mime, - content_path: PathBuf, - on_done: OnDone, - pool: CpuPool, -} - -impl Content { - pub fn new(id: String, mime: Mime, content_path: PathBuf, on_done: OnDone, pool: CpuPool) -> Self { - Content { - id, - mime, - content_path, - on_done, - pool, - } - } -} - -impl ContentValidator for Content { - type Error = ValidationError; - - fn validate_and_install(self, response: fetch::Response) -> Result { - let pool = self.pool; - let id = self.id.clone(); - let mime = self.mime; - let validate = move |content_path: PathBuf| { - // Create dir - let (_, content_path) = write_response_and_check_hash(&id, content_path, &id, response)?; - - Ok(local::Dapp::single_file(pool, content_path, mime, PageCache::Enabled)) - }; - - // Prepare path for a file - let content_path = self.content_path.join(&self.id); - // Make sure to always call on_done (even in case of errors)! - let result = validate(content_path.clone()); - // remove the file if there was an error - if result.is_err() { - // Ignore errors since the file might not exist - let _ = fs::remove_dir_all(&content_path); - } - (self.on_done)(result.as_ref().ok().cloned()); - result.map(ValidatorResponse::Local) - } -} - -pub struct Dapp { - id: String, - dapps_path: PathBuf, - on_done: OnDone, - pool: CpuPool, -} - -impl Dapp { - pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, pool: CpuPool) -> Self { - Dapp { - id, - dapps_path, - on_done, - pool, - } - } - - fn find_manifest(zip: &mut zip::ZipArchive) -> Result<(Manifest, PathBuf), ValidationError> { - for i in 0..zip.len() { - let mut file = zip.by_index(i)?; - - if !file.name().ends_with(MANIFEST_FILENAME) { - continue; - } - - // try to read manifest - let mut manifest = String::new(); - let manifest = file - .read_to_string(&mut manifest).ok() - .and_then(|_| deserialize_manifest(manifest).ok()); - - if let Some(manifest) = manifest { - let mut manifest_location = PathBuf::from(file.name()); - manifest_location.pop(); // get rid of filename - return Ok((manifest, manifest_location)); - } - } - - Err(ValidationError::ManifestNotFound) - } -} - -impl ContentValidator for Dapp { - type Error = ValidationError; - - fn validate_and_install(self, response: fetch::Response) -> Result { - let id = self.id.clone(); - let pool = self.pool; - let validate = move |dapp_path: PathBuf| { - let (file, zip_path) = write_response_and_check_hash(&id, dapp_path.clone(), &format!("{}.zip", id), response)?; - trace!(target: "dapps", "Opening dapp bundle at {:?}", zip_path); - // Unpack archive - let mut zip = zip::ZipArchive::new(file)?; - // First find manifest file - let (mut manifest, manifest_dir) = Self::find_manifest(&mut zip)?; - // Overwrite id to match hash - manifest.id = Some(id); - - // Unpack zip - for i in 0..zip.len() { - let mut file = zip.by_index(i)?; - let is_dir = file.name().chars().rev().next() == Some('/'); - - let file_path = PathBuf::from(file.name()); - let location_in_manifest_base = file_path.strip_prefix(&manifest_dir); - // Create files that are inside manifest directory - if let Ok(location_in_manifest_base) = location_in_manifest_base { - let p = dapp_path.join(location_in_manifest_base); - // Check if it's a directory - if is_dir { - fs::create_dir_all(p)?; - } else { - let mut target = fs::File::create(p)?; - io::copy(&mut file, &mut target)?; - } - } - } - - // Remove zip - fs::remove_file(&zip_path)?; - - // Write manifest - let manifest_str = serialize_manifest(&manifest).map_err(ValidationError::ManifestSerialization)?; - let manifest_path = dapp_path.join(MANIFEST_FILENAME); - let mut manifest_file = fs::File::create(manifest_path)?; - manifest_file.write_all(manifest_str.as_bytes())?; - // Create endpoint - let endpoint = local::Dapp::new(pool, dapp_path, manifest.into(), PageCache::Enabled); - Ok(endpoint) - }; - - // Prepare directory for dapp - let target = self.dapps_path.join(&self.id); - // Validate the dapp - let result = validate(target.clone()); - // remove the file if there was an error - if result.is_err() { - // Ignore errors since the file might not exist - let _ = fs::remove_dir_all(&target); - } - (self.on_done)(result.as_ref().ok().cloned()); - result.map(ValidatorResponse::Local) - } -} - -#[derive(Debug)] -pub enum ValidationError { - Io(io::Error), - Zip(zip::result::ZipError), - InvalidContentId, - ManifestNotFound, - ManifestSerialization(String), - HashMismatch { expected: H256, got: H256, }, -} - -impl fmt::Display for ValidationError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - ValidationError::Io(ref io) => write!(f, "Unexpected IO error occured: {:?}", io), - ValidationError::Zip(ref zip) => write!(f, "Unable to read ZIP archive: {:?}", zip), - ValidationError::InvalidContentId => write!(f, "ID is invalid. It should be 256 bits keccak hash of content."), - ValidationError::ManifestNotFound => write!(f, "Downloaded Dapp bundle did not contain valid manifest.json file."), - ValidationError::ManifestSerialization(ref err) => { - write!(f, "There was an error during Dapp Manifest serialization: {:?}", err) - }, - ValidationError::HashMismatch { ref expected, ref got } => { - write!(f, "Hash of downloaded content did not match. Expected:{:?}, Got:{:?}.", expected, got) - }, - } - } -} - -impl From for ValidationError { - fn from(err: io::Error) -> Self { - ValidationError::Io(err) - } -} - -impl From for ValidationError { - fn from(err: zip::result::ZipError) -> Self { - ValidationError::Zip(err) - } -} - -impl From>> for ValidationError { - fn from(err: io::IntoInnerError>) -> Self { - ValidationError::Io(err.into()) - } -} diff --git a/dapps/src/apps/fetcher/mod.rs b/dapps/src/apps/fetcher/mod.rs deleted file mode 100644 index a7afd91eed1..00000000000 --- a/dapps/src/apps/fetcher/mod.rs +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Fetchable Dapps support. -//! Manages downloaded (cached) Dapps and downloads them when necessary. -//! Uses `URLHint` to resolve addresses into Dapps bundle file location. - -mod installers; - -use std::{fs, env}; -use std::path::PathBuf; -use std::sync::Arc; -use futures::{future, Future}; -use futures_cpupool::CpuPool; -use fetch::{Client as FetchClient, Fetch}; -use hash_fetch::urlhint::{URLHintContract, URLHint, URLHintResult}; - -use hyper::StatusCode; - -use ethereum_types::H256; -use {SyncStatus, random_filename}; -use parking_lot::Mutex; -use page::local; -use handlers::{ContentHandler, ContentFetcherHandler}; -use endpoint::{self, Endpoint, EndpointPath}; -use apps::cache::{ContentCache, ContentStatus}; - -/// Limit of cached dapps/content -const MAX_CACHED_DAPPS: usize = 20; - -pub trait Fetcher: Endpoint + 'static { - fn contains(&self, content_id: &str) -> bool; -} - -pub struct ContentFetcher { - cache_path: PathBuf, - resolver: R, - cache: Arc>, - sync: Arc, - fetch: F, - pool: CpuPool, - only_content: bool, -} - -impl Drop for ContentFetcher { - fn drop(&mut self) { - // Clear cache path - let _ = fs::remove_dir_all(&self.cache_path); - } -} - -impl ContentFetcher { - pub fn new( - resolver: R, - sync: Arc, - fetch: F, - pool: CpuPool, - ) -> Self { - let mut cache_path = env::temp_dir(); - cache_path.push(random_filename()); - - ContentFetcher { - cache_path, - resolver, - sync, - cache: Arc::new(Mutex::new(ContentCache::default())), - fetch, - pool, - only_content: true, - } - } - - pub fn allow_dapps(mut self, dapps: bool) -> Self { - self.only_content = !dapps; - self - } - - fn not_found() -> endpoint::Response { - Box::new(future::ok(ContentHandler::error( - StatusCode::NotFound, - "Resource Not Found", - "Requested resource was not found.", - None, - ).into())) - } - - fn still_syncing() -> endpoint::Response { - Box::new(future::ok(ContentHandler::error( - StatusCode::ServiceUnavailable, - "Sync In Progress", - "Your node is still syncing. We cannot resolve any content before it's fully synced.", - Some("Refresh"), - ).into())) - } - - fn dapps_disabled() -> endpoint::Response { - Box::new(future::ok(ContentHandler::error( - StatusCode::ServiceUnavailable, - "Network Dapps Not Available", - "This interface doesn't support network dapps for security reasons.", - None, - ).into())) - } - - #[cfg(test)] - fn set_status(&self, content_id: &str, status: ContentStatus) { - self.cache.lock().insert(content_id.to_owned(), status); - } - - // resolve contract call synchronously. - // TODO: port to futures-based hyper and make it all async. - fn resolve(&self, content_id: H256) -> Option { - self.resolver.resolve(content_id) - .wait() - .unwrap_or_else(|e| { warn!("Error resolving content-id: {}", e); None }) - } -} - -impl Fetcher for ContentFetcher { - fn contains(&self, content_id: &str) -> bool { - { - let mut cache = self.cache.lock(); - // Check if we already have the app - if cache.get(content_id).is_some() { - return true; - } - } - // fallback to resolver - if let Ok(content_id) = content_id.parse() { - // if there is content or we are syncing return true - self.sync.is_major_importing() || self.resolve(content_id).is_some() - } else { - false - } - } -} - -impl Endpoint for ContentFetcher { - fn respond(&self, path: EndpointPath, req: endpoint::Request) -> endpoint::Response { - let mut cache = self.cache.lock(); - let content_id = path.app_id.clone(); - - let (new_status, handler) = { - let status = cache.get(&content_id); - match status { - // Just serve the content - Some(&mut ContentStatus::Ready(ref endpoint)) => { - (None, endpoint.to_response(&path)) - }, - // Content is already being fetched - Some(&mut ContentStatus::Fetching(ref fetch_control)) if !fetch_control.is_deadline_reached() => { - trace!(target: "dapps", "Content fetching in progress. Waiting..."); - (None, fetch_control.to_response(path)) - }, - // We need to start fetching the content - _ => { - trace!(target: "dapps", "Content unavailable. Fetching... {:?}", content_id); - let content_hex = content_id.parse().expect("to_handler is called only when `contains` returns true."); - let content = self.resolve(content_hex); - - let cache = self.cache.clone(); - let id = content_id.clone(); - let on_done = move |result: Option| { - let mut cache = cache.lock(); - match result { - Some(endpoint) => cache.insert(id.clone(), ContentStatus::Ready(endpoint)), - // In case of error - None => cache.remove(&id), - }; - }; - - match content { - // Don't serve dapps if we are still syncing (but serve content) - Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => { - (None, Self::still_syncing()) - }, - Some(URLHintResult::Dapp(_)) if self.only_content => { - (None, Self::dapps_disabled()) - }, - Some(content) => { - let handler = match content { - URLHintResult::Dapp(dapp) => { - ContentFetcherHandler::new( - req.method(), - &dapp.url(), - path, - installers::Dapp::new( - content_id.clone(), - self.cache_path.clone(), - Box::new(on_done), - self.pool.clone(), - ), - self.fetch.clone(), - self.pool.clone(), - ) - }, - URLHintResult::GithubDapp(content) => { - ContentFetcherHandler::new( - req.method(), - &content.url, - path, - installers::Dapp::new( - content_id.clone(), - self.cache_path.clone(), - Box::new(on_done), - self.pool.clone(), - ), - self.fetch.clone(), - self.pool.clone(), - ) - }, - URLHintResult::Content(content) => { - ContentFetcherHandler::new( - req.method(), - &content.url, - path, - installers::Content::new( - content_id.clone(), - content.mime, - self.cache_path.clone(), - Box::new(on_done), - self.pool.clone(), - ), - self.fetch.clone(), - self.pool.clone(), - ) - }, - }; - - (Some(ContentStatus::Fetching(handler.fetch_control())), Box::new(handler) as endpoint::Response) - }, - None if self.sync.is_major_importing() => { - (None, Self::still_syncing()) - }, - None => { - // This may happen when sync status changes in between - // `contains` and `to_handler` - (None, Self::not_found()) - }, - } - }, - } - }; - - if let Some(status) = new_status { - cache.clear_garbage(MAX_CACHED_DAPPS); - cache.insert(content_id, status); - } - - handler - } -} - -#[cfg(test)] -mod tests { - use std::env; - use std::sync::Arc; - use fetch::Client; - use futures::{future, Future}; - use hash_fetch::urlhint::{URLHint, URLHintResult}; - use ethereum_types::H256; - - use apps::cache::ContentStatus; - use endpoint::EndpointInfo; - use page::local; - use super::{ContentFetcher, Fetcher}; - use {SyncStatus}; - - #[derive(Clone)] - struct FakeResolver; - impl URLHint for FakeResolver { - fn resolve(&self, _id: H256) -> Box, Error = String> + Send> { - Box::new(future::ok(None)) - } - } - - #[derive(Debug)] - struct FakeSync(bool); - impl SyncStatus for FakeSync { - fn is_major_importing(&self) -> bool { self.0 } - fn peers(&self) -> (usize, usize) { (0, 5) } - } - - #[test] - fn should_true_if_contains_the_app() { - // given - let pool = ::futures_cpupool::CpuPool::new(1); - let path = env::temp_dir(); - let fetcher = ContentFetcher::new( - FakeResolver, - Arc::new(FakeSync(false)), - Client::new().unwrap(), - pool.clone(), - ).allow_dapps(true); - - let handler = local::Dapp::new(pool, path, EndpointInfo { - id: None, - name: "fake".into(), - description: "".into(), - version: "".into(), - author: "".into(), - icon_url: "".into(), - local_url: Some("".into()), - allow_js_eval: None, - }, Default::default()); - - // when - fetcher.set_status("test", ContentStatus::Ready(handler)); - fetcher.set_status("test2", ContentStatus::Fetching(Default::default())); - - // then - assert_eq!(fetcher.contains("test"), true); - assert_eq!(fetcher.contains("test2"), true); - assert_eq!(fetcher.contains("test3"), false); - } -} diff --git a/dapps/src/apps/fs.rs b/dapps/src/apps/fs.rs deleted file mode 100644 index 975f3067eee..00000000000 --- a/dapps/src/apps/fs.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::collections::BTreeMap; -use std::io; -use std::io::Read; -use std::fs; -use std::path::{Path, PathBuf}; -use futures_cpupool::CpuPool; - -use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest}; -use endpoint::{Endpoint, EndpointInfo}; -use page::{local, PageCache}; - -struct LocalDapp { - id: String, - path: PathBuf, - info: EndpointInfo, -} - -/// Tries to find and read manifest file in given `path` to extract `EndpointInfo` -/// If manifest is not found sensible default `EndpointInfo` is returned based on given `name`. -fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo { - path.push(MANIFEST_FILENAME); - - fs::File::open(path.clone()) - .map_err(|e| format!("{:?}", e)) - .and_then(|mut f| { - // Reat file - let mut s = String::new(); - f.read_to_string(&mut s).map_err(|e| format!("{:?}", e))?; - // Try to deserialize manifest - deserialize_manifest(s) - }) - .unwrap_or_else(|e| { - warn!(target: "dapps", "Cannot read manifest file at: {:?}. Error: {:?}", path, e); - - EndpointInfo { - id: None, - name: name.into(), - description: name.into(), - version: "0.0.0".into(), - author: "?".into(), - icon_url: "icon.png".into(), - local_url: None, - allow_js_eval: Some(false), - } - }) -} - -/// Returns Dapp Id and Local Dapp Endpoint for given filesystem path. -/// Parses the path to extract last component (for name). -/// `None` is returned when path is invalid or non-existent. -pub fn local_endpoint>(path: P, pool: CpuPool) -> Option<(String, Box)> { - let path = path.as_ref().to_owned(); - path.canonicalize().ok().and_then(|path| { - let name = path.file_name().and_then(|name| name.to_str()); - name.map(|name| { - let dapp = local_dapp(name.into(), path.clone()); - (dapp.id, Box::new(local::Dapp::new( - pool.clone(), dapp.path, dapp.info, PageCache::Disabled) - )) - }) - }) -} - -fn local_dapp(name: String, path: PathBuf) -> LocalDapp { - // try to get manifest file - let info = read_manifest(&name, path.clone()); - LocalDapp { - id: name, - path: path, - info: info, - } -} - -/// Returns endpoints for Local Dapps found for given filesystem path. -/// Scans the directory and collects `local::Dapp`. -pub fn local_endpoints>(dapps_path: P, pool: CpuPool) -> BTreeMap> { - let mut pages = BTreeMap::>::new(); - for dapp in local_dapps(dapps_path.as_ref()) { - pages.insert( - dapp.id, - Box::new(local::Dapp::new(pool.clone(), dapp.path, dapp.info, PageCache::Disabled)) - ); - } - pages -} - -fn local_dapps(dapps_path: &Path) -> Vec { - let files = fs::read_dir(dapps_path); - if let Err(e) = files { - warn!(target: "dapps", "Unable to load local dapps from: {}. Reason: {:?}", dapps_path.display(), e); - return vec![]; - } - - let files = files.expect("Check is done earlier"); - files.map(|dir| { - let entry = dir?; - let file_type = entry.file_type()?; - - // skip files - if file_type.is_file() { - return Err(io::Error::new(io::ErrorKind::NotFound, "Not a file")); - } - - // take directory name and path - entry.file_name().into_string() - .map(|name| (name, entry.path())) - .map_err(|e| { - info!(target: "dapps", "Unable to load dapp: {:?}. Reason: {:?}", entry.path(), e); - io::Error::new(io::ErrorKind::NotFound, "Invalid name") - }) - }) - .filter_map(|m| { - if let Err(ref e) = m { - debug!(target: "dapps", "Ignoring local dapp: {:?}", e); - } - m.ok() - }) - .map(|(name, path)| local_dapp(name, path)) - .collect() -} diff --git a/dapps/src/apps/manifest.rs b/dapps/src/apps/manifest.rs deleted file mode 100644 index 4d71af40fe0..00000000000 --- a/dapps/src/apps/manifest.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use serde_json; -pub use apps::App as Manifest; - -pub const MANIFEST_FILENAME: &'static str = "manifest.json"; - -pub fn deserialize_manifest(manifest: String) -> Result { - let mut manifest = serde_json::from_str::(&manifest).map_err(|e| format!("{:?}", e))?; - if manifest.id.is_none() { - return Err("App 'id' is missing.".into()); - } - manifest.allow_js_eval = Some(manifest.allow_js_eval.unwrap_or(false)); - - Ok(manifest) -} - -pub fn serialize_manifest(manifest: &Manifest) -> Result { - serde_json::to_string_pretty(manifest).map_err(|e| format!("{:?}", e)) -} diff --git a/dapps/src/apps/mod.rs b/dapps/src/apps/mod.rs deleted file mode 100644 index 3fe394b6de2..00000000000 --- a/dapps/src/apps/mod.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::path::PathBuf; -use std::sync::Arc; - -use endpoint::Endpoints; -use futures_cpupool::CpuPool; -use proxypac::ProxyPac; -use web::Web; -use fetch::Fetch; -use WebProxyTokens; - -mod app; -mod cache; -pub mod fs; -pub mod fetcher; -pub mod manifest; - -pub use self::app::App; - -pub const HOME_PAGE: &'static str = "home"; -pub const RPC_PATH: &'static str = "rpc"; -pub const API_PATH: &'static str = "api"; -pub const WEB_PATH: &'static str = "web"; -pub const URL_REFERER: &'static str = "__referer="; - -pub fn all_endpoints( - dapps_path: PathBuf, - extra_dapps: Vec, - dapps_domain: &str, - web_proxy_tokens: Arc, - fetch: F, - pool: CpuPool, -) -> (Vec, Endpoints) { - // fetch fs dapps at first to avoid overwriting builtins - let mut pages = fs::local_endpoints(dapps_path.clone(), pool.clone()); - let local_endpoints: Vec = pages.keys().cloned().collect(); - for path in extra_dapps { - if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), pool.clone()) { - pages.insert(id, endpoint); - } else { - warn!(target: "dapps", "Ignoring invalid dapp at {}", path.display()); - } - } - - pages.insert( - "proxy".into(), - ProxyPac::boxed(dapps_domain.to_owned()) - ); - pages.insert( - WEB_PATH.into(), - Web::boxed(web_proxy_tokens.clone(), fetch.clone(), pool.clone()) - ); - - (local_endpoints, pages) -} diff --git a/dapps/src/endpoint.rs b/dapps/src/endpoint.rs deleted file mode 100644 index 948f412b381..00000000000 --- a/dapps/src/endpoint.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! URL Endpoint traits - -use std::collections::BTreeMap; - -use futures::Future; -use hyper; - -#[derive(Debug, PartialEq, Default, Clone)] -pub struct EndpointPath { - pub app_id: String, - pub app_params: Vec, - pub query: Option, - pub host: String, - pub port: u16, - pub using_dapps_domains: bool, -} - -impl EndpointPath { - pub fn has_no_params(&self) -> bool { - self.app_params.is_empty() || self.app_params.iter().all(|x| x.is_empty()) - } -} - -pub type EndpointInfo = ::apps::App; -pub type Endpoints = BTreeMap>; -pub type Response = Box + Send>; -pub type Request = hyper::Request; - -pub trait Endpoint : Send + Sync { - fn info(&self) -> Option<&EndpointInfo> { None } - - fn respond(&self, path: EndpointPath, req: Request) -> Response; -} diff --git a/dapps/src/error_tpl.html b/dapps/src/error_tpl.html deleted file mode 100644 index 4b155cf35d6..00000000000 --- a/dapps/src/error_tpl.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - {title} - - - -
-
-
-

{title}

-

{message}

-

{details}

-
-
- {version} -
- - diff --git a/dapps/src/handlers/content.rs b/dapps/src/handlers/content.rs deleted file mode 100644 index 9449f0f796b..00000000000 --- a/dapps/src/handlers/content.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Simple Content Handler - -use hyper::{self, mime, header}; -use hyper::StatusCode; - -use parity_version::version; - -use handlers::add_security_headers; - -#[derive(Debug, Clone)] -pub struct ContentHandler { - code: StatusCode, - content: String, - mimetype: mime::Mime, -} - -impl ContentHandler { - pub fn ok(content: String, mimetype: mime::Mime) -> Self { - Self::new(StatusCode::Ok, content, mimetype) - } - - pub fn html(code: StatusCode, content: String) -> Self { - Self::new(code, content, mime::TEXT_HTML) - } - - pub fn error( - code: StatusCode, - title: &str, - message: &str, - details: Option<&str>, - ) -> Self { - Self::html(code, format!( - include_str!("../error_tpl.html"), - title=title, - message=message, - details=details.unwrap_or_else(|| ""), - version=version(), - )) - } - - pub fn new( - code: StatusCode, - content: String, - mimetype: mime::Mime, - ) -> Self { - ContentHandler { - code, - content, - mimetype, - } - } -} - -impl Into for ContentHandler { - fn into(self) -> hyper::Response { - let mut res = hyper::Response::new() - .with_status(self.code) - .with_header(header::ContentType(self.mimetype)) - .with_body(self.content); - add_security_headers(&mut res.headers_mut(), false); - res - } -} diff --git a/dapps/src/handlers/echo.rs b/dapps/src/handlers/echo.rs deleted file mode 100644 index 03dfd1c974c..00000000000 --- a/dapps/src/handlers/echo.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Echo Handler - -use hyper::{self, header}; - -use handlers::add_security_headers; - -#[derive(Debug)] -pub struct EchoHandler { - request: hyper::Request, -} - -impl EchoHandler { - pub fn new(request: hyper::Request) -> Self { - EchoHandler { - request, - } - } -} - -impl Into for EchoHandler { - fn into(self) -> hyper::Response { - let content_type = self.request.headers().get().cloned(); - let mut res = hyper::Response::new() - .with_header(content_type.unwrap_or(header::ContentType::json())) - .with_body(self.request.body()); - - add_security_headers(res.headers_mut(), false); - res - } -} diff --git a/dapps/src/handlers/errors.rs b/dapps/src/handlers/errors.rs deleted file mode 100644 index 5261dc3c158..00000000000 --- a/dapps/src/handlers/errors.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Handler errors. - -use handlers::{ContentHandler, FETCH_TIMEOUT}; -use hyper::StatusCode; -use std::fmt; - -pub fn streaming() -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Streaming Error", - "This content is being streamed in other place.", - None, - ) -} - -pub fn download_error(e: E) -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Download Error", - "There was an error when fetching the content.", - Some(&format!("{:?}", e)), - ) -} - -pub fn invalid_content(e: E) -> ContentHandler { - ContentHandler::error( - StatusCode::BadGateway, - "Invalid Dapp", - "Downloaded bundle does not contain a valid content.", - Some(&format!("{:?}", e)), - ) -} - -pub fn timeout_error() -> ContentHandler { - ContentHandler::error( - StatusCode::GatewayTimeout, - "Download Timeout", - &format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT.as_secs()), - None, - ) -} - -pub fn method_not_allowed() -> ContentHandler { - ContentHandler::error( - StatusCode::MethodNotAllowed, - "Method Not Allowed", - "Only GET requests are allowed.", - None, - ) -} diff --git a/dapps/src/handlers/fetch.rs b/dapps/src/handlers/fetch.rs deleted file mode 100644 index 3fee3b1fec1..00000000000 --- a/dapps/src/handlers/fetch.rs +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Hyper Server Handler that fetches a file during a request (proxy). - -use std::{fmt, mem}; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::Instant; -use fetch::{self, Fetch}; -use futures::sync::oneshot; -use futures::{self, Future}; -use futures_cpupool::CpuPool; -use hyper; -use parking_lot::Mutex; - -use endpoint::{self, EndpointPath}; -use handlers::{ContentHandler, StreamingHandler, FETCH_TIMEOUT, errors}; -use page::local; - -pub enum ValidatorResponse { - Local(local::Dapp), - Streaming(StreamingHandler), -} - -pub trait ContentValidator: Sized + Send + 'static { - type Error: fmt::Debug + fmt::Display; - - fn validate_and_install(self, fetch::Response) -> Result; -} - -#[derive(Debug, Clone)] -pub struct FetchControl { - abort: Arc, - listeners: Arc>>>, - deadline: Instant, -} - -impl Default for FetchControl { - fn default() -> Self { - FetchControl { - abort: Arc::new(AtomicBool::new(false)), - listeners: Arc::new(Mutex::new(Vec::new())), - deadline: Instant::now() + FETCH_TIMEOUT, - } - } -} - -impl FetchControl { - pub fn is_deadline_reached(&self) -> bool { - self.deadline < Instant::now() - } - - pub fn abort(&self) { - self.abort.store(true, Ordering::SeqCst); - } - - pub fn to_response(&self, path: EndpointPath) -> endpoint::Response { - let (tx, receiver) = oneshot::channel(); - self.listeners.lock().push(tx); - - Box::new(WaitingHandler { - path, - state: WaitState::Waiting(receiver), - }) - } - - fn notify WaitResult>(&self, status: F) { - let mut listeners = self.listeners.lock(); - for sender in listeners.drain(..) { - trace!(target: "dapps", "Resuming request waiting for content..."); - if let Err(_) = sender.send(status()) { - trace!(target: "dapps", "Waiting listener notification failed."); - } - } - } - - fn set_status(&self, status: &FetchState) { - match *status { - FetchState::Error(ref handler) => self.notify(|| WaitResult::Error(handler.clone())), - FetchState::Done(ref endpoint, _) => self.notify(|| WaitResult::Done(endpoint.clone())), - FetchState::Streaming(_) => self.notify(|| WaitResult::NonAwaitable), - FetchState::InProgress(_) => {}, - FetchState::Empty => {}, - } - } -} - -enum WaitState { - Waiting(oneshot::Receiver), - Done(endpoint::Response), -} - -#[derive(Debug)] -enum WaitResult { - Error(ContentHandler), - Done(local::Dapp), - NonAwaitable, -} - -pub struct WaitingHandler { - path: EndpointPath, - state: WaitState, -} - -impl Future for WaitingHandler { - type Item = hyper::Response; - type Error = hyper::Error; - - fn poll(&mut self) -> futures::Poll { - loop { - let new_state = match self.state { - WaitState::Waiting(ref mut receiver) => { - let result = try_ready!(receiver.poll().map_err(|_| hyper::Error::Timeout)); - - match result { - WaitResult::Error(handler) => { - return Ok(futures::Async::Ready(handler.into())); - }, - WaitResult::NonAwaitable => { - return Ok(futures::Async::Ready(errors::streaming().into())); - }, - WaitResult::Done(endpoint) => { - WaitState::Done(endpoint.to_response(&self.path).into()) - }, - } - }, - WaitState::Done(ref mut response) => { - return response.poll() - }, - }; - - self.state = new_state; - } - } -} - -enum FetchState { - Error(ContentHandler), - InProgress(Box + Send>), - Streaming(hyper::Response), - Done(local::Dapp, endpoint::Response), - Empty, -} - -impl fmt::Debug for FetchState { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - use self::FetchState::*; - - write!(fmt, "FetchState(")?; - match *self { - Error(ref error) => write!(fmt, "error: {:?}", error), - InProgress(_) => write!(fmt, "in progress"), - Streaming(ref res) => write!(fmt, "streaming: {:?}", res), - Done(ref endpoint, _) => write!(fmt, "done: {:?}", endpoint), - Empty => write!(fmt, "?"), - }?; - write!(fmt, ")") - } -} - -#[derive(Debug)] -pub struct ContentFetcherHandler { - fetch_control: FetchControl, - status: FetchState, -} - -impl ContentFetcherHandler { - pub fn fetch_control(&self) -> FetchControl { - self.fetch_control.clone() - } - - pub fn new( - method: &hyper::Method, - url: &str, - path: EndpointPath, - installer: H, - fetch: F, - pool: CpuPool, - ) -> Self { - let fetch_control = FetchControl::default(); - - // Validation of method - let status = match *method { - // Start fetching content - hyper::Method::Get => { - trace!(target: "dapps", "Fetching content from: {:?}", url); - FetchState::InProgress(Self::fetch_content( - pool, - fetch, - url, - fetch_control.abort.clone(), - path, - installer, - )) - }, - // or return error - _ => FetchState::Error(errors::method_not_allowed()), - }; - - ContentFetcherHandler { - fetch_control, - status, - } - } - - fn fetch_content( - pool: CpuPool, - fetch: F, - url: &str, - abort: Arc, - path: EndpointPath, - installer: H, - ) -> Box + Send> { - // Start fetching the content - let pool2 = pool.clone(); - let future = fetch.get(url, abort.into()).then(move |result| { - trace!(target: "dapps", "Fetching content finished. Starting validation: {:?}", result); - Ok(match result { - Ok(response) => match installer.validate_and_install(response) { - Ok(ValidatorResponse::Local(endpoint)) => { - trace!(target: "dapps", "Validation OK. Returning response."); - let response = endpoint.to_response(&path); - FetchState::Done(endpoint, response) - }, - Ok(ValidatorResponse::Streaming(stream)) => { - trace!(target: "dapps", "Validation OK. Streaming response."); - let (reading, response) = stream.into_response(); - pool.spawn(reading).forget(); - FetchState::Streaming(response) - }, - Err(e) => { - trace!(target: "dapps", "Error while validating content: {:?}", e); - FetchState::Error(errors::invalid_content(e)) - }, - }, - Err(e) => { - warn!(target: "dapps", "Unable to fetch content: {:?}", e); - FetchState::Error(errors::download_error(e)) - }, - }) - }); - - // make sure to run within fetch thread pool. - Box::new(pool2.spawn(future)) - } -} - -impl Future for ContentFetcherHandler { - type Item = hyper::Response; - type Error = hyper::Error; - - fn poll(&mut self) -> futures::Poll { - loop { - trace!(target: "dapps", "Polling status: {:?}", self.status); - self.status = match mem::replace(&mut self.status, FetchState::Empty) { - FetchState::Error(error) => { - return Ok(futures::Async::Ready(error.into())); - }, - FetchState::Streaming(response) => { - return Ok(futures::Async::Ready(response)); - }, - any => any, - }; - - let status = match self.status { - // Request may time out - FetchState::InProgress(_) if self.fetch_control.is_deadline_reached() => { - trace!(target: "dapps", "Fetching dapp failed because of timeout."); - FetchState::Error(errors::timeout_error()) - }, - FetchState::InProgress(ref mut receiver) => { - // Check if there is a response - trace!(target: "dapps", "Polling streaming response."); - try_ready!(receiver.poll().map_err(|err| { - warn!(target: "dapps", "Error while fetching response: {:?}", err); - hyper::Error::Timeout - })) - }, - FetchState::Done(_, ref mut response) => { - return response.poll() - }, - FetchState::Empty => panic!("Future polled twice."), - _ => unreachable!(), - }; - - trace!(target: "dapps", "New status: {:?}", status); - self.fetch_control.set_status(&status); - self.status = status; - } - } -} diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs deleted file mode 100644 index cb0eba04293..00000000000 --- a/dapps/src/handlers/mod.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Hyper handlers implementations. - -mod content; -mod echo; -mod fetch; -mod reader; -mod redirect; -mod streaming; -mod errors; - -pub use self::content::ContentHandler; -pub use self::echo::EchoHandler; -pub use self::fetch::{ContentFetcherHandler, ContentValidator, FetchControl, ValidatorResponse}; -pub use self::reader::Reader; -pub use self::redirect::Redirection; -pub use self::streaming::StreamingHandler; - -use hyper::header; -use std::time::Duration; - -const FETCH_TIMEOUT: Duration = Duration::from_secs(300); - -/// Adds security-related headers to the Response. -pub fn add_security_headers(headers: &mut header::Headers, allow_js_eval: bool) { - headers.set_raw("X-XSS-Protection", "1; mode=block"); - headers.set_raw("X-Content-Type-Options", "nosniff"); - headers.set_raw("X-Frame-Options", "SAMEORIGIN"); - - // Content Security Policy headers - headers.set_raw("Content-Security-Policy", String::new() - // Restrict everything to the same origin by default. - + "default-src 'self';" - // Allow connecting to WS servers and HTTP(S) servers. - // We could be more restrictive and allow only RPC server URL. - + "connect-src http: https: ws: wss:;" - // Allow framing any content from HTTP(S). - // Again we could only allow embedding from RPC server URL. - // (deprecated) - + "frame-src 'self' http: https:;" - // Allow framing and web workers from HTTP(S). - + "child-src 'self' http: https:;" - // We allow data: blob: and HTTP(s) images. - // We could get rid of wildcarding HTTP and only allow RPC server URL. - // (http required for local dapps icons) - + "img-src 'self' 'unsafe-inline' data: blob: http: https:;" - // Allow style from data: blob: and HTTPS. - + "style-src 'self' 'unsafe-inline' data: blob: https:;" - // Allow fonts from data: and HTTPS. - + "font-src 'self' data: https:;" - // Disallow objects - + "object-src 'none';" - // Allow scripts - + { - let script_src = ""; - let eval = if allow_js_eval { " 'unsafe-eval'" } else { "" }; - - &format!( - "script-src 'self' {}{};", - script_src, - eval - ) - } - // Same restrictions as script-src with additional - // blob: that is required for camera access (worker) - + "worker-src 'self' https: blob:;" - // Run in sandbox mode (although it's not fully safe since we allow same-origin and script) - + "sandbox allow-same-origin allow-forms allow-modals allow-popups allow-presentation allow-scripts;" - // Disallow submitting forms from any dapps - + "form-action 'none';" - // Never allow mixed content - + "block-all-mixed-content;" - // Specify if the site can be embedded. - + "frame-ancestors 'self';" - ); -} diff --git a/dapps/src/handlers/reader.rs b/dapps/src/handlers/reader.rs deleted file mode 100644 index 3b0aa5449b2..00000000000 --- a/dapps/src/handlers/reader.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! A chunk-producing io::Read wrapper. - -use std::io::{self, Read}; - -use futures::{self, sink, Sink, Future}; -use futures::sync::mpsc; -use hyper; - -type Sender = mpsc::Sender>; - -const MAX_CHUNK_SIZE: usize = 32 * 1024; - -/// A Reader is essentially a stream of `hyper::Chunks`. -/// The chunks are read from given `io::Read` instance. -/// -/// Unfortunately `hyper` doesn't allow you to pass `Stream` -/// directly to the response, so you need to create -/// a `Body::pair()` and send over chunks using `sink::Send`. -/// Also `Chunks` need to take `Vec` by value, so we need -/// to allocate it for each chunk being sent. -pub struct Reader { - buffer: [u8; MAX_CHUNK_SIZE], - content: io::BufReader, - sending: sink::Send, -} - -impl Reader { - pub fn pair(content: R, initial: Vec) -> (Self, hyper::Body) { - let (tx, rx) = hyper::Body::pair(); - let reader = Reader { - buffer: [0; MAX_CHUNK_SIZE], - content: io::BufReader::new(content), - sending: tx.send(Ok(initial.into())), - }; - - (reader, rx) - } -} - -impl Future for Reader { - type Item = (); - type Error = (); - - fn poll(&mut self) -> futures::Poll { - loop { - let next = try_ready!(self.sending.poll().map_err(|err| { - warn!(target: "dapps", "Unable to send next chunk: {:?}", err); - })); - - self.sending = match self.content.read(&mut self.buffer) { - Ok(0) => return Ok(futures::Async::Ready(())), - Ok(read) => next.send(Ok(self.buffer[..read].to_vec().into())), - Err(err) => next.send(Err(hyper::Error::Io(err))), - } - } - } -} diff --git a/dapps/src/handlers/redirect.rs b/dapps/src/handlers/redirect.rs deleted file mode 100644 index c8bf837d856..00000000000 --- a/dapps/src/handlers/redirect.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! HTTP Redirection hyper handler - -use hyper::{self, header, StatusCode}; - -#[derive(Clone)] -pub struct Redirection { - to_url: String -} - -impl Redirection { - pub fn new>(url: T) -> Self { - Redirection { - to_url: url.into() - } - } -} - -impl Into for Redirection { - fn into(self) -> hyper::Response { - // Don't use `MovedPermanently` here to prevent browser from caching the redirections. - hyper::Response::new() - .with_status(StatusCode::Found) - .with_header(header::Location::new(self.to_url)) - } -} diff --git a/dapps/src/handlers/streaming.rs b/dapps/src/handlers/streaming.rs deleted file mode 100644 index b6feaa63827..00000000000 --- a/dapps/src/handlers/streaming.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Content Stream Response - -use std::io; -use hyper::{self, header, mime, StatusCode}; - -use handlers::{add_security_headers, Reader}; - -pub struct StreamingHandler { - initial: Vec, - content: R, - status: StatusCode, - mimetype: mime::Mime, -} - -impl StreamingHandler { - pub fn new(content: R, status: StatusCode, mimetype: mime::Mime) -> Self { - StreamingHandler { - initial: Vec::new(), - content, - status, - mimetype, - } - } - - pub fn set_initial_content(&mut self, content: &str) { - self.initial = content.as_bytes().to_vec(); - } - - pub fn into_response(self) -> (Reader, hyper::Response) { - let (reader, body) = Reader::pair(self.content, self.initial); - let mut res = hyper::Response::new() - .with_status(self.status) - .with_header(header::ContentType(self.mimetype)) - .with_body(body); - add_security_headers(&mut res.headers_mut(), false); - - (reader, res) - } -} diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs deleted file mode 100644 index 4fcf9740d78..00000000000 --- a/dapps/src/lib.rs +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Ethcore Webapplications for Parity -#![warn(missing_docs)] - -extern crate base32; -extern crate futures_cpupool; -extern crate itertools; -extern crate linked_hash_map; -extern crate mime_guess; -extern crate parking_lot; -extern crate rand; -extern crate rustc_hex; -extern crate serde; -extern crate serde_json; -extern crate unicase; -extern crate zip; - -extern crate jsonrpc_http_server; - -extern crate parity_bytes as bytes; -extern crate ethereum_types; -extern crate fetch; -extern crate node_health; -extern crate parity_dapps_glue as parity_dapps; -extern crate parity_hash_fetch as hash_fetch; -extern crate keccak_hash as hash; -extern crate parity_version; -extern crate registrar; - -#[macro_use] -extern crate futures; -#[macro_use] -extern crate log; -#[macro_use] -extern crate serde_derive; - -#[cfg(test)] -extern crate env_logger; -#[cfg(test)] -extern crate ethcore_devtools as devtools; -#[cfg(test)] -extern crate jsonrpc_core; -#[cfg(test)] -extern crate parity_reactor; - -mod endpoint; -mod apps; -mod page; -mod router; -mod handlers; -mod api; -mod proxypac; -mod web; -#[cfg(test)] -mod tests; - -use std::collections::HashMap; -use std::mem; -use std::path::PathBuf; -use std::sync::Arc; -use futures_cpupool::CpuPool; -use jsonrpc_http_server::{self as http, hyper, Origin}; -use parking_lot::RwLock; - -use fetch::Fetch; -use node_health::NodeHealth; - -pub use registrar::{RegistrarClient, Asynchronous}; -pub use node_health::SyncStatus; -pub use page::builtin::Dapp; - -/// Validates Web Proxy tokens -pub trait WebProxyTokens: Send + Sync { - /// Should return a domain allowed to be accessed by this token or `None` if the token is not valid - fn domain(&self, token: &str) -> Option; -} - -impl WebProxyTokens for F where F: Fn(String) -> Option + Send + Sync { - fn domain(&self, token: &str) -> Option { self(token.to_owned()) } -} - -/// Current supported endpoints. -#[derive(Default, Clone)] -pub struct Endpoints { - local_endpoints: Arc>>, - endpoints: Arc>, - dapps_path: PathBuf, - pool: Option, -} - -impl Endpoints { - /// Returns a current list of app endpoints. - pub fn list(&self) -> Vec { - self.endpoints.read().iter().filter_map(|(ref k, ref e)| { - e.info().map(|ref info| info.with_id(k)) - }).collect() - } - - /// Check for any changes in the local dapps folder and update. - pub fn refresh_local_dapps(&self) { - let pool = match self.pool.as_ref() { - None => return, - Some(pool) => pool, - }; - let new_local = apps::fs::local_endpoints(&self.dapps_path, pool.clone()); - let old_local = mem::replace(&mut *self.local_endpoints.write(), new_local.keys().cloned().collect()); - let (_, to_remove): (_, Vec<_>) = old_local - .into_iter() - .partition(|k| new_local.contains_key(&k.clone())); - - let mut endpoints = self.endpoints.write(); - // remove the dead dapps - for k in to_remove { - endpoints.remove(&k); - } - // new dapps to be added - for (k, v) in new_local { - if !endpoints.contains_key(&k) { - endpoints.insert(k, v); - } - } - } -} - -/// Dapps server as `jsonrpc-http-server` request middleware. -pub struct Middleware { - endpoints: Endpoints, - router: router::Router, -} - -impl Middleware { - /// Get local endpoints handle. - pub fn endpoints(&self) -> &Endpoints { - &self.endpoints - } - - /// Creates new Dapps server middleware. - pub fn dapps( - pool: CpuPool, - health: NodeHealth, - dapps_path: PathBuf, - extra_dapps: Vec, - dapps_domain: &str, - registrar: Arc>, - sync_status: Arc, - web_proxy_tokens: Arc, - fetch: F, - ) -> Self { - let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( - hash_fetch::urlhint::URLHintContract::new(registrar), - sync_status.clone(), - fetch.clone(), - pool.clone(), - ).allow_dapps(true)); - let (local_endpoints, endpoints) = apps::all_endpoints( - dapps_path.clone(), - extra_dapps, - dapps_domain, - web_proxy_tokens, - fetch.clone(), - pool.clone(), - ); - let endpoints = Endpoints { - endpoints: Arc::new(RwLock::new(endpoints)), - dapps_path, - local_endpoints: Arc::new(RwLock::new(local_endpoints)), - pool: Some(pool.clone()), - }; - - let special = special_endpoints( - health, - content_fetcher.clone(), - ); - - let router = router::Router::new( - content_fetcher, - Some(endpoints.clone()), - special, - dapps_domain.to_owned(), - ); - - Middleware { - endpoints, - router, - } - } -} - -impl http::RequestMiddleware for Middleware { - fn on_request(&self, req: hyper::Request) -> http::RequestMiddlewareAction { - self.router.on_request(req) - } -} - -fn special_endpoints( - health: NodeHealth, - content_fetcher: Arc, -) -> HashMap>> { - let mut special = HashMap::new(); - special.insert(router::SpecialEndpoint::Rpc, None); - special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new( - content_fetcher, - health, - ))); - special -} - -/// Random filename -fn random_filename() -> String { - use ::rand::Rng; - let mut rng = ::rand::OsRng::new().unwrap(); - rng.gen_ascii_chars().take(12).collect() -} diff --git a/dapps/src/page/builtin.rs b/dapps/src/page/builtin.rs deleted file mode 100644 index 685b1401d15..00000000000 --- a/dapps/src/page/builtin.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::io; -use futures::future; -use futures_cpupool::CpuPool; -use hyper::mime::{self, Mime}; -use itertools::Itertools; -use parity_dapps::{WebApp, Info}; - -use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response}; -use page::{handler, PageCache}; - -/// Represents a builtin Dapp. -pub struct Dapp { - /// futures cpu pool - pool: CpuPool, - /// Content of the files - app: T, - info: EndpointInfo, - fallback_to_index_html: bool, -} - -impl Dapp { - /// Creates new `Dapp` for builtin (compile time) Dapp. - pub fn new(pool: CpuPool, app: T) -> Self { - let info = app.info(); - Dapp { - pool, - app, - info: EndpointInfo::from(info), - fallback_to_index_html: false, - } - } - - /// Creates a new `Dapp` for builtin (compile time) Dapp. - /// Instead of returning 404 this endpoint will always server index.html. - pub fn with_fallback_to_index(pool: CpuPool, app: T) -> Self { - let info = app.info(); - Dapp { - pool, - app, - info: EndpointInfo::from(info), - fallback_to_index_html: true, - } - } - - /// Allow the dapp to use `unsafe-eval` to run JS. - pub fn allow_js_eval(&mut self) { - self.info.allow_js_eval = Some(true); - } -} - -impl Endpoint for Dapp { - fn info(&self) -> Option<&EndpointInfo> { - Some(&self.info) - } - - fn respond(&self, path: EndpointPath, _req: Request) -> Response { - trace!(target: "dapps", "Builtin file path: {:?}", path); - let file_path = if path.has_no_params() { - "index.html".to_owned() - } else { - path.app_params.into_iter().filter(|x| !x.is_empty()).join("/") - }; - trace!(target: "dapps", "Builtin file: {:?}", file_path); - - let file = { - let file = |path| self.app.file(path).map(|file| { - let content_type = match file.content_type.parse() { - Ok(mime) => mime, - Err(_) => { - warn!(target: "dapps", "invalid MIME type: {}", file.content_type); - mime::TEXT_HTML - }, - }; - BuiltinFile { - content_type, - content: io::Cursor::new(file.content), - } - }); - let res = file(&file_path); - if self.fallback_to_index_html { - res.or_else(|| file("index.html")) - } else { - res - } - }; - - let (reader, response) = handler::PageHandler { - file, - cache: PageCache::Disabled, - allow_js_eval: self.info.allow_js_eval.clone().unwrap_or(false), - }.into_response(); - - self.pool.spawn(reader).forget(); - - Box::new(future::ok(response)) - } -} - -impl From for EndpointInfo { - fn from(info: Info) -> Self { - EndpointInfo { - id: None, - name: info.name.into(), - description: info.description.into(), - author: info.author.into(), - icon_url: info.icon_url.into(), - local_url: None, - version: info.version.into(), - allow_js_eval: None, - } - } -} - -struct BuiltinFile { - content_type: Mime, - content: io::Cursor<&'static [u8]>, -} - -impl handler::DappFile for BuiltinFile { - type Reader = io::Cursor<&'static [u8]>; - - fn content_type(&self) -> &Mime { - &self.content_type - } - - fn into_reader(self) -> Self::Reader { - self.content - } -} diff --git a/dapps/src/page/handler.rs b/dapps/src/page/handler.rs deleted file mode 100644 index d7fcefa7f04..00000000000 --- a/dapps/src/page/handler.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::io; -use std::time::{Duration, SystemTime}; -use hyper::{self, header, StatusCode}; -use hyper::mime::{Mime}; - -use handlers::{Reader, ContentHandler, add_security_headers}; - -/// Represents a file that can be sent to client. -/// Implementation should keep track of bytes already sent internally. -pub trait DappFile { - /// A reader type returned by this file. - type Reader: io::Read; - - /// Returns a content-type of this file. - fn content_type(&self) -> &Mime; - - /// Convert this file into io::Read instance. - fn into_reader(self) -> Self::Reader where Self: Sized; -} - -/// Defines what cache headers should be appended to returned resources. -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum PageCache { - Enabled, - Disabled, -} - -impl Default for PageCache { - fn default() -> Self { - PageCache::Disabled - } -} - -/// A handler for a single webapp. -/// Resolves correct paths and serves as a plumbing code between -/// hyper server and dapp. -pub struct PageHandler { - /// File currently being served - pub file: Option, - /// Cache settings for this page. - pub cache: PageCache, - /// Allow JS unsafe-eval. - pub allow_js_eval: bool, -} - -impl PageHandler { - pub fn into_response(self) -> (Option>, hyper::Response) { - let file = match self.file { - None => return (None, ContentHandler::error( - StatusCode::NotFound, - "File not found", - "Requested file has not been found.", - None, - ).into()), - Some(file) => file, - }; - - let mut res = hyper::Response::new() - .with_status(StatusCode::Ok); - - // headers - { - let mut headers = res.headers_mut(); - - if let PageCache::Enabled = self.cache { - let validity_secs = 365u32 * 24 * 3600; - let validity = Duration::from_secs(validity_secs as u64); - headers.set(header::CacheControl(vec![ - header::CacheDirective::Public, - header::CacheDirective::MaxAge(validity_secs), - ])); - headers.set(header::Expires(header::HttpDate::from(SystemTime::now() + validity))); - } - - headers.set(header::ContentType(file.content_type().to_owned())); - - add_security_headers(&mut headers, self.allow_js_eval); - } - - let (reader, body) = Reader::pair(file.into_reader(), Vec::new()); - res.set_body(body); - (Some(reader), res) - } -} diff --git a/dapps/src/page/local.rs b/dapps/src/page/local.rs deleted file mode 100644 index a43735d7684..00000000000 --- a/dapps/src/page/local.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use mime_guess; -use std::{fs, fmt}; -use std::path::{Path, PathBuf}; -use futures::{future}; -use futures_cpupool::CpuPool; -use page::handler::{self, PageCache}; -use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response}; -use hyper::mime::Mime; - -#[derive(Clone)] -pub struct Dapp { - pool: CpuPool, - path: PathBuf, - mime: Option, - info: Option, - cache: PageCache, -} - -impl fmt::Debug for Dapp { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("Dapp") - .field("path", &self.path) - .field("mime", &self.mime) - .field("info", &self.info) - .field("cache", &self.cache) - .finish() - } -} - -impl Dapp { - pub fn new(pool: CpuPool, path: PathBuf, info: EndpointInfo, cache: PageCache) -> Self { - Dapp { - pool, - path, - mime: None, - info: Some(info), - cache, - } - } - - pub fn single_file(pool: CpuPool, path: PathBuf, mime: Mime, cache: PageCache) -> Self { - Dapp { - pool, - path, - mime: Some(mime), - info: None, - cache, - } - } - - pub fn path(&self) -> PathBuf { - self.path.clone() - } - - fn get_file(&self, path: &EndpointPath) -> Option { - if let Some(ref mime) = self.mime { - return LocalFile::from_path(&self.path, mime.to_owned()); - } - - let mut file_path = self.path.to_owned(); - - if path.has_no_params() { - file_path.push("index.html"); - } else { - for part in &path.app_params { - file_path.push(part); - } - } - - let mime = mime_guess::guess_mime_type(&file_path); - LocalFile::from_path(&file_path, mime) - } - - pub fn to_response(&self, path: &EndpointPath) -> Response { - let (reader, response) = handler::PageHandler { - file: self.get_file(path), - cache: self.cache, - allow_js_eval: self.info.as_ref().and_then(|x| x.allow_js_eval).unwrap_or(false), - }.into_response(); - - self.pool.spawn(reader).forget(); - - Box::new(future::ok(response)) - } -} - -impl Endpoint for Dapp { - fn info(&self) -> Option<&EndpointInfo> { - self.info.as_ref() - } - - fn respond(&self, path: EndpointPath, _req: Request) -> Response { - self.to_response(&path) - } -} - -struct LocalFile { - content_type: Mime, - file: fs::File, -} - -impl LocalFile { - fn from_path>(path: P, content_type: Mime) -> Option { - trace!(target: "dapps", "Local file: {:?}", path.as_ref()); - // Check if file exists - fs::File::open(&path).ok().map(|file| { - LocalFile { - content_type, - file, - } - }) - } -} - -impl handler::DappFile for LocalFile { - type Reader = fs::File; - - fn content_type(&self) -> &Mime { - &self.content_type - } - - fn into_reader(self) -> Self::Reader { - self.file - } -} diff --git a/dapps/src/page/mod.rs b/dapps/src/page/mod.rs deleted file mode 100644 index 65385320c48..00000000000 --- a/dapps/src/page/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -pub mod builtin; -pub mod local; -mod handler; - -pub use self::handler::PageCache; diff --git a/dapps/src/proxypac.rs b/dapps/src/proxypac.rs deleted file mode 100644 index 1acd7b1b9e3..00000000000 --- a/dapps/src/proxypac.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Serving ProxyPac file - -use apps::HOME_PAGE; -use endpoint::{Endpoint, Request, Response, EndpointPath}; -use futures::future; -use handlers::ContentHandler; -use hyper::mime; - -pub struct ProxyPac { - dapps_domain: String, -} - -impl ProxyPac { - pub fn boxed(dapps_domain: String) -> Box { - Box::new(ProxyPac { dapps_domain }) - } -} - -impl Endpoint for ProxyPac { - fn respond(&self, path: EndpointPath, _req: Request) -> Response { - let ui = format!("{}:{}", path.host, path.port); - - let content = format!( -r#" -function FindProxyForURL(url, host) {{ - if (shExpMatch(host, "{0}.{1}")) - {{ - return "PROXY {4}"; - }} - - if (shExpMatch(host, "*.{1}")) - {{ - return "PROXY {2}:{3}"; - }} - - return "DIRECT"; -}} -"#, - HOME_PAGE, self.dapps_domain, path.host, path.port, ui); - - Box::new(future::ok( - ContentHandler::ok(content, mime::TEXT_JAVASCRIPT).into() - )) - } -} diff --git a/dapps/src/router.rs b/dapps/src/router.rs deleted file mode 100644 index 28a3e24c3f0..00000000000 --- a/dapps/src/router.rs +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Router implementation -//! Dispatch requests to proper application. - -use std::sync::Arc; -use std::collections::HashMap; - -use futures::future; -use hyper::{self, header, Uri}; -use jsonrpc_http_server as http; - -use apps; -use apps::fetcher::Fetcher; -use endpoint::{self, Endpoint, EndpointPath}; -use Endpoints; -use handlers; - -/// Special endpoints are accessible on every domain (every dapp) -#[derive(Debug, PartialEq, Hash, Eq)] -pub enum SpecialEndpoint { - Rpc, - Api, - Home, - None, -} - -enum Response { - Some(endpoint::Response), - None(hyper::Request), -} - -/// An endpoint router. -/// Dispatches the request to particular Endpoint by requested uri/path. -pub struct Router { - endpoints: Option, - fetch: Arc, - special: HashMap>>, - dapps_domain: String, -} - -impl Router { - fn resolve_request(&self, req: hyper::Request, refresh_dapps: bool) -> Response { - // Choose proper handler depending on path / domain - let endpoint = extract_endpoint(req.uri(), req.headers().get(), &self.dapps_domain); - let referer = extract_referer_endpoint(&req, &self.dapps_domain); - let is_get_request = *req.method() == hyper::Method::Get; - let is_head_request = *req.method() == hyper::Method::Head; - let has_dapp = |dapp: &str| self.endpoints - .as_ref() - .map_or(false, |endpoints| endpoints.endpoints.read().contains_key(dapp)); - - trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", req.uri(), req); - debug!(target: "dapps", "Handling endpoint request: {:?}, referer: {:?}", endpoint, referer); - - match (endpoint.0, endpoint.1, referer) { - // Handle invalid web requests that we can recover from - (ref path, SpecialEndpoint::None, Some(ref referer)) - if referer.app_id == apps::WEB_PATH - && has_dapp(apps::WEB_PATH) - && !is_web_endpoint(path) - => - { - let token = referer.app_params.get(0).map(String::as_str).unwrap_or(""); - let requested = req.uri().path(); - let query = req.uri().query().map_or_else(String::new, |query| format!("?{}", query)); - let redirect_url = format!("/{}/{}{}{}", apps::WEB_PATH, token, requested, query); - trace!(target: "dapps", "Redirecting to correct web request: {:?}", redirect_url); - Response::Some(Box::new(future::ok( - handlers::Redirection::new(redirect_url).into() - ))) - }, - // First check special endpoints - (ref path, ref endpoint, _) if self.special.contains_key(endpoint) => { - trace!(target: "dapps", "Resolving to special endpoint."); - let special = self.special.get(endpoint).expect("special known to contain key; qed"); - match *special { - Some(ref special) => Response::Some(special.respond(path.clone().unwrap_or_default(), req)), - None => Response::None(req), - } - }, - // Then delegate to dapp - (Some(ref path), _, _) if has_dapp(&path.app_id) => { - trace!(target: "dapps", "Resolving to local/builtin dapp."); - Response::Some(self.endpoints - .as_ref() - .expect("endpoints known to be set; qed") - .endpoints - .read() - .get(&path.app_id) - .expect("endpoints known to contain key; qed") - .respond(path.clone(), req)) - }, - // Try to resolve and fetch the dapp - (Some(ref path), _, _) if self.fetch.contains(&path.app_id) => { - trace!(target: "dapps", "Resolving to fetchable content."); - Response::Some(self.fetch.respond(path.clone(), req)) - }, - // 404 for non-existent content (only if serving endpoints and not homepage) - (Some(ref path), _, _) - if (is_get_request || is_head_request) - && self.endpoints.is_some() - && path.app_id != apps::HOME_PAGE - => - { - trace!(target: "dapps", "Resolving to 404."); - if refresh_dapps { - debug!(target: "dapps", "Refreshing dapps and re-trying."); - self.endpoints.as_ref().map(|endpoints| endpoints.refresh_local_dapps()); - return self.resolve_request(req, false); - } else { - Response::Some(Box::new(future::ok(handlers::ContentHandler::error( - hyper::StatusCode::NotFound, - "404 Not Found", - "Requested content was not found.", - None, - ).into()))) - } - }, - // Any other GET|HEAD requests to home page. - _ if (is_get_request || is_head_request) && self.special.contains_key(&SpecialEndpoint::Home) => { - trace!(target: "dapps", "Resolving to home page."); - let special = self.special.get(&SpecialEndpoint::Home).expect("special known to contain key; qed"); - match *special { - Some(ref special) => { - let mut endpoint = EndpointPath::default(); - endpoint.app_params = req.uri().path().split('/').map(str::to_owned).collect(); - Response::Some(special.respond(endpoint, req)) - }, - None => Response::None(req), - } - }, - // RPC by default - _ if self.special.contains_key(&SpecialEndpoint::Rpc) => { - trace!(target: "dapps", "Resolving to RPC call."); - Response::None(req) - }, - // 404 otherwise - _ => { - Response::Some(Box::new(future::ok(handlers::ContentHandler::error( - hyper::StatusCode::NotFound, - "404 Not Found", - "Requested content was not found.", - None, - ).into()))) - }, - } - } -} - -impl http::RequestMiddleware for Router { - fn on_request(&self, req: hyper::Request) -> http::RequestMiddlewareAction { - let is_origin_set = req.headers().get::().is_some(); - let response = self.resolve_request(req, self.endpoints.is_some()); - match response { - Response::Some(response) => http::RequestMiddlewareAction::Respond { - should_validate_hosts: true, - response, - }, - Response::None(request) => http::RequestMiddlewareAction::Proceed { - should_continue_on_invalid_cors: !is_origin_set, - request, - }, - } - } -} - -impl Router { - pub fn new( - content_fetcher: Arc, - endpoints: Option, - special: HashMap>>, - dapps_domain: String, - ) -> Self { - Router { - endpoints: endpoints, - fetch: content_fetcher, - special: special, - dapps_domain: format!(".{}", dapps_domain), - } - } -} - -fn is_web_endpoint(path: &Option) -> bool { - match *path { - Some(ref path) if path.app_id == apps::WEB_PATH => true, - _ => false, - } -} - -fn extract_referer_endpoint(req: &hyper::Request, dapps_domain: &str) -> Option { - let referer = req.headers().get::(); - - let url = referer.and_then(|referer| referer.parse().ok()); - url.and_then(|url| { - extract_url_referer_endpoint(&url, dapps_domain).or_else(|| { - extract_endpoint(&url, None, dapps_domain).0 - }) - }) -} - -fn extract_url_referer_endpoint(url: &Uri, dapps_domain: &str) -> Option { - let query = url.query(); - match query { - Some(query) if query.starts_with(apps::URL_REFERER) => { - let scheme = url.scheme().unwrap_or("http"); - let host = url.host().unwrap_or("unknown"); - let port = default_port(url, None); - let referer_url = format!("{}://{}:{}/{}", scheme, host, port, &query[apps::URL_REFERER.len()..]); - debug!(target: "dapps", "Recovering referer from query parameter: {}", referer_url); - - if let Some(referer_url) = referer_url.parse().ok() { - extract_endpoint(&referer_url, None, dapps_domain).0 - } else { - None - } - }, - _ => None, - } -} - -fn extract_endpoint(url: &Uri, extra_host: Option<&header::Host>, dapps_domain: &str) -> (Option, SpecialEndpoint) { - fn special_endpoint(path: &[&str]) -> SpecialEndpoint { - if path.len() <= 1 { - return SpecialEndpoint::None; - } - - match path[0].as_ref() { - apps::RPC_PATH => SpecialEndpoint::Rpc, - apps::API_PATH => SpecialEndpoint::Api, - apps::HOME_PAGE => SpecialEndpoint::Home, - _ => SpecialEndpoint::None, - } - } - - let port = default_port(url, extra_host.as_ref().and_then(|h| h.port())); - let host = url.host().or_else(|| extra_host.as_ref().map(|h| h.hostname())); - let query = url.query().map(str::to_owned); - let mut path_segments = url.path().split('/').skip(1).collect::>(); - trace!( - target: "dapps", - "Extracting endpoint from: {:?} (dapps: {}). Got host {:?}:{} with path {:?}", - url, dapps_domain, host, port, path_segments - ); - match host { - Some(host) if host.ends_with(dapps_domain) => { - let id = &host[0..(host.len() - dapps_domain.len())]; - let special = special_endpoint(&path_segments); - - // remove special endpoint id from params - if special != SpecialEndpoint::None { - path_segments.remove(0); - } - - let (app_id, app_params) = if let Some(split) = id.rfind('.') { - let (params, id) = id.split_at(split); - path_segments.insert(0, params); - (id[1..].to_owned(), path_segments) - } else { - (id.to_owned(), path_segments) - }; - - (Some(EndpointPath { - app_id, - app_params: app_params.into_iter().map(Into::into).collect(), - query, - host: host.to_owned(), - port, - using_dapps_domains: true, - }), special) - }, - Some(host) if path_segments.len() > 1 => { - let special = special_endpoint(&path_segments); - let id = path_segments.remove(0); - (Some(EndpointPath { - app_id: id.to_owned(), - app_params: path_segments.into_iter().map(Into::into).collect(), - query, - host: host.to_owned(), - port, - using_dapps_domains: false, - }), special) - }, - _ => (None, special_endpoint(&path_segments)), - } -} - -fn default_port(url: &Uri, extra_port: Option) -> u16 { - let scheme = url.scheme().unwrap_or("http"); - url.port().or(extra_port).unwrap_or_else(|| match scheme { - "http" => 80, - "https" => 443, - _ => 80, - }) -} - -#[cfg(test)] -mod tests { - use super::{SpecialEndpoint, EndpointPath, extract_endpoint}; - - #[test] - fn should_extract_endpoint() { - let dapps_domain = ".web3.site"; - - // With path prefix - assert_eq!( - extract_endpoint(&"http://localhost:8080/status/index.html?q=1".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["index.html".to_owned()], - query: Some("q=1".into()), - host: "localhost".to_owned(), - port: 8080, - using_dapps_domains: false, - }), SpecialEndpoint::None) - ); - - // With path prefix - assert_eq!( - extract_endpoint(&"http://localhost:8080/rpc/".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "rpc".to_owned(), - app_params: vec!["".to_owned()], - query: None, - host: "localhost".to_owned(), - port: 8080, - using_dapps_domains: false, - }), SpecialEndpoint::Rpc) - ); - - // By Subdomain - assert_eq!( - extract_endpoint(&"http://status.web3.site/test.html".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["test.html".to_owned()], - query: None, - host: "status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::None) - ); - - // RPC by subdomain - assert_eq!( - extract_endpoint(&"http://my.status.web3.site/rpc/".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["my".into(), "".into()], - query: None, - host: "my.status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::Rpc) - ); - - // API by subdomain - assert_eq!( - extract_endpoint(&"http://my.status.web3.site/api/".parse().unwrap(), None, dapps_domain), - (Some(EndpointPath { - app_id: "status".to_owned(), - app_params: vec!["my".into(), "".into()], - query: None, - host: "my.status.web3.site".to_owned(), - port: 80, - using_dapps_domains: true, - }), SpecialEndpoint::Api) - ); - } -} diff --git a/dapps/src/tests/api.rs b/dapps/src/tests/api.rs deleted file mode 100644 index d31f796d57b..00000000000 --- a/dapps/src/tests/api.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use tests::helpers::{serve, serve_with_registrar, request, assert_security_headers}; - -#[test] -fn should_return_error() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - GET /api/empty HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - response.assert_header("Content-Type", "application/json"); - assert_eq!(response.body, format!("58\n{}\n0\n\n", r#"{"code":"404","title":"Not Found","detail":"Resource you requested has not been found."}"#)); - assert_security_headers(&response.headers); -} - -#[test] -fn should_handle_ping() { - // given - let server = serve(); - - // when - let response = request(server, - "\ - POST /api/ping HTTP/1.1\r\n\ - Host: home.parity\r\n\ - Content-Type: application/json\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - response.assert_header("Content-Type", "application/json"); - assert_eq!(response.body, "0\n\n".to_owned()); - assert_security_headers(&response.headers); -} - -#[test] -fn should_try_to_resolve_dapp() { - // given - let (server, registrar) = serve_with_registrar(); - - // when - let response = request(server, - "\ - GET /api/content/1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d HTTP/1.1\r\n\ - Host: home.parity\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - assert_eq!(registrar.calls.lock().len(), 2); - assert_security_headers(&response.headers); -} diff --git a/dapps/src/tests/fetch.rs b/dapps/src/tests/fetch.rs deleted file mode 100644 index 444d5b656ac..00000000000 --- a/dapps/src/tests/fetch.rs +++ /dev/null @@ -1,544 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use devtools::http_client; -use rustc_hex::FromHex; -use tests::helpers::{ - serve_with_registrar, serve_with_registrar_and_sync, serve_with_fetch, - serve_with_registrar_and_fetch, - request, assert_security_headers -}; - -#[test] -fn should_resolve_dapp() { - // given - let (server, registrar) = serve_with_registrar(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 404 Not Found"); - assert_eq!(registrar.calls.lock().len(), 4); - assert_security_headers(&response.headers); -} - -#[test] -fn should_return_503_when_syncing_but_should_make_the_calls() { - // given - let (server, registrar) = serve_with_registrar_and_sync(); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 503 Service Unavailable"); - assert_eq!(registrar.calls.lock().len(), 2); - assert_security_headers(&response.headers); -} - -const GAVCOIN_DAPP: &'static str = "00000000000000000000000000000000000000000000000000000000000000609faf32e1e3845e237cc6efd27187cee13b3b99db000000000000000000000000000000000000000000000000d8bd350823e28ff75e74a34215faefdc8a52fd8e00000000000000000000000000000000000000000000000000000000000000116761766f66796f726b2f676176636f696e000000000000000000000000000000"; -const GAVCOIN_ICON: &'static str = "00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d8bd350823e28ff75e74a34215faefdc8a52fd8e000000000000000000000000000000000000000000000000000000000000007768747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f657468636f72652f646170702d6173736574732f623838653938336162616131613661363334356238643934343863313562313137646462353430652f746f6b656e732f676176636f696e2d36347836342e706e67000000000000000000"; - -#[test] -fn should_return_502_on_hash_mismatch() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_DAPP.from_hex().unwrap(); - registrar.set_result( - "94f093625c06887d94d9fee0d5f9cc4aaa46f33d24d1c7e4b5237e7c37d547dd".parse().unwrap(), - Ok(gavcoin.clone()) - ); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 94f093625c06887d94d9fee0d5f9cc4aaa46f33d24d1c7e4b5237e7c37d547dd.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - assert_eq!(registrar.calls.lock().len(), 4); - - fetch.assert_requested("https://codeload.github.com/gavofyork/gavcoin/zip/9faf32e1e3845e237cc6efd27187cee13b3b99db"); - fetch.assert_no_more_requests(); - - response.assert_status("HTTP/1.1 502 Bad Gateway"); - assert!(response.body.contains("HashMismatch"), "Expected hash mismatch response, got: {:?}", response.body); - assert_security_headers(&response.headers); -} - -#[test] -fn should_return_error_for_invalid_dapp_zip() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_DAPP.from_hex().unwrap(); - registrar.set_result( - "2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".parse().unwrap(), - Ok(gavcoin.clone()) - ); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - assert_eq!(registrar.calls.lock().len(), 4); - - fetch.assert_requested("https://codeload.github.com/gavofyork/gavcoin/zip/9faf32e1e3845e237cc6efd27187cee13b3b99db"); - fetch.assert_no_more_requests(); - - response.assert_status("HTTP/1.1 502 Bad Gateway"); - assert!(response.body.contains("InvalidArchive"), "Expected invalid zip response, got: {:?}", response.body); - assert_security_headers(&response.headers); -} - -#[test] -fn should_return_fetched_dapp_content() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_DAPP.from_hex().unwrap(); - registrar.set_result( - "9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a".parse().unwrap(), - Ok(gavcoin.clone()) - ); - fetch.set_response(include_bytes!("../../res/gavcoin.zip")); - - // when - let response1 = http_client::request(server.addr(), - "\ - GET /index.html HTTP/1.1\r\n\ - Host: 9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - let response2 = http_client::request(server.addr(), - "\ - GET /manifest.json HTTP/1.1\r\n\ - Host: 9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - assert_eq!(registrar.calls.lock().len(), 4); - - fetch.assert_requested("https://codeload.github.com/gavofyork/gavcoin/zip/9faf32e1e3845e237cc6efd27187cee13b3b99db"); - fetch.assert_no_more_requests(); - - response1.assert_status("HTTP/1.1 200 OK"); - assert_security_headers(&response1.headers); - assert!( - response1.body.contains(r#"18 -

Hello Gavcoin!

- -0 - -"#), - "Expected Gavcoin body: {}", - response1.body - ); - - response2.assert_status("HTTP/1.1 200 OK"); - assert_security_headers(&response2.headers); - assert_eq!( - response2.body, - r#"EA -{ - "id": "9c94e154dab8acf859b30ee80fc828fb1d38359d938751b65db71d460588d82a", - "name": "Gavcoin", - "description": "Gavcoin", - "version": "1.0.0", - "author": "", - "iconUrl": "icon.png", - "localUrl": null, - "allowJsEval": false -} -0 - -"# - ); -} - -#[test] -fn should_return_fetched_content() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_ICON.from_hex().unwrap(); - registrar.set_result( - "2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".parse().unwrap(), - Ok(gavcoin.clone()) - ); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - assert_eq!(registrar.calls.lock().len(), 4); - - fetch.assert_requested("https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/tokens/gavcoin-64x64.png"); - fetch.assert_no_more_requests(); - - response.assert_status("HTTP/1.1 200 OK"); - response.assert_security_headers_present(None); -} - -#[test] -fn should_cache_content() { - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_ICON.from_hex().unwrap(); - registrar.set_result( - "2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".parse().unwrap(), - Ok(gavcoin.clone()) - ); - let request_str = "\ - GET / HTTP/1.1\r\n\ - Host: 2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - "; - - let response = http_client::request(server.addr(), request_str); - fetch.assert_requested("https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/tokens/gavcoin-64x64.png"); - fetch.assert_no_more_requests(); - response.assert_status("HTTP/1.1 200 OK"); - - // when - let response = http_client::request(server.addr(), request_str); - - // then - fetch.assert_no_more_requests(); - response.assert_status("HTTP/1.1 200 OK"); -} - -#[test] -fn should_not_request_content_twice() { - use std::thread; - - // given - let (server, fetch, registrar) = serve_with_registrar_and_fetch(); - let gavcoin = GAVCOIN_ICON.from_hex().unwrap(); - registrar.set_result( - "2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e".parse().unwrap(), - Ok(gavcoin.clone()) - ); - let request_str = "\ - GET / HTTP/1.1\r\n\ - Host: 2be00befcf008bc0e7d9cdefc194db9c75352e8632f48498b5a6bfce9f02c88e.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - "; - let fire_request = || { - let addr = server.addr().to_owned(); - let req = request_str.to_owned(); - thread::spawn(move || { - http_client::request(&addr, &req) - }) - }; - let control = fetch.manual(); - - // when - - // Fire two requests at the same time - let r1 = fire_request(); - let r2 = fire_request(); - - // wait for single request in fetch, the second one should go into waiting state. - control.wait_for_requests(1); - control.respond(); - - let response1 = r1.join().unwrap(); - let response2 = r2.join().unwrap(); - - // then - fetch.assert_requested("https://raw.githubusercontent.com/ethcore/dapp-assets/b88e983abaa1a6a6345b8d9448c15b117ddb540e/tokens/gavcoin-64x64.png"); - fetch.assert_no_more_requests(); - response1.assert_status("HTTP/1.1 200 OK"); - response2.assert_status("HTTP/1.1 200 OK"); -} - -#[test] -fn should_encode_and_decode_base32() { - use base32; - - let encoded = base32::encode(base32::Alphabet::Crockford, "token+https://parity.io".as_bytes()); - assert_eq!("EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY", &encoded); - - let data = base32::decode(base32::Alphabet::Crockford, "EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY").unwrap(); - assert_eq!("token+https://parity.io", &String::from_utf8(data).unwrap()); -} - -#[test] -fn should_stream_web_content() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers(&response.headers); - - fetch.assert_requested("https://parity.io/"); - fetch.assert_no_more_requests(); -} - -#[test] -fn should_support_base32_encoded_web_urls() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET /styles.css?test=123 HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers(&response.headers); - - fetch.assert_requested("https://parity.io/styles.css?test=123"); - fetch.assert_no_more_requests(); -} - -#[test] -fn should_correctly_handle_long_label_when_splitted() { - // given - let (server, fetch) = serve_with_fetch("xolrg9fePeQyKLnL", "https://contribution.melonport.com"); - - // when - let response = request(server, - "\ - GET /styles.css?test=123 HTTP/1.1\r\n\ - Host: f1qprwk775k6am35a5wmpk3e9gnpgx3me1sk.mbsfcdqpwx3jd5h7ax39dxq2wvb5dhqpww3fe9t2wrvfdm.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers(&response.headers); - - fetch.assert_requested("https://contribution.melonport.com/styles.css?test=123"); - fetch.assert_no_more_requests(); -} - -#[test] -fn should_support_base32_encoded_web_urls_as_path() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET /web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/styles.css?test=123 HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_security_headers(&response.headers); - - fetch.assert_requested("https://parity.io/styles.css?test=123"); - fetch.assert_no_more_requests(); -} - -#[test] -fn should_return_error_on_non_whitelisted_domain() { - // given - let (server, fetch) = serve_with_fetch("token", "https://ethcore.io"); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers(&response.headers); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_return_error_on_invalid_token() { - // given - let (server, fetch) = serve_with_fetch("test", "https://parity.io"); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers(&response.headers); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_return_error_on_invalid_protocol() { - // given - let (server, fetch) = serve_with_fetch("token", "ftp://parity.io"); - - // when - let response = request(server, - "\ - GET /web/token/ftp/parity.io/ HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 400 Bad Request"); - assert_security_headers(&response.headers); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_disallow_non_get_requests() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - POST / HTTP/1.1\r\n\ - Host: EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY.web.web3.site\r\n\ - Content-Type: application/json\r\n\ - Connection: close\r\n\ - \r\n\ - 123\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 405 Method Not Allowed"); - assert_security_headers(&response.headers); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_fix_absolute_requests_based_on_referer() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET /styles.css HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - Referer: http://localhost:8080/web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - response.assert_header("Location", "/web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/styles.css"); - - fetch.assert_no_more_requests(); -} - -#[test] -fn should_fix_absolute_requests_based_on_referer_in_url() { - // given - let (server, fetch) = serve_with_fetch("token", "https://parity.io"); - - // when - let response = request(server, - "\ - GET /styles.css HTTP/1.1\r\n\ - Host: localhost:8080\r\n\ - Connection: close\r\n\ - Referer: http://localhost:8080/?__referer=web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/\r\n\ - \r\n\ - " - ); - - // then - response.assert_status("HTTP/1.1 302 Found"); - response.assert_header("Location", "/web/EHQPPSBE5DM78X3GECX2YBVGC5S6JX3S5SMPY/styles.css"); - - fetch.assert_no_more_requests(); -} diff --git a/dapps/src/tests/helpers/fetch.rs b/dapps/src/tests/helpers/fetch.rs deleted file mode 100644 index 4affffe6efa..00000000000 --- a/dapps/src/tests/helpers/fetch.rs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::{thread, time}; -use std::sync::{atomic, mpsc, Arc}; -use parking_lot::Mutex; -use hyper; - -use futures::{self, future, Future}; -use fetch::{self, Fetch, Url, Request, Abort}; - -pub struct FetchControl { - sender: mpsc::Sender<()>, - fetch: FakeFetch, -} - -impl FetchControl { - pub fn respond(self) { - self.sender.send(()) - .expect("Fetch cannot be finished without sending a response at least once."); - } - - pub fn wait_for_requests(&self, len: usize) { - const MAX_TIMEOUT: time::Duration = time::Duration::from_millis(5000); - const ATTEMPTS: u32 = 10; - let mut attempts_left = ATTEMPTS; - loop { - let current = self.fetch.requested.lock().len(); - - if current == len { - break; - } else if attempts_left == 0 { - panic!( - "Timeout reached when waiting for pending requests. Expected: {}, current: {}", - len, current - ); - } else { - attempts_left -= 1; - // Should we handle spurious timeouts better? - thread::park_timeout(MAX_TIMEOUT / ATTEMPTS); - } - } - } -} - -#[derive(Clone, Default)] -pub struct FakeFetch { - manual: Arc>>>, - response: Arc>>, - asserted: Arc, - requested: Arc>>, -} - -impl FakeFetch { - pub fn set_response(&self, data: &'static [u8]) { - *self.response.lock() = Some(data); - } - - pub fn manual(&self) -> FetchControl { - assert!(self.manual.lock().is_none(), "Only one manual control may be active."); - let (tx, rx) = mpsc::channel(); - *self.manual.lock() = Some(rx); - - FetchControl { - sender: tx, - fetch: self.clone(), - } - } - - pub fn assert_requested(&self, url: &str) { - let requests = self.requested.lock(); - let idx = self.asserted.fetch_add(1, atomic::Ordering::SeqCst); - - assert_eq!(requests.get(idx), Some(&url.to_owned()), "Expected fetch from specific URL."); - } - - pub fn assert_no_more_requests(&self) { - let requests = self.requested.lock(); - let len = self.asserted.load(atomic::Ordering::SeqCst); - assert_eq!(requests.len(), len, "Didn't expect any more requests, got: {:?}", &requests[len..]); - } -} - -impl Fetch for FakeFetch { - type Result = Box + Send>; - - fn fetch(&self, request: Request, abort: fetch::Abort) -> Self::Result { - let u = request.url().clone(); - self.requested.lock().push(u.as_str().into()); - let manual = self.manual.clone(); - let response = self.response.clone(); - - let (tx, rx) = futures::oneshot(); - thread::spawn(move || { - if let Some(rx) = manual.lock().take() { - // wait for manual resume - let _ = rx.recv(); - } - let data = response.lock().take().unwrap_or(b"Some content"); - tx.send(fetch::Response::new(u, hyper::Response::new().with_body(data), abort)).unwrap(); - }); - - Box::new(rx.map_err(|_| fetch::Error::Aborted)) - } - - fn get(&self, url: &str, abort: Abort) -> Self::Result { - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return Box::new(future::err(e.into())) - }; - self.fetch(Request::get(url), abort) - } - - fn post(&self, url: &str, abort: Abort) -> Self::Result { - let url: Url = match url.parse() { - Ok(u) => u, - Err(e) => return Box::new(future::err(e.into())) - }; - self.fetch(Request::post(url), abort) - } -} diff --git a/dapps/src/tests/helpers/mod.rs b/dapps/src/tests/helpers/mod.rs deleted file mode 100644 index 58ec71d7332..00000000000 --- a/dapps/src/tests/helpers/mod.rs +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::{env, io, str}; -use std::net::SocketAddr; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use env_logger::LogBuilder; -use jsonrpc_core::IoHandler; -use jsonrpc_http_server::{self as http, Host, DomainsValidation}; -use parity_reactor::Remote; - -use devtools::http_client; -use registrar::{RegistrarClient, Asynchronous}; -use fetch::{Fetch, Client as FetchClient}; -use node_health::{NodeHealth, TimeChecker, CpuPool}; - -use {Middleware, SyncStatus, WebProxyTokens}; - -mod registrar; -mod fetch; - -use self::registrar::FakeRegistrar; -use self::fetch::FakeFetch; - -#[derive(Debug)] -struct FakeSync(bool); -impl SyncStatus for FakeSync { - fn is_major_importing(&self) -> bool { self.0 } - fn peers(&self) -> (usize, usize) { (0, 5) } -} - -fn init_logger() { - // Initialize logger - if let Ok(log) = env::var("RUST_LOG") { - let mut builder = LogBuilder::new(); - builder.parse(&log); - let _ = builder.init(); // ignore errors since ./test.sh will call this multiple times. - } -} - -pub fn init_server(process: F, io: IoHandler) -> (Server, Arc) where - F: FnOnce(ServerBuilder) -> ServerBuilder, - B: Fetch, -{ - init_logger(); - let registrar = Arc::new(FakeRegistrar::new()); - let mut dapps_path = env::temp_dir(); - dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading"); - - let builder = ServerBuilder::new(FetchClient::new().unwrap(), &dapps_path, registrar.clone()); - let server = process(builder).start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), io).unwrap(); - ( - server, - registrar, - ) -} - -pub fn serve_with_rpc(io: IoHandler) -> Server { - init_server(|builder| builder, io).0 -} - -pub fn serve_hosts(hosts: Option>) -> Server { - let hosts = hosts.map(|hosts| hosts.into_iter().map(Into::into).collect()); - init_server(|mut builder| { - builder.allowed_hosts = hosts.into(); - builder - }, Default::default()).0 -} - -pub fn serve_with_registrar() -> (Server, Arc) { - init_server(|builder| builder, Default::default()) -} - -pub fn serve_with_registrar_and_sync() -> (Server, Arc) { - init_server(|mut builder| { - builder.sync_status = Arc::new(FakeSync(true)); - builder - }, Default::default()) -} - -pub fn serve_with_registrar_and_fetch() -> (Server, FakeFetch, Arc) { - let fetch = FakeFetch::default(); - let f = fetch.clone(); - let (server, reg) = init_server(move |builder| { - builder.fetch(f.clone()) - }, Default::default()); - - (server, fetch, reg) -} - -pub fn serve_with_fetch(web_token: &'static str, domain: &'static str) -> (Server, FakeFetch) { - let fetch = FakeFetch::default(); - let f = fetch.clone(); - let (server, _) = init_server(move |mut builder| { - builder.web_proxy_tokens = Arc::new(move |token| { - if &token == web_token { Some(domain.into()) } else { None } - }); - builder.fetch(f.clone()) - }, Default::default()); - - (server, fetch) -} - -pub fn serve() -> Server { - init_server(|builder| builder, Default::default()).0 -} - -pub fn request(server: Server, request: &str) -> http_client::Response { - http_client::request(server.addr(), request) -} - -pub fn assert_security_headers(headers: &[String]) { - http_client::assert_security_headers_present(headers, None) -} - -/// Webapps HTTP+RPC server build. -pub struct ServerBuilder { - dapps_path: PathBuf, - registrar: Arc>, - sync_status: Arc, - web_proxy_tokens: Arc, - allowed_hosts: DomainsValidation, - fetch: T, -} - -impl ServerBuilder { - /// Construct new dapps server - pub fn new>(fetch: FetchClient, dapps_path: P, registrar: Arc>) -> Self { - ServerBuilder { - dapps_path: dapps_path.as_ref().to_owned(), - registrar: registrar, - sync_status: Arc::new(FakeSync(false)), - web_proxy_tokens: Arc::new(|_| None), - allowed_hosts: DomainsValidation::Disabled, - fetch: fetch, - } - } -} - -impl ServerBuilder { - /// Set a fetch client to use. - pub fn fetch(self, fetch: X) -> ServerBuilder { - ServerBuilder { - dapps_path: self.dapps_path, - registrar: self.registrar, - sync_status: self.sync_status, - web_proxy_tokens: self.web_proxy_tokens, - allowed_hosts: self.allowed_hosts, - fetch: fetch, - } - } - - /// Asynchronously start server with no authentication, - /// returns result with `Server` handle on success or an error. - pub fn start_unsecured_http(self, addr: &SocketAddr, io: IoHandler) -> io::Result { - Server::start_http( - addr, - io, - self.allowed_hosts, - self.dapps_path, - vec![], - self.registrar, - self.sync_status, - self.web_proxy_tokens, - Remote::new_sync(), - self.fetch, - ) - } -} - -const DAPPS_DOMAIN: &'static str = "web3.site"; - -/// Webapps HTTP server. -pub struct Server { - server: Option, -} - -impl Server { - fn start_http( - addr: &SocketAddr, - io: IoHandler, - allowed_hosts: DomainsValidation, - dapps_path: PathBuf, - extra_dapps: Vec, - registrar: Arc>, - sync_status: Arc, - web_proxy_tokens: Arc, - remote: Remote, - fetch: F, - ) -> io::Result { - let health = NodeHealth::new( - sync_status.clone(), - TimeChecker::new::(&[], CpuPool::new(1)), - remote.clone(), - ); - let pool = ::futures_cpupool::CpuPool::new(1); - let middleware = - Middleware::dapps( - pool, - health, - dapps_path, - extra_dapps, - DAPPS_DOMAIN.into(), - registrar, - sync_status, - web_proxy_tokens, - fetch, - ); - - let mut allowed_hosts: Option> = allowed_hosts.into(); - allowed_hosts.as_mut().map(|hosts| { - hosts.push(format!("http://*.{}:*", DAPPS_DOMAIN).into()); - hosts.push(format!("http://*.{}", DAPPS_DOMAIN).into()); - }); - - http::ServerBuilder::new(io) - .request_middleware(middleware) - .allowed_hosts(allowed_hosts.into()) - .cors(http::DomainsValidation::Disabled) - .start_http(addr) - .map(|server| Server { - server: Some(server), - }) - } - - /// Returns address that this server is bound to. - pub fn addr(&self) -> &SocketAddr { - self.server.as_ref() - .expect("server is always Some at the start; it's consumed only when object is dropped; qed") - .address() - } -} - -impl Drop for Server { - fn drop(&mut self) { - self.server.take().unwrap().close() - } -} diff --git a/dapps/src/tests/helpers/registrar.rs b/dapps/src/tests/helpers/registrar.rs deleted file mode 100644 index b9acb1afc3e..00000000000 --- a/dapps/src/tests/helpers/registrar.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::str; -use std::sync::Arc; -use std::collections::HashMap; - -use ethereum_types::{H256, Address}; -use bytes::{Bytes, ToPretty}; -use registrar::{RegistrarClient, Asynchronous}; -use parking_lot::Mutex; -use rustc_hex::FromHex; - -const REGISTRAR: &'static str = "8e4e9b13d4b45cb0befc93c3061b1408f67316b2"; -const URLHINT: &'static str = "deadbeefcafe0000000000000000000000000000"; -const URLHINT_RESOLVE: &'static str = "267b6922"; -const DEFAULT_HASH: &'static str = "1472a9e190620cdf6b31f383373e45efcfe869a820c91f9ccd7eb9fb45e4985d"; - -pub struct FakeRegistrar { - pub calls: Arc>>, - pub responses: Mutex>>, -} - -impl FakeRegistrar { - pub fn new() -> Self { - FakeRegistrar { - calls: Arc::new(Mutex::new(Vec::new())), - responses: Mutex::new({ - let mut map = HashMap::new(); - map.insert( - (REGISTRAR.into(), "6795dbcd058740ee9a5a3fb9f1cfa10752baec87e09cc45cd7027fd54708271aca300c75000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000000".into()), - Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()), - ); - map.insert( - (URLHINT.into(), format!("{}{}", URLHINT_RESOLVE, DEFAULT_HASH)), - Ok(vec![]) - ); - map - }), - } - } - - pub fn set_result(&self, hash: H256, result: Result) { - self.responses.lock().insert( - (URLHINT.into(), format!("{}{:x}", URLHINT_RESOLVE, hash)), - result - ); - } -} - -impl RegistrarClient for FakeRegistrar { - type Call = Asynchronous; - - fn registrar_address(&self) -> Result { - Ok(REGISTRAR.parse().unwrap()) - } - - fn call_contract(&self, address: Address, data: Bytes) -> Self::Call { - let call = (address.to_hex(), data.to_hex()); - self.calls.lock().push(call.clone()); - let res = self.responses.lock().get(&call).cloned().expect(&format!("No response for call: {:?}", call)); - Box::new(::futures::future::done(res)) - } -} diff --git a/dapps/src/tests/mod.rs b/dapps/src/tests/mod.rs deleted file mode 100644 index c4d88cf9f17..00000000000 --- a/dapps/src/tests/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Dapps server test suite - -mod helpers; - -mod api; -mod fetch; -mod rpc; -mod validation; diff --git a/dapps/src/tests/rpc.rs b/dapps/src/tests/rpc.rs deleted file mode 100644 index 326fcd72a63..00000000000 --- a/dapps/src/tests/rpc.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use jsonrpc_core::{IoHandler, Value}; - -use tests::helpers::{serve_with_rpc, request}; - -#[test] -fn should_serve_rpc() { - // given - let mut io = IoHandler::default(); - io.add_method("rpc_test", |_| { - Ok(Value::String("Hello World!".into())) - }); - let server = serve_with_rpc(io); - - // when - let req = r#"{"jsonrpc":"2.0","id":1,"method":"rpc_test","params":[]}"#; - let response = request(server, &format!( - "\ - POST /rpc/ HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - Content-Type: application/json\r\n\ - Content-Length: {}\r\n\ - \r\n\ - {}\r\n\ - ", - req.as_bytes().len(), - req, - )); - - // then - response.assert_status("HTTP/1.1 200 OK"); - assert_eq!(response.body, "31\n{\"jsonrpc\":\"2.0\",\"result\":\"Hello World!\",\"id\":1}\n\n0\n\n".to_owned()); -} diff --git a/dapps/src/tests/validation.rs b/dapps/src/tests/validation.rs deleted file mode 100644 index f9d22f802d8..00000000000 --- a/dapps/src/tests/validation.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use tests::helpers::{serve_hosts, request}; - -#[test] -fn should_reject_invalid_host() { - // given - let server = serve_hosts(Some(vec!["localhost:8080".into()])); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: 127.0.0.1:8080\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 403 Forbidden"); - assert!(response.body.contains("Provided Host header is not whitelisted."), response.body); -} - -#[test] -fn should_serve_dapps_domains() { - // given - let server = serve_hosts(Some(vec!["localhost:8080".into()])); - - // when - let response = request(server, - "\ - GET / HTTP/1.1\r\n\ - Host: proxy.web3.site\r\n\ - Connection: close\r\n\ - \r\n\ - {} - " - ); - - // then - response.assert_status("HTTP/1.1 200 OK"); -} diff --git a/dapps/src/web.rs b/dapps/src/web.rs deleted file mode 100644 index fac0dca1afd..00000000000 --- a/dapps/src/web.rs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Serving web-based content (proxying) - -use std::sync::Arc; - -use base32; -use fetch::{self, Fetch}; -use hyper::{mime, StatusCode}; - -use apps; -use endpoint::{Endpoint, EndpointPath, Request, Response}; -use futures::future; -use futures_cpupool::CpuPool; -use handlers::{ - ContentFetcherHandler, ContentHandler, ContentValidator, ValidatorResponse, - StreamingHandler, -}; -use WebProxyTokens; - -pub struct Web { - web_proxy_tokens: Arc, - fetch: F, - pool: CpuPool, -} - -impl Web { - pub fn boxed( - web_proxy_tokens: Arc, - fetch: F, - pool: CpuPool, - ) -> Box { - Box::new(Web { - web_proxy_tokens, - fetch, - pool, - }) - } - - fn extract_target_url(&self, path: &EndpointPath) -> Result { - let token_and_url = path.app_params.get(0) - .map(|encoded| encoded.replace('.', "")) - .and_then(|encoded| base32::decode(base32::Alphabet::Crockford, &encoded.to_uppercase())) - .and_then(|data| String::from_utf8(data).ok()) - .ok_or_else(|| ContentHandler::error( - StatusCode::BadRequest, - "Invalid parameter", - "Couldn't parse given parameter:", - path.app_params.get(0).map(String::as_str), - ))?; - - let mut token_it = token_and_url.split('+'); - let token = token_it.next(); - let target_url = token_it.next(); - - // Check if token supplied in URL is correct. - let domain = match token.and_then(|token| self.web_proxy_tokens.domain(token)) { - Some(domain) => domain, - _ => { - return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Access Token", "Invalid or old web proxy access token supplied.", Some("Try refreshing the page."), - )); - } - }; - - // Validate protocol - let mut target_url = match target_url { - Some(url) if url.starts_with("http://") || url.starts_with("https://") => url.to_owned(), - _ => { - return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Protocol", "Invalid protocol used.", None, - )); - } - }; - - if !target_url.starts_with(&*domain) { - return Err(ContentHandler::error( - StatusCode::BadRequest, "Invalid Domain", "Dapp attempted to access invalid domain.", Some(&target_url), - )); - } - - if !target_url.ends_with("/") { - target_url = format!("{}/", target_url); - } - - // Skip the token - let query = path.query.as_ref().map_or_else(String::new, |query| format!("?{}", query)); - let path = path.app_params[1..].join("/"); - - Ok(format!("{}{}{}", target_url, path, query)) - } -} - -impl Endpoint for Web { - fn respond(&self, path: EndpointPath, req: Request) -> Response { - // First extract the URL (reject invalid URLs) - let target_url = match self.extract_target_url(&path) { - Ok(url) => url, - Err(response) => { - return Box::new(future::ok(response.into())); - } - }; - - let token = path.app_params.get(0) - .expect("`target_url` is valid; app_params is not empty;qed") - .to_owned(); - - Box::new(ContentFetcherHandler::new( - req.method(), - &target_url, - path, - WebInstaller { - token, - }, - self.fetch.clone(), - self.pool.clone(), - )) - } -} - -struct WebInstaller { - token: String, -} - -impl ContentValidator for WebInstaller { - type Error = String; - - fn validate_and_install(self, response: fetch::Response) -> Result { - let status = response.status(); - let is_html = response.is_html(); - let mime = response.content_type().unwrap_or(mime::TEXT_HTML); - let mut handler = StreamingHandler::new( - fetch::BodyReader::new(response), - status, - mime, - ); - if is_html { - handler.set_initial_content(&format!( - r#""#, - apps::URL_REFERER, - apps::WEB_PATH, - &self.token, - )); - } - Ok(ValidatorResponse::Streaming(handler)) - } -} diff --git a/dapps/node-health/Cargo.toml b/node-health/Cargo.toml similarity index 86% rename from dapps/node-health/Cargo.toml rename to node-health/Cargo.toml index 0ac3f62ae4c..22432a5f390 100644 --- a/dapps/node-health/Cargo.toml +++ b/node-health/Cargo.toml @@ -15,4 +15,4 @@ serde = "1.0" serde_derive = "1.0" time = "0.1.35" -parity-reactor = { path = "../../util/reactor" } +parity-reactor = { path = "../util/reactor" } diff --git a/dapps/node-health/src/health.rs b/node-health/src/health.rs similarity index 100% rename from dapps/node-health/src/health.rs rename to node-health/src/health.rs diff --git a/dapps/node-health/src/lib.rs b/node-health/src/lib.rs similarity index 100% rename from dapps/node-health/src/lib.rs rename to node-health/src/lib.rs diff --git a/dapps/node-health/src/time.rs b/node-health/src/time.rs similarity index 100% rename from dapps/node-health/src/time.rs rename to node-health/src/time.rs diff --git a/dapps/node-health/src/types.rs b/node-health/src/types.rs similarity index 100% rename from dapps/node-health/src/types.rs rename to node-health/src/types.rs diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 1ea64b67bbb..21af2968ef5 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -184,7 +184,7 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> { execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(false, false, false)?; + cmd.dirs.create_dirs(false, false)?; let cache = Arc::new(Mutex::new( LightDataCache::new(Default::default(), Duration::new(0, 0)) @@ -337,7 +337,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(false, false, false)?; + cmd.dirs.create_dirs(false, false)?; // prepare client config let mut client_config = to_client_config( @@ -528,7 +528,7 @@ fn start_client( execute_upgrades(&dirs.base, &db_dirs, algorithm, &compaction)?; // create dirs used by parity - dirs.create_dirs(false, false, false)?; + dirs.create_dirs(false, false)?; // prepare client config let client_config = to_client_config( diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 29a265757ca..460a78d9b18 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -26,15 +26,6 @@ usage! { // Arguments must start with arg_ // Flags must start with flag_ - CMD cmd_dapp - { - "Manage dapps", - - ARG arg_dapp_path: (Option) = None, - "", - "Path to the dapps", - } - CMD cmd_daemon { "Use Parity as a daemon", @@ -232,6 +223,17 @@ usage! { { "Print the hashed light clients headers of the given --chain (default: mainnet) in a JSON format. To be used as hardcoded headers in a genesis file.", } + + // CMD removed in 2.0 + + CMD cmd_dapp + { + "Manage dapps", + + ARG arg_dapp_path: (Option) = None, + "", + "Path to the dapps", + } } { // Global flags and arguments @@ -539,15 +541,6 @@ usage! { "--ipc-apis=[APIS]", "Specify custom API set available via JSON-RPC over IPC using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", - ["API and Console Options – Dapps"] - FLAG flag_no_dapps: (bool) = false, or |c: &Config| c.dapps.as_ref()?.disable.clone(), - "--no-dapps", - "Disable the Dapps server (e.g. status page).", - - ARG arg_dapps_path: (String) = "$BASE/dapps", or |c: &Config| c.dapps.as_ref()?.path.clone(), - "--dapps-path=[PATH]", - "Specify directory where dapps should be installed.", - ["API and Console Options – IPFS"] FLAG flag_ipfs_api: (bool) = false, or |c: &Config| c.ipfs.as_ref()?.enable.clone(), "--ipfs-api", @@ -969,6 +962,10 @@ usage! { "--fast-and-loose", "Does nothing; DB WAL is always activated.", + FLAG flag_no_dapps: (bool) = false, or |c: &Config| c.dapps.as_ref()?._legacy_disable.clone(), + "--no-dapps", + "Disable the Dapps server (e.g. status page).", + // ARG Removed in 1.6 or before. ARG arg_etherbase: (Option) = None, or |_| None, @@ -1029,27 +1026,27 @@ usage! { // ARG Removed in 1.7. - ARG arg_dapps_port: (Option) = None, or |c: &Config| c.dapps.as_ref()?.port.clone(), + ARG arg_dapps_port: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_port.clone(), "--dapps-port=[PORT]", "Does nothing; dapps server has been removed.", - ARG arg_dapps_interface: (Option) = None, or |c: &Config| c.dapps.as_ref()?.interface.clone(), + ARG arg_dapps_interface: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_interface.clone(), "--dapps-interface=[IP]", "Does nothing; dapps server has been removed.", - ARG arg_dapps_hosts: (Option) = None, or |c: &Config| c.dapps.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), + ARG arg_dapps_hosts: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_hosts.as_ref().map(|vec| vec.join(",")), "--dapps-hosts=[HOSTS]", "Does nothing; dapps server has been removed.", - ARG arg_dapps_cors: (Option) = None, or |c: &Config| c.dapps.as_ref()?.cors.clone(), + ARG arg_dapps_cors: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_cors.clone(), "--dapps-cors=[URL]", "Does nothing; dapps server has been removed.", - ARG arg_dapps_user: (Option) = None, or |c: &Config| c.dapps.as_ref()?.user.clone(), + ARG arg_dapps_user: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_user.clone(), "--dapps-user=[USERNAME]", "Dapps server authentication has been removed.", - ARG arg_dapps_pass: (Option) = None, or |c: &Config| c.dapps.as_ref()?.pass.clone(), + ARG arg_dapps_pass: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_pass.clone(), "--dapps-pass=[PASSWORD]", "Dapps server authentication has been removed.", @@ -1074,6 +1071,12 @@ usage! { ARG arg_tx_queue_ban_time: (Option) = None, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_time.clone(), "--tx-queue-ban-time=[SEC]", "Not supported.", + + // ARG removed in 2.0. + + ARG arg_dapps_path: (Option) = None, or |c: &Config| c.dapps.as_ref()?._legacy_path.clone(), + "--dapps-path=[PATH]", + "Specify directory where dapps should be installed.", } } @@ -1223,14 +1226,22 @@ struct Ipc { #[derive(Default, Debug, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] struct Dapps { - disable: Option, - port: Option, - interface: Option, - hosts: Option>, - cors: Option, - path: Option, - user: Option, - pass: Option, + #[serde(rename="disable")] + _legacy_disable: Option, + #[serde(rename="port")] + _legacy_port: Option, + #[serde(rename="interface")] + _legacy_interface: Option, + #[serde(rename="hosts")] + _legacy_hosts: Option>, + #[serde(rename="cors")] + _legacy_cors: Option, + #[serde(rename="path")] + _legacy_path: Option, + #[serde(rename="user")] + _legacy_user: Option, + #[serde(rename="pass")] + _legacy_pass: Option, } #[derive(Default, Debug, PartialEq, Deserialize)] @@ -1663,7 +1674,7 @@ mod tests { arg_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc,secretstore".into(), // DAPPS - arg_dapps_path: "$HOME/.parity/dapps".into(), + arg_dapps_path: Some("$HOME/.parity/dapps".into()), flag_no_dapps: false, // SECRETSTORE @@ -1922,14 +1933,14 @@ mod tests { apis: Some(vec!["rpc".into(), "eth".into()]), }), dapps: Some(Dapps { - disable: None, - port: Some(8080), - path: None, - interface: None, - hosts: None, - cors: None, - user: Some("username".into()), - pass: Some("password".into()) + _legacy_disable: None, + _legacy_port: Some(8080), + _legacy_path: None, + _legacy_interface: None, + _legacy_hosts: None, + _legacy_cors: None, + _legacy_user: Some("username".into()), + _legacy_pass: Some("password".into()) }), secretstore: Some(SecretStore { disable: None, diff --git a/parity/configuration.rs b/parity/configuration.rs index e3fdcce9407..6f6951e2fcd 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -17,7 +17,7 @@ use std::time::Duration; use std::io::Read; use std::net::SocketAddr; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::collections::BTreeMap; use std::cmp; use cli::{Args, ArgsError}; @@ -41,7 +41,6 @@ use dir::helpers::{replace_home, replace_home_and_local}; use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType}; use ethcore_logger::Config as LogConfig; use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path}; -use dapps::Configuration as DappsConfiguration; use ipfs::Configuration as IpfsConfiguration; use ethcore_private_tx::{ProviderConfig, EncryptorConfig}; use secretstore::{NodeSecretKey, Configuration as SecretStoreConfiguration, ContractAddress as SecretStoreContractAddress}; @@ -136,7 +135,6 @@ impl Configuration { let compaction = self.args.arg_db_compaction.parse()?; let warp_sync = !self.args.flag_no_warp; let geth_compatibility = self.args.flag_geth; - let dapps_conf = self.dapps_config(); let ipfs_conf = self.ipfs_config(); let secretstore_conf = self.secretstore_config()?; let format = self.format()?; @@ -370,13 +368,11 @@ impl Configuration { warp_barrier: self.args.arg_warp_barrier, geth_compatibility: geth_compatibility, net_settings: self.network_settings()?, - dapps_conf: dapps_conf, ipfs_conf: ipfs_conf, secretstore_conf: secretstore_conf, private_provider_conf: private_provider_conf, private_encryptor_conf: private_enc_conf, private_tx_enabled, - dapp: self.dapp_to_open()?, name: self.args.arg_identity, custom_bootnodes: self.args.arg_bootnodes.is_some(), no_periodic_snapshot: self.args.flag_no_periodic_snapshot, @@ -582,18 +578,6 @@ impl Configuration { self.args.arg_ntp_servers.split(",").map(str::to_owned).collect() } - fn dapps_config(&self) -> DappsConfiguration { - DappsConfiguration { - enabled: self.dapps_enabled(), - dapps_path: PathBuf::from(self.directories().dapps), - extra_dapps: if self.args.cmd_dapp { - self.args.arg_dapp_path.iter().map(|path| PathBuf::from(path)).collect() - } else { - vec![] - }, - } - } - fn secretstore_config(&self) -> Result { Ok(SecretStoreConfiguration { enabled: self.secretstore_enabled(), @@ -627,19 +611,6 @@ impl Configuration { } } - fn dapp_to_open(&self) -> Result, String> { - if !self.args.cmd_dapp { - return Ok(None); - } - let path = self.args.arg_dapp_path.as_ref().map(String::as_str).unwrap_or("."); - let path = Path::new(path).canonicalize() - .map_err(|e| format!("Invalid path: {}. Error: {:?}", path, e))?; - let name = path.file_name() - .and_then(|name| name.to_str()) - .ok_or_else(|| "Root path is not supported.".to_owned())?; - Ok(Some(name.into())) - } - fn gas_pricer_config(&self) -> Result { fn wei_per_gas(usd_per_tx: f32, usd_per_eth: f32) -> U256 { let wei_per_usd: f32 = 1.0e18 / usd_per_eth; @@ -881,8 +852,6 @@ impl Configuration { } fn ws_config(&self) -> Result { - let http = self.http_config()?; - let support_token_api = // enabled when not unlocking self.args.arg_unlock.is_none(); @@ -896,7 +865,6 @@ impl Configuration { origins: self.ws_origins(), signer_path: self.directories().signer.into(), support_token_api, - dapps_address: http.address(), max_connections: self.args.arg_ws_max_connections, }; @@ -980,7 +948,6 @@ impl Configuration { let db_path = replace_home_and_local(&data_path, &local_path, &base_db_path); let cache_path = replace_home_and_local(&data_path, &local_path, cache_path); let keys_path = replace_home(&data_path, &self.args.arg_keys_path); - let dapps_path = replace_home(&data_path, &self.args.arg_dapps_path); let secretstore_path = replace_home(&data_path, &self.args.arg_secretstore_path); let ui_path = replace_home(&data_path, &self.args.arg_ui_path); @@ -989,7 +956,6 @@ impl Configuration { base: data_path, cache: cache_path, db: db_path, - dapps: dapps_path, signer: ui_path, secretstore: secretstore_path, } @@ -1094,10 +1060,6 @@ impl Configuration { !self.args.flag_no_ws } - fn dapps_enabled(&self) -> bool { - !self.args.flag_dapps_off && !self.args.flag_no_dapps && self.rpc_enabled() && cfg!(feature = "dapps") - } - fn secretstore_enabled(&self) -> bool { !self.args.flag_no_secretstore && cfg!(feature = "secretstore") } @@ -1364,7 +1326,6 @@ mod tests { origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]), hosts: Some(vec![]), signer_path: expected.into(), - dapps_address: Some("127.0.0.1:8545".into()), support_token_api: true, max_connections: 100, }, LogConfig { @@ -1433,13 +1394,11 @@ mod tests { vm_type: Default::default(), geth_compatibility: false, net_settings: Default::default(), - dapps_conf: Default::default(), ipfs_conf: Default::default(), secretstore_conf: Default::default(), private_provider_conf: Default::default(), private_encryptor_conf: Default::default(), private_tx_enabled: false, - dapp: None, name: "".into(), custom_bootnodes: false, fat_db: Default::default(), @@ -1649,20 +1608,6 @@ mod tests { assert_eq!(conf4.directories().signer, "signer".to_owned()); } - #[test] - fn should_parse_dapp_opening() { - // given - let tempdir = TempDir::new("").unwrap(); - - // when - let conf0 = parse(&["parity", "dapp", tempdir.path().to_str().unwrap()]); - - // then - assert_eq!(conf0.dapp_to_open(), Ok(Some(tempdir.path().file_name().unwrap().to_str().unwrap().into()))); - let extra_dapps = conf0.dapps_config().extra_dapps; - assert_eq!(extra_dapps, vec![tempdir.path().to_owned()]); - } - #[test] fn should_not_bail_on_empty_line_in_reserved_peers() { let tempdir = TempDir::new("").unwrap(); @@ -1708,7 +1653,6 @@ mod tests { assert_eq!(c.net_conf.min_peers, 50); assert_eq!(c.net_conf.max_peers, 100); assert_eq!(c.ipc_conf.enabled, false); - assert_eq!(c.dapps_conf.enabled, false); assert_eq!(c.miner_options.force_sealing, true); assert_eq!(c.miner_options.reseal_on_external_tx, true); assert_eq!(c.miner_options.reseal_on_own_tx, true); diff --git a/parity/dapps.rs b/parity/dapps.rs deleted file mode 100644 index ce5b3a8daa7..00000000000 --- a/parity/dapps.rs +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::path::PathBuf; -use std::sync::Arc; - -use bytes::Bytes; -use dir::default_data_path; -use dir::helpers::replace_home; -use ethcore::client::{Client, BlockChainClient, BlockId, CallContract}; -use sync::LightSync; -use futures::{Future, future, IntoFuture}; -use futures_cpupool::CpuPool; -use hash_fetch::fetch::Client as FetchClient; -use registrar::{RegistrarClient, Asynchronous}; -use light::client::LightChainClient; -use light::on_demand::{self, OnDemand}; -use node_health::{SyncStatus, NodeHealth}; -use rpc; -use rpc_apis::SignerService; -use transaction::{Transaction, Action}; -use ethereum_types::Address; - -#[derive(Debug, PartialEq, Clone)] -pub struct Configuration { - pub enabled: bool, - pub dapps_path: PathBuf, - pub extra_dapps: Vec, -} - -impl Default for Configuration { - fn default() -> Self { - let data_dir = default_data_path(); - Configuration { - enabled: true, - dapps_path: replace_home(&data_dir, "$BASE/dapps").into(), - extra_dapps: vec![], - } - } -} - -impl Configuration { - pub fn address(&self, address: Option<::parity_rpc::Host>) -> Option<::parity_rpc::Host> { - match self.enabled { - true => address, - false => None, - } - } -} - -/// Registrar implementation of the full client. -pub struct FullRegistrar { - /// Handle to the full client. - pub client: Arc, -} - -impl FullRegistrar { - pub fn new(client: Arc) -> Self { - FullRegistrar { - client, - } - } -} - -impl RegistrarClient for FullRegistrar { - type Call = Asynchronous; - - fn registrar_address(&self) -> Result { - self.client.registrar_address() - .ok_or_else(|| "Registrar not defined.".into()) - } - - fn call_contract(&self, address: Address, data: Bytes) -> Self::Call { - Box::new(self.client.call_contract(BlockId::Latest, address, data).into_future()) - } -} - -/// Registrar implementation for the light client. -pub struct LightRegistrar { - /// The light client. - pub client: Arc, - /// Handle to the on-demand service. - pub on_demand: Arc, - /// Handle to the light network service. - pub sync: Arc, -} - -impl RegistrarClient for LightRegistrar { - type Call = Box + Send>; - - fn registrar_address(&self) -> Result { - self.client.engine().additional_params().get("registrar") - .ok_or_else(|| "Registrar not defined.".into()) - .and_then(|registrar| { - registrar.parse().map_err(|e| format!("Invalid registrar address: {:?}", e)) - }) - } - - fn call_contract(&self, address: Address, data: Bytes) -> Self::Call { - let header = self.client.best_block_header(); - let env_info = self.client.env_info(BlockId::Hash(header.hash())) - .ok_or_else(|| format!("Cannot fetch env info for header {}", header.hash())); - - let env_info = match env_info { - Ok(e) => e, - Err(e) => return Box::new(future::err(e)), - }; - - let maybe_future = self.sync.with_context(move |ctx| { - self.on_demand - .request(ctx, on_demand::request::TransactionProof { - tx: Transaction { - nonce: self.client.engine().account_start_nonce(header.number()), - action: Action::Call(address), - gas: 50_000.into(), // should be enough for all registry lookups. TODO: exponential backoff - gas_price: 0.into(), - value: 0.into(), - data: data, - }.fake_sign(Address::default()), - header: header.into(), - env_info: env_info, - engine: self.client.engine().clone(), - }) - .expect("No back-references; therefore all back-refs valid; qed") - .then(|res| match res { - Ok(Ok(executed)) => Ok(executed.output), - Ok(Err(e)) => Err(format!("Failed to execute transaction: {}", e)), - Err(_) => Err(format!("On-demand service dropped request unexpectedly.")), - }) - }); - - match maybe_future { - Some(fut) => Box::new(fut), - None => Box::new(future::err("cannot query registry: network disabled".into())), - } - } -} - -// TODO: light client implementation forwarding to OnDemand and waiting for future -// to resolve. -#[derive(Clone)] -pub struct Dependencies { - pub node_health: NodeHealth, - pub sync_status: Arc, - pub contract_client: Arc>, - pub fetch: FetchClient, - pub pool: CpuPool, - pub signer: Arc, -} - -pub fn new(configuration: Configuration, deps: Dependencies) -> Result, String> { - if !configuration.enabled { - return Ok(None); - } - - server::dapps_middleware( - deps, - configuration.dapps_path, - configuration.extra_dapps, - rpc::DAPPS_DOMAIN, - ).map(Some) -} - -pub use self::server::{Middleware, service}; - -#[cfg(not(feature = "dapps"))] -mod server { - use super::Dependencies; - use std::sync::Arc; - use std::path::PathBuf; - use parity_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction}; - use rpc_apis; - - pub struct Middleware; - impl RequestMiddleware for Middleware { - fn on_request(&self, _req: hyper::Request) -> RequestMiddlewareAction { - unreachable!() - } - } - - pub fn dapps_middleware( - _deps: Dependencies, - _dapps_path: PathBuf, - _extra_dapps: Vec, - _dapps_domain: &str, - ) -> Result { - Err("Your Parity version has been compiled without WebApps support.".into()) - } - - pub fn service(_: &Option) -> Option> { - None - } -} - -#[cfg(feature = "dapps")] -mod server { - use super::Dependencies; - use std::path::PathBuf; - use std::sync::Arc; - use rpc_apis; - - use parity_dapps; - - pub use parity_dapps::Middleware; - - pub fn dapps_middleware( - deps: Dependencies, - dapps_path: PathBuf, - extra_dapps: Vec, - dapps_domain: &str, - ) -> Result { - let signer = deps.signer; - let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token)); - - Ok(parity_dapps::Middleware::dapps( - deps.pool, - deps.node_health, - dapps_path, - extra_dapps, - dapps_domain, - deps.contract_client, - deps.sync_status, - web_proxy_tokens, - deps.fetch, - )) - } - - pub fn service(middleware: &Option) -> Option> { - middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper { - endpoints: m.endpoints().clone(), - }) as Arc) - } - - pub struct DappsServiceWrapper { - endpoints: parity_dapps::Endpoints, - } - - impl rpc_apis::DappsService for DappsServiceWrapper { - fn list_dapps(&self) -> Vec { - self.endpoints.list() - .into_iter() - .map(|app| rpc_apis::LocalDapp { - id: app.id.unwrap_or_else(|| "unknown".into()), - name: app.name, - description: app.description, - version: app.version, - author: app.author, - icon_url: app.icon_url, - local_url: app.local_url, - }) - .collect() - } - - fn refresh_local_dapps(&self) -> bool { - self.endpoints.refresh_local_dapps(); - true - } - } -} diff --git a/parity/deprecated.rs b/parity/deprecated.rs index 0753876a7e7..514e7d5d92d 100644 --- a/parity/deprecated.rs +++ b/parity/deprecated.rs @@ -209,6 +209,22 @@ pub fn find_deprecated(args: &Args) -> Vec { result.push(Deprecated::Removed("--fast-and-loose")); } + if args.cmd_dapp { + result.push(Deprecated::Removed("parity dapp")); + } + + if args.arg_dapp_path.is_some() { + result.push(Deprecated::Removed("--dapp-path")); + } + + if args.flag_no_dapps { + result.push(Deprecated::Removed("--no-dapps")); + } + + if args.arg_dapps_path.is_some() { + result.push(Deprecated::Removed("--dapps-path")); + } + result } diff --git a/parity/export_hardcoded_sync.rs b/parity/export_hardcoded_sync.rs index 15fe199f427..b3121f08616 100644 --- a/parity/export_hardcoded_sync.rs +++ b/parity/export_hardcoded_sync.rs @@ -68,7 +68,7 @@ pub fn execute(cmd: ExportHsyncCmd) -> Result { execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(false, false, false)?; + cmd.dirs.create_dirs(false, false)?; // TODO: configurable cache size. let cache = LightDataCache::new(Default::default(), Duration::from_secs(60 * GAS_CORPUS_EXPIRATION_MINUTES)); diff --git a/parity/lib.rs b/parity/lib.rs index 4a925bba70a..3f1695ad6ca 100644 --- a/parity/lib.rs +++ b/parity/lib.rs @@ -88,8 +88,6 @@ extern crate parity_dapps; #[macro_use] extern crate pretty_assertions; -#[cfg(windows)] extern crate winapi; - #[cfg(test)] extern crate tempdir; @@ -101,7 +99,6 @@ mod blockchain; mod cache; mod cli; mod configuration; -mod dapps; mod export_hardcoded_sync; mod ipfs; mod deprecated; @@ -118,7 +115,6 @@ mod secretstore; mod signer; mod snapshot; mod upgrade; -mod url; mod user_defaults; mod whisper; mod db; @@ -205,10 +201,6 @@ fn execute(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res match command.cmd { Cmd::Run(run_cmd) => { - if let Some(ref dapp) = run_cmd.dapp { - open_dapp(&run_cmd.dapps_conf, &run_cmd.http_conf, dapp)?; - } - let outcome = run::execute(run_cmd, logger, on_client_rq, on_updater_rq)?; Ok(ExecutionAction::Running(outcome)) }, @@ -248,13 +240,3 @@ pub fn start(conf: Configuration, on_client_rq: Cr, on_updater_rq: Rr) - execute(conf.into_command()?, on_client_rq, on_updater_rq) } - -fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> { - if !dapps_conf.enabled { - return Err("Cannot use DAPP command with Dapps turned off.".into()) - } - - let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp); - url::open(&url).map_err(|e| format!("{}", e))?; - Ok(()) -} diff --git a/parity/rpc.rs b/parity/rpc.rs index b5733f0ce0c..eb769eda087 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -19,7 +19,6 @@ use std::sync::Arc; use std::path::PathBuf; use std::collections::HashSet; -use dapps; use dir::default_data_path; use dir::helpers::replace_home; use helpers::parity_ipc_path; @@ -48,12 +47,6 @@ pub struct HttpConfiguration { pub max_payload: usize, } -impl HttpConfiguration { - pub fn address(&self) -> Option { - address(self.enabled, &self.interface, self.port, &self.hosts) - } -} - impl Default for HttpConfiguration { fn default() -> Self { HttpConfiguration { @@ -103,7 +96,6 @@ pub struct WsConfiguration { pub hosts: Option>, pub signer_path: PathBuf, pub support_token_api: bool, - pub dapps_address: Option, } impl Default for WsConfiguration { @@ -119,7 +111,6 @@ impl Default for WsConfiguration { hosts: Some(Vec::new()), signer_path: replace_home(&data_dir, "$BASE/signer").into(), support_token_api: true, - dapps_address: Some("127.0.0.1:8545".into()), } } } @@ -173,7 +164,7 @@ pub fn new_ws( }; let remote = deps.remote.clone(); - let allowed_origins = into_domains(with_domain(conf.origins, domain, &conf.dapps_address)); + let allowed_origins = into_domains(with_domain(conf.origins, domain, &None)); let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()))); let signer_path; @@ -210,7 +201,6 @@ pub fn new_http( options: &str, conf: HttpConfiguration, deps: &Dependencies, - middleware: Option, ) -> Result, String> { if !conf.enabled { return Ok(None); @@ -232,7 +222,6 @@ pub fn new_http( handler, remote, rpc::RpcExtractor, - middleware, conf.server_threads, conf.max_payload, ); diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index d76438b1594..ade6c696946 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -20,7 +20,7 @@ use std::str::FromStr; use std::sync::{Arc, Weak}; pub use parity_rpc::signer::SignerService; -pub use parity_rpc::dapps::{DappsService, LocalDapp}; +pub use parity_rpc::dapps::LocalDapp; use ethcore_service::PrivateTxService; use ethcore::account_provider::AccountProvider; @@ -227,8 +227,6 @@ pub struct FullDependencies { pub updater: Arc, pub health: NodeHealth, pub geth_compatibility: bool, - pub dapps_service: Option>, - pub dapps_address: Option, pub ws_address: Option, pub fetch: FetchClient, pub pool: CpuPool, @@ -337,7 +335,6 @@ impl FullDependencies { self.logger.clone(), self.settings.clone(), signer, - self.dapps_address.clone(), self.ws_address.clone(), ).to_delegate()); @@ -362,7 +359,6 @@ impl FullDependencies { &self.miner, &self.updater, &self.net_service, - self.dapps_service.clone(), self.fetch.clone(), self.pool.clone(), ).to_delegate()) @@ -439,8 +435,6 @@ pub struct LightDependencies { pub on_demand: Arc<::light::on_demand::OnDemand>, pub cache: Arc>, pub transaction_queue: Arc>, - pub dapps_service: Option>, - pub dapps_address: Option, pub ws_address: Option, pub fetch: FetchClient, pub pool: CpuPool, @@ -553,7 +547,6 @@ impl LightDependencies { self.settings.clone(), self.health.clone(), signer, - self.dapps_address.clone(), self.ws_address.clone(), self.gas_price_percentile, ).to_delegate()); @@ -576,7 +569,6 @@ impl LightDependencies { Api::ParitySet => { handler.extend_with(light::ParitySetClient::new( self.sync.clone(), - self.dapps_service.clone(), self.fetch.clone(), self.pool.clone(), ).to_delegate()) diff --git a/parity/run.rs b/parity/run.rs index 9bde9ad40a2..176121d750b 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -21,8 +21,9 @@ use std::time::{Duration, Instant}; use std::thread; use ansi_term::Colour; +use bytes::Bytes; use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; -use ethcore::client::{Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; +use ethcore::client::{BlockId, CallContract, Client, Mode, DatabaseCompactionProfile, VMType, BlockChainClient, BlockInfo}; use ethcore::ethstore::ethkey; use ethcore::miner::{stratum, Miner, MinerService, MinerOptions}; use ethcore::snapshot; @@ -30,9 +31,11 @@ use ethcore::spec::{SpecParams, OptimizeFor}; use ethcore::verification::queue::VerifierSettings; use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_service::ClientService; +use ethereum_types::Address; use sync::{self, SyncConfig}; #[cfg(feature = "work-notify")] use miner::work_notify::WorkPoster; +use futures::IntoFuture; use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; use informant::{Informant, LightNodeInformantData, FullNodeInformantData}; @@ -55,10 +58,10 @@ use upgrade::upgrade_key_location; use dir::{Directories, DatabaseDirectories}; use cache::CacheConfig; use user_defaults::UserDefaults; -use dapps; use ipfs; use jsonrpc_core; use modules; +use registrar::{RegistrarClient, Asynchronous}; use rpc; use rpc_apis; use secretstore; @@ -112,13 +115,11 @@ pub struct RunCmd { pub vm_type: VMType, pub geth_compatibility: bool, pub net_settings: NetworkSettings, - pub dapps_conf: dapps::Configuration, pub ipfs_conf: ipfs::Configuration, pub secretstore_conf: secretstore::Configuration, pub private_provider_conf: ProviderConfig, pub private_encryptor_conf: EncryptorConfig, pub private_tx_enabled: bool, - pub dapp: Option, pub name: String, pub custom_bootnodes: bool, pub stratum: Option, @@ -185,10 +186,10 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result); impl fmt::Debug for LightSyncStatus { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { @@ -309,26 +304,14 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result) -> Result) -> Result(cmd: RunCmd, logger: Arc, on_client_rq: execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; // create dirs used by parity - cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.acc_conf.unlocked_accounts.len() == 0, cmd.secretstore_conf.enabled)?; + cmd.dirs.create_dirs(cmd.acc_conf.unlocked_accounts.len() == 0, cmd.secretstore_conf.enabled)?; // run in daemon mode if let Some(pid_file) = cmd.daemon { @@ -448,7 +429,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: } //print out running parity environment - print_running_environment(&spec.name, &cmd.dirs, &db_dirs, &cmd.dapps_conf); + print_running_environment(&spec.name, &cmd.dirs, &db_dirs); // display info about used pruning algorithm info!("State DB configuration: {}{}{}", @@ -709,7 +690,21 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: chain_notify.start(); } - let contract_client = Arc::new(::dapps::FullRegistrar::new(client.clone())); + let contract_client = { + struct FullRegistrar { client: Arc } + impl RegistrarClient for FullRegistrar { + type Call = Asynchronous; + fn registrar_address(&self) -> Result { + self.client.registrar_address() + .ok_or_else(|| "Registrar not defined.".into()) + } + fn call_contract(&self, address: Address, data: Bytes) -> Self::Call { + Box::new(self.client.call_contract(BlockId::Latest, address, data).into_future()) + } + } + + Arc::new(FullRegistrar { client: client.clone() }) + }; // the updater service let updater_fetch = fetch.clone(); @@ -727,7 +722,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.logger_config)); // the dapps server - let (node_health, dapps_deps) = { + let node_health = { let (sync, client) = (sync_provider.clone(), client.clone()); struct SyncStatus(Arc, Arc, sync::NetworkConfiguration); @@ -747,23 +742,13 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: } let sync_status = Arc::new(SyncStatus(sync, client, net_conf)); - let node_health = node_health::NodeHealth::new( + node_health::NodeHealth::new( sync_status.clone(), node_health::TimeChecker::new(&cmd.ntp_servers, cpu_pool.clone()), event_loop.remote(), - ); - (node_health.clone(), dapps::Dependencies { - sync_status, - node_health, - contract_client, - fetch: fetch.clone(), - pool: cpu_pool.clone(), - signer: signer_service.clone(), - }) + ) }; - let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; - let dapps_service = dapps::service(&dapps_middleware); let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies { signer_service: signer_service, snapshot: snapshot_service.clone(), @@ -779,8 +764,6 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: net_service: manage_network.clone(), updater: updater.clone(), geth_compatibility: cmd.geth_compatibility, - dapps_service: dapps_service, - dapps_address: cmd.dapps_conf.address(cmd.http_conf.address()), ws_address: cmd.ws_conf.address(), fetch: fetch.clone(), pool: cpu_pool.clone(), @@ -807,7 +790,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: let rpc_direct = rpc::setup_apis(rpc_apis::ApiSet::All, &dependencies); let ws_server = rpc::new_ws(cmd.ws_conf.clone(), &dependencies)?; let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; - let http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies, dapps_middleware)?; + let http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies)?; // secret store key server let secretstore_deps = secretstore::Dependencies { @@ -1001,11 +984,10 @@ fn daemonize(_pid_file: String) -> Result<(), String> { Err("daemon is no supported on windows".into()) } -fn print_running_environment(spec_name: &String, dirs: &Directories, db_dirs: &DatabaseDirectories, dapps_conf: &dapps::Configuration) { +fn print_running_environment(spec_name: &String, dirs: &Directories, db_dirs: &DatabaseDirectories) { info!("Starting {}", Colour::White.bold().paint(version())); info!("Keys path {}", Colour::White.bold().paint(dirs.keys_path(spec_name).to_string_lossy().into_owned())); info!("DB path {}", Colour::White.bold().paint(db_dirs.db_root_path().to_string_lossy().into_owned())); - info!("Path to dapps {}", Colour::White.bold().paint(dapps_conf.dapps_path.to_string_lossy().into_owned())); } fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[Password]) -> Result { diff --git a/parity/url.rs b/parity/url.rs deleted file mode 100644 index 832da84908b..00000000000 --- a/parity/url.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Cross-platform open url in default browser - -use std; -use std::os::raw::c_int; - -#[allow(unused)] -pub enum Error { - ProcessError(std::io::Error), - WindowsShellExecute(c_int), -} - -impl From for Error { - fn from(err: std::io::Error) -> Self { - Error::ProcessError(err) - } -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - match *self { - Error::ProcessError(ref e) => write!(f, "{}", e), - Error::WindowsShellExecute(e) => write!(f, "WindowsShellExecute error: {}", e), - } - } -} - -#[cfg(windows)] -pub fn open(url: &str) -> Result<(), Error> { - use std::ffi::CString; - use std::ptr; - use winapi::um::shellapi::ShellExecuteA; - use winapi::um::winuser::SW_SHOWNORMAL as Normal; - - const WINDOWS_SHELL_EXECUTE_SUCCESS: c_int = 32; - - let h_instance = unsafe { - ShellExecuteA(ptr::null_mut(), - CString::new("open").unwrap().as_ptr(), - CString::new(url.to_owned().replace("\n", "%0A")).unwrap().as_ptr(), - ptr::null(), - ptr::null(), - Normal) as c_int - }; - - // https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx - // `ShellExecute` returns a value greater than 32 on success - if h_instance > WINDOWS_SHELL_EXECUTE_SUCCESS { - Ok(()) - } else { - Err(Error::WindowsShellExecute(h_instance)) - } -} - -#[cfg(any(target_os="macos", target_os="freebsd"))] -pub fn open(url: &str) -> Result<(), Error> { - let _ = std::process::Command::new("open").arg(url).spawn()?; - Ok(()) -} - -#[cfg(target_os="linux")] -pub fn open(url: &str) -> Result<(), Error> { - let _ = std::process::Command::new("xdg-open").arg(url).spawn()?; - Ok(()) -} - -#[cfg(any(target_os="android", target_os="ios"))] -pub fn open(_url: &str) -> Result<(), Error> { - // TODO: While it is generally always bad to leave a function implemented, there is not much - // more we can do here. This function will eventually be removed when we compile Parity - // as a library and not as a full binary. - Ok(()) -} diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index af5b4f413d2..d551d90c530 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -54,7 +54,7 @@ ethkey = { path = "../ethkey" } ethstore = { path = "../ethstore" } fetch = { path = "../util/fetch" } keccak-hash = { git = "https://github.com/paritytech/parity-common" } -node-health = { path = "../dapps/node-health" } +node-health = { path = "../node-health" } parity-reactor = { path = "../util/reactor" } parity-updater = { path = "../updater" } parity-version = { path = "../util/version" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 860e4bc6d74..98d743881ed 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -131,14 +131,13 @@ use http::tokio_core; pub type HttpServer = http::Server; /// Start http server asynchronously and returns result with `Server` handle on success or an error. -pub fn start_http( +pub fn start_http( addr: &SocketAddr, cors_domains: http::DomainsValidation, allowed_hosts: http::DomainsValidation, handler: H, remote: tokio_core::reactor::Remote, extractor: T, - middleware: Option, threads: usize, max_payload: usize, ) -> ::std::io::Result where @@ -146,21 +145,45 @@ pub fn start_http( S: jsonrpc_core::Middleware, H: Into>, T: HttpMetaExtractor, - R: RequestMiddleware, { let extractor = http_common::MetaExtractor::new(extractor); - let mut builder = http::ServerBuilder::with_meta_extractor(handler, extractor) + Ok(http::ServerBuilder::with_meta_extractor(handler, extractor) .threads(threads) .event_loop_remote(remote) .cors(cors_domains.into()) .allowed_hosts(allowed_hosts.into()) - .max_request_body_size(max_payload * 1024 * 1024); - - if let Some(dapps) = middleware { - builder = builder.request_middleware(dapps) - } + .max_request_body_size(max_payload * 1024 * 1024) + .start_http(addr)?) +} - Ok(builder.start_http(addr)?) +/// Same as `start_http`, but takes an additional `middleware` parameter that is introduced as a +/// hyper middleware. +pub fn start_http_with_middleware( + addr: &SocketAddr, + cors_domains: http::DomainsValidation, + allowed_hosts: http::DomainsValidation, + handler: H, + remote: tokio_core::reactor::Remote, + extractor: T, + middleware: R, + threads: usize, + max_payload: usize, +) -> ::std::io::Result where + M: jsonrpc_core::Metadata, + S: jsonrpc_core::Middleware, + H: Into>, + T: HttpMetaExtractor, + R: RequestMiddleware, +{ + let extractor = http_common::MetaExtractor::new(extractor); + Ok(http::ServerBuilder::with_meta_extractor(handler, extractor) + .threads(threads) + .event_loop_remote(remote) + .cors(cors_domains.into()) + .allowed_hosts(allowed_hosts.into()) + .max_request_body_size(max_payload * 1024 * 1024) + .request_middleware(middleware) + .start_http(addr)?) } /// Start ipc server asynchronously and returns result with `Server` handle on success or an error. diff --git a/rpc/src/tests/rpc.rs b/rpc/src/tests/rpc.rs index d0c0fafd912..d15aeca6cb0 100644 --- a/rpc/src/tests/rpc.rs +++ b/rpc/src/tests/rpc.rs @@ -26,19 +26,19 @@ fn serve(handler: Option>) -> Server { let address = "127.0.0.1:0".parse().unwrap(); let handler = handler.unwrap_or_default(); - Server::new(|remote| ::start_http( + Server::new(|remote| ::start_http_with_middleware( &address, http::DomainsValidation::Disabled, http::DomainsValidation::Disabled, handler, remote, extractors::RpcExtractor, - Some(|request: hyper::Request| { + |request: hyper::Request| { http::RequestMiddlewareAction::Proceed { should_continue_on_invalid_cors: false, request, } - }), + }, 1, 5, ).unwrap()) diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 9ef316b70be..f722781111e 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -58,7 +58,6 @@ pub struct ParityClient { settings: Arc, health: NodeHealth, signer: Option>, - dapps_address: Option, ws_address: Option, eip86_transition: u64, gas_price_percentile: usize, @@ -74,7 +73,6 @@ impl ParityClient { settings: Arc, health: NodeHealth, signer: Option>, - dapps_address: Option, ws_address: Option, gas_price_percentile: usize, ) -> Self { @@ -85,7 +83,6 @@ impl ParityClient { settings, health, signer, - dapps_address, ws_address, eip86_transition: client.eip86_transition(), client, @@ -330,8 +327,7 @@ impl Parity for ParityClient { } fn dapps_url(&self) -> Result { - helpers::to_url(&self.dapps_address) - .ok_or_else(|| errors::dapps_disabled()) + Err(errors::dapps_disabled()) } fn ws_url(&self) -> Result { diff --git a/rpc/src/v1/impls/light/parity_set.rs b/rpc/src/v1/impls/light/parity_set.rs index 4e907deaf19..dfe90a8ac8d 100644 --- a/rpc/src/v1/impls/light/parity_set.rs +++ b/rpc/src/v1/impls/light/parity_set.rs @@ -27,7 +27,6 @@ use hash::keccak_buffer; use jsonrpc_core::{Result, BoxFuture}; use jsonrpc_core::futures::Future; -use v1::helpers::dapps::DappsService; use v1::helpers::errors; use v1::traits::ParitySet; use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp}; @@ -35,17 +34,15 @@ use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp}; /// Parity-specific rpc interface for operations altering the settings. pub struct ParitySetClient { net: Arc, - dapps: Option>, fetch: F, pool: CpuPool, } impl ParitySetClient { /// Creates new `ParitySetClient` with given `Fetch`. - pub fn new(net: Arc, dapps: Option>, fetch: F, p: CpuPool) -> Self { + pub fn new(net: Arc, fetch: F, p: CpuPool) -> Self { ParitySetClient { net: net, - dapps: dapps, fetch: fetch, pool: p, } @@ -141,11 +138,11 @@ impl ParitySet for ParitySetClient { } fn dapps_refresh(&self) -> Result { - self.dapps.as_ref().map(|dapps| dapps.refresh_local_dapps()).ok_or_else(errors::dapps_disabled) + Err(errors::dapps_disabled()) } fn dapps_list(&self) -> Result> { - self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled) + Err(errors::dapps_disabled()) } fn upgrade_ready(&self) -> Result> { diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index acafbb1cd68..ac4bb11525b 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -63,7 +63,6 @@ pub struct ParityClient { logger: Arc, settings: Arc, signer: Option>, - dapps_address: Option, ws_address: Option, eip86_transition: u64, } @@ -83,7 +82,6 @@ impl ParityClient where logger: Arc, settings: Arc, signer: Option>, - dapps_address: Option, ws_address: Option, ) -> Self { let eip86_transition = client.eip86_transition(); @@ -98,7 +96,6 @@ impl ParityClient where logger, settings, signer, - dapps_address, ws_address, eip86_transition, } @@ -351,8 +348,7 @@ impl Parity for ParityClient where } fn dapps_url(&self) -> Result { - helpers::to_url(&self.dapps_address) - .ok_or_else(|| errors::dapps_disabled()) + Err(errors::dapps_disabled()) } fn ws_url(&self) -> Result { diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index e861bd3eb92..82880f7207d 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -29,7 +29,6 @@ use updater::{Service as UpdateService}; use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_core::futures::Future; -use v1::helpers::dapps::DappsService; use v1::helpers::errors; use v1::traits::ParitySet; use v1::types::{Bytes, H160, H256, U256, ReleaseInfo, Transaction, LocalDapp}; @@ -40,7 +39,6 @@ pub struct ParitySetClient { miner: Arc, updater: Arc, net: Arc, - dapps: Option>, fetch: F, pool: CpuPool, eip86_transition: u64, @@ -55,7 +53,6 @@ impl ParitySetClient miner: &Arc, updater: &Arc, net: &Arc, - dapps: Option>, fetch: F, pool: CpuPool, ) -> Self { @@ -64,7 +61,6 @@ impl ParitySetClient miner: miner.clone(), updater: updater.clone(), net: net.clone(), - dapps: dapps, fetch: fetch, pool: pool, eip86_transition: client.eip86_transition(), @@ -187,11 +183,11 @@ impl ParitySet for ParitySetClient where } fn dapps_refresh(&self) -> Result { - self.dapps.as_ref().map(|dapps| dapps.refresh_local_dapps()).ok_or_else(errors::dapps_disabled) + Err(errors::dapps_disabled()) } fn dapps_list(&self) -> Result> { - self.dapps.as_ref().map(|dapps| dapps.list_dapps()).ok_or_else(errors::dapps_disabled) + Err(errors::dapps_disabled()) } fn upgrade_ready(&self) -> Result> { diff --git a/rpc/src/v1/tests/helpers/dapps.rs b/rpc/src/v1/tests/helpers/dapps.rs deleted file mode 100644 index 70f42a29e50..00000000000 --- a/rpc/src/v1/tests/helpers/dapps.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Test implementation of dapps service. - -use v1::types::LocalDapp; -use v1::helpers::dapps::DappsService; - -/// Test implementation of dapps service. Will always return the same list of dapps. -#[derive(Default, Clone)] -pub struct TestDappsService; - -impl DappsService for TestDappsService { - fn list_dapps(&self) -> Vec { - vec![LocalDapp { - id: "skeleton".into(), - name: "Skeleton".into(), - description: "A skeleton dapp".into(), - version: "0.1".into(), - author: "Parity Technologies Ltd".into(), - icon_url: "title.png".into(), - local_url: None, - }] - } - - fn refresh_local_dapps(&self) -> bool { - true - } -} diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index a2782eec60c..ba87428b989 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -16,13 +16,11 @@ //! Test rpc services. -mod dapps; mod miner_service; mod snapshot_service; mod sync_provider; mod update_service; -pub use self::dapps::TestDappsService; pub use self::miner_service::TestMinerService; pub use self::snapshot_service::TestSnapshotService; pub use self::sync_provider::{Config, TestSyncProvider}; diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index a2db6f08341..e4b136586bd 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -45,7 +45,6 @@ pub struct Dependencies { pub settings: Arc, pub network: Arc, pub accounts: Arc, - pub dapps_address: Option, pub ws_address: Option, } @@ -75,7 +74,6 @@ impl Dependencies { }), network: Arc::new(TestManageNetwork), accounts: Arc::new(AccountProvider::transient_provider()), - dapps_address: Some("127.0.0.1:18080".into()), ws_address: Some("127.0.0.1:18546".into()), } } @@ -92,7 +90,6 @@ impl Dependencies { self.logger.clone(), self.settings.clone(), signer, - self.dapps_address.clone(), self.ws_address.clone(), ) } @@ -431,19 +428,15 @@ fn rpc_parity_ws_address() { #[test] fn rpc_parity_dapps_address() { // given - let mut deps = Dependencies::new(); + let deps = Dependencies::new(); let io1 = deps.default_client(); - deps.dapps_address = None; - let io2 = deps.default_client(); // when let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsUrl", "params": [], "id": 1}"#; - let response1 = r#"{"jsonrpc":"2.0","result":"127.0.0.1:18080","id":1}"#; - let response2 = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Dapps Server is disabled. This API is not available."},"id":1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Dapps Server is disabled. This API is not available."},"id":1}"#; // then - assert_eq!(io1.handle_request_sync(request), Some(response1.to_owned())); - assert_eq!(io2.handle_request_sync(request), Some(response2.to_owned())); + assert_eq!(io1.handle_request_sync(request), Some(response.to_owned())); } #[test] diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index 90855afe54a..0347da39ad6 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -26,7 +26,7 @@ use futures_cpupool::CpuPool; use jsonrpc_core::IoHandler; use v1::{ParitySet, ParitySetClient}; -use v1::tests::helpers::{TestMinerService, TestUpdater, TestDappsService}; +use v1::tests::helpers::{TestMinerService, TestUpdater}; use super::manage_network::TestManageNetwork; use fake_fetch::FakeFetch; @@ -55,9 +55,8 @@ fn parity_set_client( updater: &Arc, net: &Arc, ) -> TestParitySetClient { - let dapps_service = Arc::new(TestDappsService); let pool = CpuPool::new(1); - ParitySetClient::new(client, miner, updater, &(net.clone() as Arc), Some(dapps_service), FakeFetch::new(Some(1)), pool) + ParitySetClient::new(client, miner, updater, &(net.clone() as Arc), FakeFetch::new(Some(1)), pool) } #[test] @@ -250,7 +249,7 @@ fn rpc_parity_set_dapps_list() { io.extend_with(parity_set_client(&client, &miner, &updater, &network).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "parity_dappsList", "params":[], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":[{"author":"Parity Technologies Ltd","description":"A skeleton dapp","iconUrl":"title.png","id":"skeleton","localUrl":null,"name":"Skeleton","version":"0.1"}],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32000,"message":"Dapps Server is disabled. This API is not available."},"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); } diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 1b9a7d09f5b..56634cc158c 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -162,6 +162,7 @@ build_rpc_trait! { fn local_transactions(&self) -> Result>; /// Returns current Dapps Server interface and port or an error if dapps server is disabled. + /// (deprecated, should always return an error now). #[rpc(name = "parity_dappsUrl")] fn dapps_url(&self) -> Result; diff --git a/rpc/src/v1/traits/parity_set.rs b/rpc/src/v1/traits/parity_set.rs index 8cfffb50c7c..dfd0ad5541f 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -95,11 +95,12 @@ build_rpc_trait! { #[rpc(name = "parity_hashContent")] fn hash_content(&self, String) -> BoxFuture; - /// Returns true if refresh successful, error if unsuccessful or server is disabled. + /// Returns true if refresh successful, error if unsuccessful or server is disabled + /// (deprecated, should always return an error now). #[rpc(name = "parity_dappsRefresh")] fn dapps_refresh(&self) -> Result; - /// Returns a list of local dapps + /// Returns a list of local dapps (deprecated, should always return an error now). #[rpc(name = "parity_dappsList")] fn dapps_list(&self) -> Result>; diff --git a/util/dir/src/lib.rs b/util/dir/src/lib.rs index 712b53f0de3..88792fe8a61 100644 --- a/util/dir/src/lib.rs +++ b/util/dir/src/lib.rs @@ -61,8 +61,6 @@ pub struct Directories { pub keys: String, /// Signer dir pub signer: String, - /// Dir to store dapps - pub dapps: String, /// Secrets dir pub secretstore: String, } @@ -77,7 +75,6 @@ impl Default for Directories { cache: replace_home_and_local(&data_dir, &local_dir, CACHE_PATH), keys: replace_home(&data_dir, "$BASE/keys"), signer: replace_home(&data_dir, "$BASE/signer"), - dapps: replace_home(&data_dir, "$BASE/dapps"), secretstore: replace_home(&data_dir, "$BASE/secretstore"), } } @@ -85,7 +82,7 @@ impl Default for Directories { impl Directories { /// Create local directories - pub fn create_dirs(&self, dapps_enabled: bool, signer_enabled: bool, secretstore_enabled: bool) -> Result<(), String> { + pub fn create_dirs(&self, signer_enabled: bool, secretstore_enabled: bool) -> Result<(), String> { fs::create_dir_all(&self.base).map_err(|e| e.to_string())?; fs::create_dir_all(&self.db).map_err(|e| e.to_string())?; fs::create_dir_all(&self.cache).map_err(|e| e.to_string())?; @@ -93,9 +90,6 @@ impl Directories { if signer_enabled { fs::create_dir_all(&self.signer).map_err(|e| e.to_string())?; } - if dapps_enabled { - fs::create_dir_all(&self.dapps).map_err(|e| e.to_string())?; - } if secretstore_enabled { fs::create_dir_all(&self.secretstore).map_err(|e| e.to_string())?; } @@ -356,7 +350,6 @@ mod tests { ), keys: replace_home(&data_dir, "$BASE/keys"), signer: replace_home(&data_dir, "$BASE/signer"), - dapps: replace_home(&data_dir, "$BASE/dapps"), secretstore: replace_home(&data_dir, "$BASE/secretstore"), }; assert_eq!(expected, Directories::default());