Remove UI related settings from CLI (#8783)

* Remove all ui reference in dapps interface

* Pass primary cli build

* Add back parity wallet dapp as builtin

* Clean up ui settings

* Fix all tests in cli

* Missed ui files to commit

* Add parity-utils endpoint back

* Fix non-dapp feature compiling

* Inline styles

* Remove parity-utils endpoint

* Remove ui precompiled crate

* Remove parity-ui alltogether

* Remove ui feature flags

* Move errors to static methods

* Fix tests

* Remove all reference to utils endpoint and remove server side injection

According to https://github.com/paritytech/parity/pull/8539, inject.js is already handled by Parity UI.
This commit is contained in:
Wei Tang 2018-06-06 16:05:52 +08:00 committed by Marek Kotewicz
parent 114d4433a9
commit a5190449da
42 changed files with 306 additions and 1639 deletions

56
Cargo.lock generated
View File

@ -2071,8 +2071,6 @@ dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-hash-fetch 1.12.0", "parity-hash-fetch 1.12.0",
"parity-reactor 0.1.0", "parity-reactor 0.1.0",
"parity-ui 1.12.0",
"parity-ui-deprecation 1.10.0",
"parity-version 1.12.0", "parity-version 1.12.0",
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2283,56 +2281,6 @@ dependencies = [
"tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "parity-ui"
version = "1.12.0"
dependencies = [
"parity-ui-dev 1.9.0 (git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2)",
"parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)",
"parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6)",
"parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079)",
"rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-ui-deprecation"
version = "1.10.0"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-ui-dev"
version = "1.9.0"
source = "git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2#eecaadcb9e421bce31e91680d14a20bbd38f92a2"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-ui-old-dev"
version = "1.9.0"
source = "git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87#65deb02e7c007a0fd8aab0c089c93e3fd1de6f87"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-ui-old-precompiled"
version = "1.9.0"
source = "git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6#4b6f112412716cd05123d32eeb7fda448288a6c6"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parity-ui-precompiled"
version = "1.9.0"
source = "git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079#bd25b41cd642c6b822d820dded3aa601a29aa079"
dependencies = [
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "parity-updater" name = "parity-updater"
version = "1.12.0" version = "1.12.0"
@ -3970,10 +3918,6 @@ dependencies = [
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
"checksum parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "261c025c67ba416e9fe63aa9b3236520ce3c74cfbe43590c9cdcec4ccc8180e4" "checksum parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "261c025c67ba416e9fe63aa9b3236520ce3c74cfbe43590c9cdcec4ccc8180e4"
"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>" "checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "<none>"
"checksum parity-ui-dev 1.9.0 (git+https://github.com/parity-js/shell.git?rev=eecaadcb9e421bce31e91680d14a20bbd38f92a2)" = "<none>"
"checksum parity-ui-old-dev 1.9.0 (git+https://github.com/parity-js/dapp-wallet.git?rev=65deb02e7c007a0fd8aab0c089c93e3fd1de6f87)" = "<none>"
"checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git?rev=4b6f112412716cd05123d32eeb7fda448288a6c6)" = "<none>"
"checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-10-shell.git?rev=bd25b41cd642c6b822d820dded3aa601a29aa079)" = "<none>"
"checksum parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a93ad771f67ce8a6af64c6444a99c07b15f4674203657496fc31244ffb1de2c3" "checksum parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a93ad771f67ce8a6af64c6444a99c07b15f4674203657496fc31244ffb1de2c3"
"checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693" "checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693"
"checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" "checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd"

View File

@ -88,16 +88,7 @@ winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] }
daemonize = { git = "https://github.com/paritytech/daemonize" } daemonize = { git = "https://github.com/paritytech/daemonize" }
[features] [features]
default = ["ui-precompiled"] default = ["dapps"]
ui = [
"ui-enabled",
"parity-dapps/ui",
]
ui-precompiled = [
"ui-enabled",
"parity-dapps/ui-precompiled",
]
ui-enabled = ["dapps"]
dapps = ["parity-dapps"] dapps = ["parity-dapps"]
json-tests = ["ethcore/json-tests"] json-tests = ["ethcore/json-tests"]
test-heavy = ["ethcore/test-heavy"] test-heavy = ["ethcore/test-heavy"]

View File

@ -34,8 +34,6 @@ fetch = { path = "../util/fetch" }
node-health = { path = "./node-health" } node-health = { path = "./node-health" }
parity-hash-fetch = { path = "../hash-fetch" } parity-hash-fetch = { path = "../hash-fetch" }
parity-reactor = { path = "../util/reactor" } parity-reactor = { path = "../util/reactor" }
parity-ui = { path = "./ui" }
parity-ui-deprecation = { path = "./ui-deprecation" }
keccak-hash = { path = "../util/hash" } keccak-hash = { path = "../util/hash" }
parity-version = { path = "../util/version" } parity-version = { path = "../util/version" }
registrar = { path = "../registrar" } registrar = { path = "../registrar" }
@ -43,7 +41,3 @@ registrar = { path = "../registrar" }
[dev-dependencies] [dev-dependencies]
env_logger = "0.4" env_logger = "0.4"
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
[features]
ui = ["parity-ui/no-precompiled-js"]
ui-precompiled = ["parity-ui/use-precompiled-js"]

View File

@ -27,7 +27,6 @@ use mime_guess::Mime;
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest}; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest};
use handlers::{ContentValidator, ValidatorResponse}; use handlers::{ContentValidator, ValidatorResponse};
use page::{local, PageCache}; use page::{local, PageCache};
use Embeddable;
type OnDone = Box<Fn(Option<local::Dapp>) + Send>; type OnDone = Box<Fn(Option<local::Dapp>) + Send>;
@ -124,17 +123,15 @@ pub struct Dapp {
id: String, id: String,
dapps_path: PathBuf, dapps_path: PathBuf,
on_done: OnDone, on_done: OnDone,
embeddable_on: Embeddable,
pool: CpuPool, pool: CpuPool,
} }
impl Dapp { impl Dapp {
pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, embeddable_on: Embeddable, pool: CpuPool) -> Self { pub fn new(id: String, dapps_path: PathBuf, on_done: OnDone, pool: CpuPool) -> Self {
Dapp { Dapp {
id, id,
dapps_path, dapps_path,
on_done, on_done,
embeddable_on,
pool, pool,
} }
} }
@ -170,7 +167,6 @@ impl ContentValidator for Dapp {
fn validate_and_install(self, response: fetch::Response) -> Result<ValidatorResponse, ValidationError> { fn validate_and_install(self, response: fetch::Response) -> Result<ValidatorResponse, ValidationError> {
let id = self.id.clone(); let id = self.id.clone();
let pool = self.pool; let pool = self.pool;
let embeddable_on = self.embeddable_on;
let validate = move |dapp_path: PathBuf| { let validate = move |dapp_path: PathBuf| {
let (file, zip_path) = write_response_and_check_hash(&id, dapp_path.clone(), &format!("{}.zip", id), response)?; 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); trace!(target: "dapps", "Opening dapp bundle at {:?}", zip_path);
@ -210,7 +206,7 @@ impl ContentValidator for Dapp {
let mut manifest_file = fs::File::create(manifest_path)?; let mut manifest_file = fs::File::create(manifest_path)?;
manifest_file.write_all(manifest_str.as_bytes())?; manifest_file.write_all(manifest_str.as_bytes())?;
// Create endpoint // Create endpoint
let endpoint = local::Dapp::new(pool, dapp_path, manifest.into(), PageCache::Enabled, embeddable_on); let endpoint = local::Dapp::new(pool, dapp_path, manifest.into(), PageCache::Enabled);
Ok(endpoint) Ok(endpoint)
}; };

View File

@ -31,7 +31,7 @@ use hash_fetch::urlhint::{URLHintContract, URLHint, URLHintResult};
use hyper::StatusCode; use hyper::StatusCode;
use ethereum_types::H256; use ethereum_types::H256;
use {Embeddable, SyncStatus, random_filename}; use {SyncStatus, random_filename};
use parking_lot::Mutex; use parking_lot::Mutex;
use page::local; use page::local;
use handlers::{ContentHandler, ContentFetcherHandler}; use handlers::{ContentHandler, ContentFetcherHandler};
@ -50,7 +50,6 @@ pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + 'static = URLHint
resolver: R, resolver: R,
cache: Arc<Mutex<ContentCache>>, cache: Arc<Mutex<ContentCache>>,
sync: Arc<SyncStatus>, sync: Arc<SyncStatus>,
embeddable_on: Embeddable,
fetch: F, fetch: F,
pool: CpuPool, pool: CpuPool,
only_content: bool, only_content: bool,
@ -78,7 +77,6 @@ impl<R: URLHint + 'static, F: Fetch> ContentFetcher<F, R> {
resolver, resolver,
sync, sync,
cache: Arc::new(Mutex::new(ContentCache::default())), cache: Arc::new(Mutex::new(ContentCache::default())),
embeddable_on: None,
fetch, fetch,
pool, pool,
only_content: true, only_content: true,
@ -90,38 +88,30 @@ impl<R: URLHint + 'static, F: Fetch> ContentFetcher<F, R> {
self self
} }
pub fn embeddable_on(mut self, embeddable_on: Embeddable) -> Self { fn not_found() -> endpoint::Response {
self.embeddable_on = embeddable_on;
self
}
fn not_found(embeddable: Embeddable) -> endpoint::Response {
Box::new(future::ok(ContentHandler::error( Box::new(future::ok(ContentHandler::error(
StatusCode::NotFound, StatusCode::NotFound,
"Resource Not Found", "Resource Not Found",
"Requested resource was not found.", "Requested resource was not found.",
None, None,
embeddable,
).into())) ).into()))
} }
fn still_syncing(embeddable: Embeddable) -> endpoint::Response { fn still_syncing() -> endpoint::Response {
Box::new(future::ok(ContentHandler::error( Box::new(future::ok(ContentHandler::error(
StatusCode::ServiceUnavailable, StatusCode::ServiceUnavailable,
"Sync In Progress", "Sync In Progress",
"Your node is still syncing. We cannot resolve any content before it's fully synced.", "Your node is still syncing. We cannot resolve any content before it's fully synced.",
Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"), Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"),
embeddable,
).into())) ).into()))
} }
fn dapps_disabled(address: Embeddable) -> endpoint::Response { fn dapps_disabled() -> endpoint::Response {
Box::new(future::ok(ContentHandler::error( Box::new(future::ok(ContentHandler::error(
StatusCode::ServiceUnavailable, StatusCode::ServiceUnavailable,
"Network Dapps Not Available", "Network Dapps Not Available",
"This interface doesn't support network dapps for security reasons.", "This interface doesn't support network dapps for security reasons.",
None, None,
address,
).into())) ).into()))
} }
@ -195,10 +185,10 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
match content { match content {
// Don't serve dapps if we are still syncing (but serve content) // Don't serve dapps if we are still syncing (but serve content)
Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => { Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => {
(None, Self::still_syncing(self.embeddable_on.clone())) (None, Self::still_syncing())
}, },
Some(URLHintResult::Dapp(_)) if self.only_content => { Some(URLHintResult::Dapp(_)) if self.only_content => {
(None, Self::dapps_disabled(self.embeddable_on.clone())) (None, Self::dapps_disabled())
}, },
Some(content) => { Some(content) => {
let handler = match content { let handler = match content {
@ -211,10 +201,8 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
content_id.clone(), content_id.clone(),
self.cache_path.clone(), self.cache_path.clone(),
Box::new(on_done), Box::new(on_done),
self.embeddable_on.clone(),
self.pool.clone(), self.pool.clone(),
), ),
self.embeddable_on.clone(),
self.fetch.clone(), self.fetch.clone(),
self.pool.clone(), self.pool.clone(),
) )
@ -228,10 +216,8 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
content_id.clone(), content_id.clone(),
self.cache_path.clone(), self.cache_path.clone(),
Box::new(on_done), Box::new(on_done),
self.embeddable_on.clone(),
self.pool.clone(), self.pool.clone(),
), ),
self.embeddable_on.clone(),
self.fetch.clone(), self.fetch.clone(),
self.pool.clone(), self.pool.clone(),
) )
@ -248,7 +234,6 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
Box::new(on_done), Box::new(on_done),
self.pool.clone(), self.pool.clone(),
), ),
self.embeddable_on.clone(),
self.fetch.clone(), self.fetch.clone(),
self.pool.clone(), self.pool.clone(),
) )
@ -258,12 +243,12 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
(Some(ContentStatus::Fetching(handler.fetch_control())), Box::new(handler) as endpoint::Response) (Some(ContentStatus::Fetching(handler.fetch_control())), Box::new(handler) as endpoint::Response)
}, },
None if self.sync.is_major_importing() => { None if self.sync.is_major_importing() => {
(None, Self::still_syncing(self.embeddable_on.clone())) (None, Self::still_syncing())
}, },
None => { None => {
// This may happen when sync status changes in between // This may happen when sync status changes in between
// `contains` and `to_handler` // `contains` and `to_handler`
(None, Self::not_found(self.embeddable_on.clone())) (None, Self::not_found())
}, },
} }
}, },
@ -330,7 +315,7 @@ mod tests {
icon_url: "".into(), icon_url: "".into(),
local_url: Some("".into()), local_url: Some("".into()),
allow_js_eval: None, allow_js_eval: None,
}, Default::default(), None); }, Default::default());
// when // when
fetcher.set_status("test", ContentStatus::Ready(handler)); fetcher.set_status("test", ContentStatus::Ready(handler));

View File

@ -24,7 +24,6 @@ use futures_cpupool::CpuPool;
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest}; use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest};
use endpoint::{Endpoint, EndpointInfo}; use endpoint::{Endpoint, EndpointInfo};
use page::{local, PageCache}; use page::{local, PageCache};
use Embeddable;
struct LocalDapp { struct LocalDapp {
id: String, id: String,
@ -65,14 +64,14 @@ fn read_manifest(name: &str, mut path: PathBuf) -> EndpointInfo {
/// Returns Dapp Id and Local Dapp Endpoint for given filesystem path. /// Returns Dapp Id and Local Dapp Endpoint for given filesystem path.
/// Parses the path to extract last component (for name). /// Parses the path to extract last component (for name).
/// `None` is returned when path is invalid or non-existent. /// `None` is returned when path is invalid or non-existent.
pub fn local_endpoint<P: AsRef<Path>>(path: P, embeddable: Embeddable, pool: CpuPool) -> Option<(String, Box<local::Dapp>)> { pub fn local_endpoint<P: AsRef<Path>>(path: P, pool: CpuPool) -> Option<(String, Box<local::Dapp>)> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
path.canonicalize().ok().and_then(|path| { path.canonicalize().ok().and_then(|path| {
let name = path.file_name().and_then(|name| name.to_str()); let name = path.file_name().and_then(|name| name.to_str());
name.map(|name| { name.map(|name| {
let dapp = local_dapp(name.into(), path.clone()); let dapp = local_dapp(name.into(), path.clone());
(dapp.id, Box::new(local::Dapp::new( (dapp.id, Box::new(local::Dapp::new(
pool.clone(), dapp.path, dapp.info, PageCache::Disabled, embeddable.clone()) pool.clone(), dapp.path, dapp.info, PageCache::Disabled)
)) ))
}) })
}) })
@ -90,12 +89,12 @@ fn local_dapp(name: String, path: PathBuf) -> LocalDapp {
/// Returns endpoints for Local Dapps found for given filesystem path. /// Returns endpoints for Local Dapps found for given filesystem path.
/// Scans the directory and collects `local::Dapp`. /// Scans the directory and collects `local::Dapp`.
pub fn local_endpoints<P: AsRef<Path>>(dapps_path: P, embeddable: Embeddable, pool: CpuPool) -> BTreeMap<String, Box<Endpoint>> { pub fn local_endpoints<P: AsRef<Path>>(dapps_path: P, pool: CpuPool) -> BTreeMap<String, Box<Endpoint>> {
let mut pages = BTreeMap::<String, Box<Endpoint>>::new(); let mut pages = BTreeMap::<String, Box<Endpoint>>::new();
for dapp in local_dapps(dapps_path.as_ref()) { for dapp in local_dapps(dapps_path.as_ref()) {
pages.insert( pages.insert(
dapp.id, dapp.id,
Box::new(local::Dapp::new(pool.clone(), dapp.path, dapp.info, PageCache::Disabled, embeddable.clone())) Box::new(local::Dapp::new(pool.clone(), dapp.path, dapp.info, PageCache::Disabled))
); );
} }
pages pages

View File

@ -17,17 +17,15 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use endpoint::{Endpoints, Endpoint}; use endpoint::Endpoints;
use futures_cpupool::CpuPool; use futures_cpupool::CpuPool;
use page;
use proxypac::ProxyPac; use proxypac::ProxyPac;
use web::Web; use web::Web;
use fetch::Fetch; use fetch::Fetch;
use {WebProxyTokens, ParentFrameSettings}; use WebProxyTokens;
mod app; mod app;
mod cache; mod cache;
mod ui;
pub mod fs; pub mod fs;
pub mod fetcher; pub mod fetcher;
pub mod manifest; pub mod manifest;
@ -35,70 +33,37 @@ pub mod manifest;
pub use self::app::App; pub use self::app::App;
pub const HOME_PAGE: &'static str = "home"; pub const HOME_PAGE: &'static str = "home";
pub const RPC_PATH: &'static str = "rpc"; pub const RPC_PATH: &'static str = "rpc";
pub const API_PATH: &'static str = "api"; pub const API_PATH: &'static str = "api";
pub const UTILS_PATH: &'static str = "parity-utils";
pub const WEB_PATH: &'static str = "web"; pub const WEB_PATH: &'static str = "web";
pub const URL_REFERER: &'static str = "__referer="; pub const URL_REFERER: &'static str = "__referer=";
pub fn utils(pool: CpuPool) -> Box<Endpoint> {
Box::new(page::builtin::Dapp::new(pool, ::parity_ui::App::default()))
}
pub fn ui(pool: CpuPool) -> Box<Endpoint> {
Box::new(page::builtin::Dapp::with_fallback_to_index(pool, ::parity_ui::App::default()))
}
pub fn ui_deprecation(pool: CpuPool) -> Box<Endpoint> {
Box::new(page::builtin::Dapp::with_fallback_to_index(pool, ::parity_ui_deprecation::App::default()))
}
pub fn ui_redirection(embeddable: Option<ParentFrameSettings>) -> Box<Endpoint> {
Box::new(ui::Redirection::new(embeddable))
}
pub fn all_endpoints<F: Fetch>( pub fn all_endpoints<F: Fetch>(
dapps_path: PathBuf, dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>, extra_dapps: Vec<PathBuf>,
dapps_domain: &str, dapps_domain: &str,
embeddable: Option<ParentFrameSettings>,
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
fetch: F, fetch: F,
pool: CpuPool, pool: CpuPool,
) -> (Vec<String>, Endpoints) { ) -> (Vec<String>, Endpoints) {
// fetch fs dapps at first to avoid overwriting builtins // fetch fs dapps at first to avoid overwriting builtins
let mut pages = fs::local_endpoints(dapps_path.clone(), embeddable.clone(), pool.clone()); let mut pages = fs::local_endpoints(dapps_path.clone(), pool.clone());
let local_endpoints: Vec<String> = pages.keys().cloned().collect(); let local_endpoints: Vec<String> = pages.keys().cloned().collect();
for path in extra_dapps { for path in extra_dapps {
if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), embeddable.clone(), pool.clone()) { if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), pool.clone()) {
pages.insert(id, endpoint); pages.insert(id, endpoint);
} else { } else {
warn!(target: "dapps", "Ignoring invalid dapp at {}", path.display()); warn!(target: "dapps", "Ignoring invalid dapp at {}", path.display());
} }
} }
// NOTE [ToDr] Dapps will be currently embeded on 8180
pages.insert(
"ui".into(),
Box::new(page::builtin::Dapp::new_safe_to_embed(pool.clone(), ::parity_ui::App::default(), embeddable.clone()))
);
// old version
pages.insert(
"v1".into(),
Box::new({
let mut page = page::builtin::Dapp::new_safe_to_embed(pool.clone(), ::parity_ui::old::App::default(), embeddable.clone());
// allow JS eval on old Wallet
page.allow_js_eval();
page
})
);
pages.insert( pages.insert(
"proxy".into(), "proxy".into(),
ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned()) ProxyPac::boxed(dapps_domain.to_owned())
); );
pages.insert( pages.insert(
WEB_PATH.into(), WEB_PATH.into(),
Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), fetch.clone(), pool.clone()) Web::boxed(web_proxy_tokens.clone(), fetch.clone(), pool.clone())
); );
(local_endpoints, pages) (local_endpoints, pages)

View File

@ -1,57 +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://www.gnu.org/licenses/>.
//! UI redirections
use hyper::StatusCode;
use futures::future;
use endpoint::{Endpoint, Request, Response, EndpointPath};
use {handlers, Embeddable};
/// Redirection to UI server.
pub struct Redirection {
embeddable_on: Embeddable,
}
impl Redirection {
pub fn new(
embeddable_on: Embeddable,
) -> Self {
Redirection {
embeddable_on,
}
}
}
impl Endpoint for Redirection {
fn respond(&self, _path: EndpointPath, req: Request) -> Response {
Box::new(future::ok(if let Some(ref frame) = self.embeddable_on {
trace!(target: "dapps", "Redirecting to signer interface.");
let protocol = req.uri().scheme().unwrap_or("http");
handlers::Redirection::new(format!("{}://{}:{}", protocol, &frame.host, frame.port)).into()
} else {
trace!(target: "dapps", "Signer disabled, returning 404.");
handlers::ContentHandler::error(
StatusCode::NotFound,
"404 Not Found",
"Your homepage is not available when Trusted Signer is disabled.",
Some("You can still access dapps by writing a correct address, though. Re-enable Signer to get your homepage back."),
None,
).into()
}))
}
}

View File

@ -4,7 +4,88 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<title>{title}</title> <title>{title}</title>
<link rel="stylesheet" href="/parity-utils/styles.css"> <style>
:root, :root body {{
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
background: rgb(95, 95, 95);
color: rgba(255, 255, 255, 0.75);
font-size: 16px;
font-family: sans-serif;
font-weight: 300;
}}
:root a, :root a:visited {{
text-decoration: none;
cursor: pointer;
color: rgb(0, 151, 167); /* #f80 */
}}
:root a:hover {{
color: rgb(0, 174, 193);
}}
h1,h2,h3,h4,h5,h6 {{
font-weight: 300;
text-transform: uppercase;
text-decoration: none;
}}
h1 {{
font-size: 24px;
line-height: 36px;
color: rgb(0, 151, 167);
}}
h2 {{
font-size: 20px;
line-height: 34px;
}}
code,kbd,pre,samp {{
font-family: monospace;
}}
.parity-navbar {{
background: rgb(65, 65, 65);
height: 72px;
padding: 0 1rem;
display: flex;
justify-content: space-between;
}}
.parity-status {{
clear: both;
padding: 1rem;
margin: 1rem 0;
text-align: right;
opacity: 0.75;
}}
.parity-box {{
margin: 1rem;
padding: 1rem;
background-color: rgb(48, 48, 48);
box-sizing: border-box;
box-shadow: rgba(0, 0, 0, 0.117647) 0px 1px 6px, rgba(0, 0, 0, 0.117647) 0px 1px 4px;
border-radius: 2px;
z-index: 1;
color: #aaa;
}}
.parity-box h1,
.parity-box h2,
.parity-box h3,
.parity-box h4,
.parity-box h5,
.parity-box h6 {{
margin: 0;
}}
</style>
</head> </head>
<body> <body>
<div class="parity-navbar"> <div class="parity-navbar">

View File

@ -22,14 +22,12 @@ use hyper::StatusCode;
use parity_version::version; use parity_version::version;
use handlers::add_security_headers; use handlers::add_security_headers;
use Embeddable;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ContentHandler { pub struct ContentHandler {
code: StatusCode, code: StatusCode,
content: String, content: String,
mimetype: mime::Mime, mimetype: mime::Mime,
safe_to_embed_on: Embeddable,
} }
impl ContentHandler { impl ContentHandler {
@ -37,8 +35,8 @@ impl ContentHandler {
Self::new(StatusCode::Ok, content, mimetype) Self::new(StatusCode::Ok, content, mimetype)
} }
pub fn html(code: StatusCode, content: String, embeddable_on: Embeddable) -> Self { pub fn html(code: StatusCode, content: String) -> Self {
Self::new_embeddable(code, content, mime::TEXT_HTML, embeddable_on) Self::new(code, content, mime::TEXT_HTML)
} }
pub fn error( pub fn error(
@ -46,7 +44,6 @@ impl ContentHandler {
title: &str, title: &str,
message: &str, message: &str,
details: Option<&str>, details: Option<&str>,
embeddable_on: Embeddable,
) -> Self { ) -> Self {
Self::html(code, format!( Self::html(code, format!(
include_str!("../error_tpl.html"), include_str!("../error_tpl.html"),
@ -54,24 +51,18 @@ impl ContentHandler {
message=message, message=message,
details=details.unwrap_or_else(|| ""), details=details.unwrap_or_else(|| ""),
version=version(), version=version(),
), embeddable_on) ))
} }
pub fn new(code: StatusCode, content: String, mimetype: mime::Mime) -> Self { pub fn new(
Self::new_embeddable(code, content, mimetype, None)
}
pub fn new_embeddable(
code: StatusCode, code: StatusCode,
content: String, content: String,
mimetype: mime::Mime, mimetype: mime::Mime,
safe_to_embed_on: Embeddable,
) -> Self { ) -> Self {
ContentHandler { ContentHandler {
code, code,
content, content,
mimetype, mimetype,
safe_to_embed_on,
} }
} }
} }
@ -82,7 +73,7 @@ impl Into<hyper::Response> for ContentHandler {
.with_status(self.code) .with_status(self.code)
.with_header(header::ContentType(self.mimetype)) .with_header(header::ContentType(self.mimetype))
.with_body(self.content); .with_body(self.content);
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on, false); add_security_headers(&mut res.headers_mut(), false);
res res
} }
} }

View File

@ -40,7 +40,7 @@ impl Into<hyper::Response> for EchoHandler {
.with_header(content_type.unwrap_or(header::ContentType::json())) .with_header(content_type.unwrap_or(header::ContentType::json()))
.with_body(self.request.body()); .with_body(self.request.body());
add_security_headers(res.headers_mut(), None, false); add_security_headers(res.headers_mut(), false);
res res
} }
} }

View File

@ -0,0 +1,66 @@
// 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://www.gnu.org/licenses/>.
//! 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: fmt::Debug>(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: fmt::Debug>(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 <code>GET</code> requests are allowed.",
None,
)
}

View File

@ -19,20 +19,17 @@
use std::{fmt, mem}; use std::{fmt, mem};
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Instant, Duration}; use std::time::Instant;
use fetch::{self, Fetch}; use fetch::{self, Fetch};
use futures::sync::oneshot; use futures::sync::oneshot;
use futures::{self, Future}; use futures::{self, Future};
use futures_cpupool::CpuPool; use futures_cpupool::CpuPool;
use hyper::{self, StatusCode}; use hyper;
use parking_lot::Mutex; use parking_lot::Mutex;
use endpoint::{self, EndpointPath}; use endpoint::{self, EndpointPath};
use handlers::{ContentHandler, StreamingHandler}; use handlers::{ContentHandler, StreamingHandler, FETCH_TIMEOUT, errors};
use page::local; use page::local;
use {Embeddable};
const FETCH_TIMEOUT: Duration = Duration::from_secs(300);
pub enum ValidatorResponse { pub enum ValidatorResponse {
Local(local::Dapp), Local(local::Dapp),
@ -134,8 +131,7 @@ impl Future for WaitingHandler {
return Ok(futures::Async::Ready(handler.into())); return Ok(futures::Async::Ready(handler.into()));
}, },
WaitResult::NonAwaitable => { WaitResult::NonAwaitable => {
let errors = Errors { embeddable_on: None }; return Ok(futures::Async::Ready(errors::streaming().into()));
return Ok(futures::Async::Ready(errors.streaming().into()));
}, },
WaitResult::Done(endpoint) => { WaitResult::Done(endpoint) => {
WaitState::Done(endpoint.to_response(&self.path).into()) WaitState::Done(endpoint.to_response(&self.path).into())
@ -152,63 +148,6 @@ impl Future for WaitingHandler {
} }
} }
#[derive(Debug, Clone)]
struct Errors {
embeddable_on: Embeddable,
}
impl Errors {
fn streaming(&self) -> ContentHandler {
ContentHandler::error(
StatusCode::BadGateway,
"Streaming Error",
"This content is being streamed in other place.",
None,
self.embeddable_on.clone(),
)
}
fn download_error<E: fmt::Debug>(&self, e: E) -> ContentHandler {
ContentHandler::error(
StatusCode::BadGateway,
"Download Error",
"There was an error when fetching the content.",
Some(&format!("{:?}", e)),
self.embeddable_on.clone(),
)
}
fn invalid_content<E: fmt::Debug>(&self, e: E) -> ContentHandler {
ContentHandler::error(
StatusCode::BadGateway,
"Invalid Dapp",
"Downloaded bundle does not contain a valid content.",
Some(&format!("{:?}", e)),
self.embeddable_on.clone(),
)
}
fn timeout_error(&self) -> ContentHandler {
ContentHandler::error(
StatusCode::GatewayTimeout,
"Download Timeout",
&format!("Could not fetch content within {} seconds.", FETCH_TIMEOUT.as_secs()),
None,
self.embeddable_on.clone(),
)
}
fn method_not_allowed(&self) -> ContentHandler {
ContentHandler::error(
StatusCode::MethodNotAllowed,
"Method Not Allowed",
"Only <code>GET</code> requests are allowed.",
None,
self.embeddable_on.clone(),
)
}
}
enum FetchState { enum FetchState {
Error(ContentHandler), Error(ContentHandler),
InProgress(Box<Future<Item=FetchState, Error=()> + Send>), InProgress(Box<Future<Item=FetchState, Error=()> + Send>),
@ -237,7 +176,6 @@ impl fmt::Debug for FetchState {
pub struct ContentFetcherHandler { pub struct ContentFetcherHandler {
fetch_control: FetchControl, fetch_control: FetchControl,
status: FetchState, status: FetchState,
errors: Errors,
} }
impl ContentFetcherHandler { impl ContentFetcherHandler {
@ -250,12 +188,10 @@ impl ContentFetcherHandler {
url: &str, url: &str,
path: EndpointPath, path: EndpointPath,
installer: H, installer: H,
embeddable_on: Embeddable,
fetch: F, fetch: F,
pool: CpuPool, pool: CpuPool,
) -> Self { ) -> Self {
let fetch_control = FetchControl::default(); let fetch_control = FetchControl::default();
let errors = Errors { embeddable_on };
// Validation of method // Validation of method
let status = match *method { let status = match *method {
@ -268,18 +204,16 @@ impl ContentFetcherHandler {
url, url,
fetch_control.abort.clone(), fetch_control.abort.clone(),
path, path,
errors.clone(),
installer, installer,
)) ))
}, },
// or return error // or return error
_ => FetchState::Error(errors.method_not_allowed()), _ => FetchState::Error(errors::method_not_allowed()),
}; };
ContentFetcherHandler { ContentFetcherHandler {
fetch_control, fetch_control,
status, status,
errors,
} }
} }
@ -289,7 +223,6 @@ impl ContentFetcherHandler {
url: &str, url: &str,
abort: Arc<AtomicBool>, abort: Arc<AtomicBool>,
path: EndpointPath, path: EndpointPath,
errors: Errors,
installer: H, installer: H,
) -> Box<Future<Item=FetchState, Error=()> + Send> { ) -> Box<Future<Item=FetchState, Error=()> + Send> {
// Start fetching the content // Start fetching the content
@ -311,12 +244,12 @@ impl ContentFetcherHandler {
}, },
Err(e) => { Err(e) => {
trace!(target: "dapps", "Error while validating content: {:?}", e); trace!(target: "dapps", "Error while validating content: {:?}", e);
FetchState::Error(errors.invalid_content(e)) FetchState::Error(errors::invalid_content(e))
}, },
}, },
Err(e) => { Err(e) => {
warn!(target: "dapps", "Unable to fetch content: {:?}", e); warn!(target: "dapps", "Unable to fetch content: {:?}", e);
FetchState::Error(errors.download_error(e)) FetchState::Error(errors::download_error(e))
}, },
}) })
}); });
@ -347,7 +280,7 @@ impl Future for ContentFetcherHandler {
// Request may time out // Request may time out
FetchState::InProgress(_) if self.fetch_control.is_deadline_reached() => { FetchState::InProgress(_) if self.fetch_control.is_deadline_reached() => {
trace!(target: "dapps", "Fetching dapp failed because of timeout."); trace!(target: "dapps", "Fetching dapp failed because of timeout.");
FetchState::Error(self.errors.timeout_error()) FetchState::Error(errors::timeout_error())
}, },
FetchState::InProgress(ref mut receiver) => { FetchState::InProgress(ref mut receiver) => {
// Check if there is a response // Check if there is a response

View File

@ -22,6 +22,7 @@ mod fetch;
mod reader; mod reader;
mod redirect; mod redirect;
mod streaming; mod streaming;
mod errors;
pub use self::content::ContentHandler; pub use self::content::ContentHandler;
pub use self::echo::EchoHandler; pub use self::echo::EchoHandler;
@ -30,20 +31,16 @@ pub use self::reader::Reader;
pub use self::redirect::Redirection; pub use self::redirect::Redirection;
pub use self::streaming::StreamingHandler; pub use self::streaming::StreamingHandler;
use std::iter;
use itertools::Itertools;
use hyper::header; use hyper::header;
use {apps, address, Embeddable}; use std::time::Duration;
const FETCH_TIMEOUT: Duration = Duration::from_secs(300);
/// Adds security-related headers to the Response. /// Adds security-related headers to the Response.
pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embeddable, allow_js_eval: bool) { 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-XSS-Protection", "1; mode=block");
headers.set_raw("X-Content-Type-Options", "nosniff"); headers.set_raw("X-Content-Type-Options", "nosniff");
headers.set_raw("X-Frame-Options", "SAMEORIGIN");
// Embedding header:
if let None = embeddable_on {
headers.set_raw("X-Frame-Options", "SAMEORIGIN");
}
// Content Security Policy headers // Content Security Policy headers
headers.set_raw("Content-Security-Policy", String::new() headers.set_raw("Content-Security-Policy", String::new()
@ -70,11 +67,7 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
+ "object-src 'none';" + "object-src 'none';"
// Allow scripts // Allow scripts
+ { + {
let script_src = embeddable_on.as_ref() let script_src = "";
.map(|e| e.extra_script_src.iter()
.map(|&(ref host, port)| address(host, port))
.join(" ")
).unwrap_or_default();
let eval = if allow_js_eval { " 'unsafe-eval'" } else { "" }; let eval = if allow_js_eval { " 'unsafe-eval'" } else { "" };
&format!( &format!(
@ -93,29 +86,6 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
// Never allow mixed content // Never allow mixed content
+ "block-all-mixed-content;" + "block-all-mixed-content;"
// Specify if the site can be embedded. // Specify if the site can be embedded.
+ &match embeddable_on { + "frame-ancestors 'self';"
Some(ref embed) => {
let std = address(&embed.host, embed.port);
let proxy = format!("{}.{}", apps::HOME_PAGE, embed.dapps_domain);
let domain = format!("*.{}:{}", embed.dapps_domain, embed.port);
let mut ancestors = vec![std, domain, proxy]
.into_iter()
.chain(embed.extra_embed_on
.iter()
.map(|&(ref host, port)| address(host, port))
);
let ancestors = if embed.host == "127.0.0.1" {
let localhost = address("localhost", embed.port);
ancestors.chain(iter::once(localhost)).join(" ")
} else {
ancestors.join(" ")
};
format!("frame-ancestors {};", ancestors)
},
None => format!("frame-ancestors 'self';"),
}
); );
} }

View File

@ -20,24 +20,21 @@ use std::io;
use hyper::{self, header, mime, StatusCode}; use hyper::{self, header, mime, StatusCode};
use handlers::{add_security_headers, Reader}; use handlers::{add_security_headers, Reader};
use Embeddable;
pub struct StreamingHandler<R> { pub struct StreamingHandler<R> {
initial: Vec<u8>, initial: Vec<u8>,
content: R, content: R,
status: StatusCode, status: StatusCode,
mimetype: mime::Mime, mimetype: mime::Mime,
safe_to_embed_on: Embeddable,
} }
impl<R: io::Read> StreamingHandler<R> { impl<R: io::Read> StreamingHandler<R> {
pub fn new(content: R, status: StatusCode, mimetype: mime::Mime, safe_to_embed_on: Embeddable) -> Self { pub fn new(content: R, status: StatusCode, mimetype: mime::Mime) -> Self {
StreamingHandler { StreamingHandler {
initial: Vec::new(), initial: Vec::new(),
content, content,
status, status,
mimetype, mimetype,
safe_to_embed_on,
} }
} }
@ -51,7 +48,7 @@ impl<R: io::Read> StreamingHandler<R> {
.with_status(self.status) .with_status(self.status)
.with_header(header::ContentType(self.mimetype)) .with_header(header::ContentType(self.mimetype))
.with_body(body); .with_body(body);
add_security_headers(&mut res.headers_mut(), self.safe_to_embed_on, false); add_security_headers(&mut res.headers_mut(), false);
(reader, res) (reader, res)
} }

View File

@ -38,8 +38,6 @@ extern crate fetch;
extern crate node_health; extern crate node_health;
extern crate parity_dapps_glue as parity_dapps; extern crate parity_dapps_glue as parity_dapps;
extern crate parity_hash_fetch as hash_fetch; extern crate parity_hash_fetch as hash_fetch;
extern crate parity_ui;
extern crate parity_ui_deprecation;
extern crate keccak_hash as hash; extern crate keccak_hash as hash;
extern crate parity_version; extern crate parity_version;
extern crate registrar; extern crate registrar;
@ -84,6 +82,7 @@ use node_health::NodeHealth;
pub use registrar::{RegistrarClient, Asynchronous}; pub use registrar::{RegistrarClient, Asynchronous};
pub use node_health::SyncStatus; pub use node_health::SyncStatus;
pub use page::builtin::Dapp;
/// Validates Web Proxy tokens /// Validates Web Proxy tokens
pub trait WebProxyTokens: Send + Sync { pub trait WebProxyTokens: Send + Sync {
@ -101,7 +100,6 @@ pub struct Endpoints {
local_endpoints: Arc<RwLock<Vec<String>>>, local_endpoints: Arc<RwLock<Vec<String>>>,
endpoints: Arc<RwLock<endpoint::Endpoints>>, endpoints: Arc<RwLock<endpoint::Endpoints>>,
dapps_path: PathBuf, dapps_path: PathBuf,
embeddable: Option<ParentFrameSettings>,
pool: Option<CpuPool>, pool: Option<CpuPool>,
} }
@ -119,7 +117,7 @@ impl Endpoints {
None => return, None => return,
Some(pool) => pool, Some(pool) => pool,
}; };
let new_local = apps::fs::local_endpoints(&self.dapps_path, self.embeddable.clone(), pool.clone()); 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 old_local = mem::replace(&mut *self.local_endpoints.write(), new_local.keys().cloned().collect());
let (_, to_remove): (_, Vec<_>) = old_local let (_, to_remove): (_, Vec<_>) = old_local
.into_iter() .into_iter()
@ -151,69 +149,10 @@ impl Middleware {
&self.endpoints &self.endpoints
} }
/// Creates new middleware for UI server.
pub fn ui<F: Fetch>(
pool: CpuPool,
health: NodeHealth,
dapps_domain: &str,
registrar: Arc<RegistrarClient<Call=Asynchronous>>,
sync_status: Arc<SyncStatus>,
fetch: F,
info_page_only: bool,
) -> Self {
let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
hash_fetch::urlhint::URLHintContract::new(registrar),
sync_status.clone(),
fetch.clone(),
pool.clone(),
).embeddable_on(None).allow_dapps(false));
if info_page_only {
let mut special = HashMap::default();
special.insert(router::SpecialEndpoint::Home, Some(apps::ui_deprecation(pool.clone())));
return Middleware {
endpoints: Default::default(),
router: router::Router::new(
content_fetcher,
None,
special,
None,
dapps_domain.to_owned(),
),
}
}
let special = {
let mut special = special_endpoints(
pool.clone(),
health,
content_fetcher.clone(),
);
special.insert(router::SpecialEndpoint::Home, Some(apps::ui(pool.clone())));
special
};
let router = router::Router::new(
content_fetcher,
None,
special,
None,
dapps_domain.to_owned(),
);
Middleware {
endpoints: Default::default(),
router: router,
}
}
/// Creates new Dapps server middleware. /// Creates new Dapps server middleware.
pub fn dapps<F: Fetch>( pub fn dapps<F: Fetch>(
pool: CpuPool, pool: CpuPool,
health: NodeHealth, health: NodeHealth,
ui_address: Option<(String, u16)>,
extra_embed_on: Vec<(String, u16)>,
extra_script_src: Vec<(String, u16)>,
dapps_path: PathBuf, dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>, extra_dapps: Vec<PathBuf>,
dapps_domain: &str, dapps_domain: &str,
@ -222,18 +161,16 @@ impl Middleware {
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
fetch: F, fetch: F,
) -> Self { ) -> Self {
let embeddable = as_embeddable(ui_address, extra_embed_on, extra_script_src, dapps_domain);
let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
hash_fetch::urlhint::URLHintContract::new(registrar), hash_fetch::urlhint::URLHintContract::new(registrar),
sync_status.clone(), sync_status.clone(),
fetch.clone(), fetch.clone(),
pool.clone(), pool.clone(),
).embeddable_on(embeddable.clone()).allow_dapps(true)); ).allow_dapps(true));
let (local_endpoints, endpoints) = apps::all_endpoints( let (local_endpoints, endpoints) = apps::all_endpoints(
dapps_path.clone(), dapps_path.clone(),
extra_dapps, extra_dapps,
dapps_domain, dapps_domain,
embeddable.clone(),
web_proxy_tokens, web_proxy_tokens,
fetch.clone(), fetch.clone(),
pool.clone(), pool.clone(),
@ -242,28 +179,18 @@ impl Middleware {
endpoints: Arc::new(RwLock::new(endpoints)), endpoints: Arc::new(RwLock::new(endpoints)),
dapps_path, dapps_path,
local_endpoints: Arc::new(RwLock::new(local_endpoints)), local_endpoints: Arc::new(RwLock::new(local_endpoints)),
embeddable: embeddable.clone(),
pool: Some(pool.clone()), pool: Some(pool.clone()),
}; };
let special = { let special = special_endpoints(
let mut special = special_endpoints( health,
pool.clone(), content_fetcher.clone(),
health, );
content_fetcher.clone(),
);
special.insert(
router::SpecialEndpoint::Home,
Some(apps::ui_redirection(embeddable.clone())),
);
special
};
let router = router::Router::new( let router = router::Router::new(
content_fetcher, content_fetcher,
Some(endpoints.clone()), Some(endpoints.clone()),
special, special,
embeddable,
dapps_domain.to_owned(), dapps_domain.to_owned(),
); );
@ -281,13 +208,11 @@ impl http::RequestMiddleware for Middleware {
} }
fn special_endpoints( fn special_endpoints(
pool: CpuPool,
health: NodeHealth, health: NodeHealth,
content_fetcher: Arc<apps::fetcher::Fetcher>, content_fetcher: Arc<apps::fetcher::Fetcher>,
) -> HashMap<router::SpecialEndpoint, Option<Box<endpoint::Endpoint>>> { ) -> HashMap<router::SpecialEndpoint, Option<Box<endpoint::Endpoint>>> {
let mut special = HashMap::new(); let mut special = HashMap::new();
special.insert(router::SpecialEndpoint::Rpc, None); special.insert(router::SpecialEndpoint::Rpc, None);
special.insert(router::SpecialEndpoint::Utils, Some(apps::utils(pool)));
special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new( special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new(
content_fetcher, content_fetcher,
health, health,
@ -295,45 +220,9 @@ fn special_endpoints(
special special
} }
fn address(host: &str, port: u16) -> String {
format!("{}:{}", host, port)
}
fn as_embeddable(
ui_address: Option<(String, u16)>,
extra_embed_on: Vec<(String, u16)>,
extra_script_src: Vec<(String, u16)>,
dapps_domain: &str,
) -> Option<ParentFrameSettings> {
ui_address.map(|(host, port)| ParentFrameSettings {
host,
port,
extra_embed_on,
extra_script_src,
dapps_domain: dapps_domain.to_owned(),
})
}
/// Random filename /// Random filename
fn random_filename() -> String { fn random_filename() -> String {
use ::rand::Rng; use ::rand::Rng;
let mut rng = ::rand::OsRng::new().unwrap(); let mut rng = ::rand::OsRng::new().unwrap();
rng.gen_ascii_chars().take(12).collect() rng.gen_ascii_chars().take(12).collect()
} }
type Embeddable = Option<ParentFrameSettings>;
/// Parent frame host and port allowed to embed the content.
#[derive(Debug, Clone)]
pub struct ParentFrameSettings {
/// Hostname
pub host: String,
/// Port
pub port: u16,
/// Additional URLs the dapps can be embedded on.
pub extra_embed_on: Vec<(String, u16)>,
/// Additional URLs the dapp scripts can be loaded from.
pub extra_script_src: Vec<(String, u16)>,
/// Dapps Domain (web3.site)
pub dapps_domain: String,
}

View File

@ -23,15 +23,13 @@ use parity_dapps::{WebApp, Info};
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response};
use page::{handler, PageCache}; use page::{handler, PageCache};
use Embeddable;
/// Represents a builtin Dapp.
pub struct Dapp<T: WebApp + 'static> { pub struct Dapp<T: WebApp + 'static> {
/// futures cpu pool /// futures cpu pool
pool: CpuPool, pool: CpuPool,
/// Content of the files /// Content of the files
app: T, app: T,
/// Safe to be loaded in frame by other origin. (use wisely!)
safe_to_embed_on: Embeddable,
info: EndpointInfo, info: EndpointInfo,
fallback_to_index_html: bool, fallback_to_index_html: bool,
} }
@ -43,7 +41,6 @@ impl<T: WebApp + 'static> Dapp<T> {
Dapp { Dapp {
pool, pool,
app, app,
safe_to_embed_on: None,
info: EndpointInfo::from(info), info: EndpointInfo::from(info),
fallback_to_index_html: false, fallback_to_index_html: false,
} }
@ -56,26 +53,11 @@ impl<T: WebApp + 'static> Dapp<T> {
Dapp { Dapp {
pool, pool,
app, app,
safe_to_embed_on: None,
info: EndpointInfo::from(info), info: EndpointInfo::from(info),
fallback_to_index_html: true, fallback_to_index_html: true,
} }
} }
/// Creates new `Dapp` which can be safely used in iframe
/// even from different origin. It might be dangerous (clickjacking).
/// Use wisely!
pub fn new_safe_to_embed(pool: CpuPool, app: T, address: Embeddable) -> Self {
let info = app.info();
Dapp {
pool,
app,
safe_to_embed_on: address,
info: EndpointInfo::from(info),
fallback_to_index_html: false,
}
}
/// Allow the dapp to use `unsafe-eval` to run JS. /// Allow the dapp to use `unsafe-eval` to run JS.
pub fn allow_js_eval(&mut self) { pub fn allow_js_eval(&mut self) {
self.info.allow_js_eval = Some(true); self.info.allow_js_eval = Some(true);
@ -121,7 +103,6 @@ impl<T: WebApp> Endpoint for Dapp<T> {
let (reader, response) = handler::PageHandler { let (reader, response) = handler::PageHandler {
file, file,
cache: PageCache::Disabled, cache: PageCache::Disabled,
safe_to_embed_on: self.safe_to_embed_on.clone(),
allow_js_eval: self.info.allow_js_eval.clone().unwrap_or(false), allow_js_eval: self.info.allow_js_eval.clone().unwrap_or(false),
}.into_response(); }.into_response();

View File

@ -20,7 +20,6 @@ use hyper::{self, header, StatusCode};
use hyper::mime::{Mime}; use hyper::mime::{Mime};
use handlers::{Reader, ContentHandler, add_security_headers}; use handlers::{Reader, ContentHandler, add_security_headers};
use {Embeddable};
/// Represents a file that can be sent to client. /// Represents a file that can be sent to client.
/// Implementation should keep track of bytes already sent internally. /// Implementation should keep track of bytes already sent internally.
@ -54,8 +53,6 @@ impl Default for PageCache {
pub struct PageHandler<T: DappFile> { pub struct PageHandler<T: DappFile> {
/// File currently being served /// File currently being served
pub file: Option<T>, pub file: Option<T>,
/// Flag indicating if the file can be safely embeded (put in iframe).
pub safe_to_embed_on: Embeddable,
/// Cache settings for this page. /// Cache settings for this page.
pub cache: PageCache, pub cache: PageCache,
/// Allow JS unsafe-eval. /// Allow JS unsafe-eval.
@ -70,7 +67,6 @@ impl<T: DappFile> PageHandler<T> {
"File not found", "File not found",
"Requested file has not been found.", "Requested file has not been found.",
None, None,
self.safe_to_embed_on,
).into()), ).into()),
Some(file) => file, Some(file) => file,
}; };
@ -94,7 +90,7 @@ impl<T: DappFile> PageHandler<T> {
headers.set(header::ContentType(file.content_type().to_owned())); headers.set(header::ContentType(file.content_type().to_owned()));
add_security_headers(&mut headers, self.safe_to_embed_on, self.allow_js_eval); add_security_headers(&mut headers, self.allow_js_eval);
} }
let (reader, body) = Reader::pair(file.into_reader(), Vec::new()); let (reader, body) = Reader::pair(file.into_reader(), Vec::new());

View File

@ -22,7 +22,6 @@ use futures_cpupool::CpuPool;
use page::handler::{self, PageCache}; use page::handler::{self, PageCache};
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response}; use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response};
use hyper::mime::Mime; use hyper::mime::Mime;
use Embeddable;
#[derive(Clone)] #[derive(Clone)]
pub struct Dapp { pub struct Dapp {
@ -31,7 +30,6 @@ pub struct Dapp {
mime: Option<Mime>, mime: Option<Mime>,
info: Option<EndpointInfo>, info: Option<EndpointInfo>,
cache: PageCache, cache: PageCache,
embeddable_on: Embeddable,
} }
impl fmt::Debug for Dapp { impl fmt::Debug for Dapp {
@ -41,20 +39,18 @@ impl fmt::Debug for Dapp {
.field("mime", &self.mime) .field("mime", &self.mime)
.field("info", &self.info) .field("info", &self.info)
.field("cache", &self.cache) .field("cache", &self.cache)
.field("embeddable_on", &self.embeddable_on)
.finish() .finish()
} }
} }
impl Dapp { impl Dapp {
pub fn new(pool: CpuPool, path: PathBuf, info: EndpointInfo, cache: PageCache, embeddable_on: Embeddable) -> Self { pub fn new(pool: CpuPool, path: PathBuf, info: EndpointInfo, cache: PageCache) -> Self {
Dapp { Dapp {
pool, pool,
path, path,
mime: None, mime: None,
info: Some(info), info: Some(info),
cache, cache,
embeddable_on,
} }
} }
@ -65,7 +61,6 @@ impl Dapp {
mime: Some(mime), mime: Some(mime),
info: None, info: None,
cache, cache,
embeddable_on: None,
} }
} }
@ -96,7 +91,6 @@ impl Dapp {
let (reader, response) = handler::PageHandler { let (reader, response) = handler::PageHandler {
file: self.get_file(path), file: self.get_file(path),
cache: self.cache, cache: self.cache,
safe_to_embed_on: self.embeddable_on.clone(),
allow_js_eval: self.info.as_ref().and_then(|x| x.allow_js_eval).unwrap_or(false), allow_js_eval: self.info.as_ref().and_then(|x| x.allow_js_eval).unwrap_or(false),
}.into_response(); }.into_response();

View File

@ -21,25 +21,20 @@ use endpoint::{Endpoint, Request, Response, EndpointPath};
use futures::future; use futures::future;
use handlers::ContentHandler; use handlers::ContentHandler;
use hyper::mime; use hyper::mime;
use {address, Embeddable};
pub struct ProxyPac { pub struct ProxyPac {
embeddable: Embeddable,
dapps_domain: String, dapps_domain: String,
} }
impl ProxyPac { impl ProxyPac {
pub fn boxed(embeddable: Embeddable, dapps_domain: String) -> Box<Endpoint> { pub fn boxed(dapps_domain: String) -> Box<Endpoint> {
Box::new(ProxyPac { embeddable, dapps_domain }) Box::new(ProxyPac { dapps_domain })
} }
} }
impl Endpoint for ProxyPac { impl Endpoint for ProxyPac {
fn respond(&self, path: EndpointPath, _req: Request) -> Response { fn respond(&self, path: EndpointPath, _req: Request) -> Response {
let ui = self.embeddable let ui = format!("{}:{}", path.host, path.port);
.as_ref()
.map(|ref parent| address(&parent.host, parent.port))
.unwrap_or_else(|| format!("{}:{}", path.host, path.port));
let content = format!( let content = format!(
r#" r#"

View File

@ -29,14 +29,12 @@ use apps::fetcher::Fetcher;
use endpoint::{self, Endpoint, EndpointPath}; use endpoint::{self, Endpoint, EndpointPath};
use Endpoints; use Endpoints;
use handlers; use handlers;
use Embeddable;
/// Special endpoints are accessible on every domain (every dapp) /// Special endpoints are accessible on every domain (every dapp)
#[derive(Debug, PartialEq, Hash, Eq)] #[derive(Debug, PartialEq, Hash, Eq)]
pub enum SpecialEndpoint { pub enum SpecialEndpoint {
Rpc, Rpc,
Api, Api,
Utils,
Home, Home,
None, None,
} }
@ -52,16 +50,14 @@ pub struct Router {
endpoints: Option<Endpoints>, endpoints: Option<Endpoints>,
fetch: Arc<Fetcher>, fetch: Arc<Fetcher>,
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>, special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
embeddable_on: Embeddable,
dapps_domain: String, dapps_domain: String,
} }
impl Router { impl Router {
fn resolve_request(&self, req: hyper::Request, refresh_dapps: bool) -> (bool, Response) { fn resolve_request(&self, req: hyper::Request, refresh_dapps: bool) -> Response {
// Choose proper handler depending on path / domain // Choose proper handler depending on path / domain
let endpoint = extract_endpoint(req.uri(), req.headers().get(), &self.dapps_domain); let endpoint = extract_endpoint(req.uri(), req.headers().get(), &self.dapps_domain);
let referer = extract_referer_endpoint(&req, &self.dapps_domain); let referer = extract_referer_endpoint(&req, &self.dapps_domain);
let is_utils = endpoint.1 == SpecialEndpoint::Utils;
let is_get_request = *req.method() == hyper::Method::Get; let is_get_request = *req.method() == hyper::Method::Get;
let is_head_request = *req.method() == hyper::Method::Head; let is_head_request = *req.method() == hyper::Method::Head;
let has_dapp = |dapp: &str| self.endpoints let has_dapp = |dapp: &str| self.endpoints
@ -71,7 +67,7 @@ impl Router {
trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", req.uri(), req); trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", req.uri(), req);
debug!(target: "dapps", "Handling endpoint request: {:?}, referer: {:?}", endpoint, referer); debug!(target: "dapps", "Handling endpoint request: {:?}, referer: {:?}", endpoint, referer);
(is_utils, match (endpoint.0, endpoint.1, referer) { match (endpoint.0, endpoint.1, referer) {
// Handle invalid web requests that we can recover from // Handle invalid web requests that we can recover from
(ref path, SpecialEndpoint::None, Some(ref referer)) (ref path, SpecialEndpoint::None, Some(ref referer))
if referer.app_id == apps::WEB_PATH if referer.app_id == apps::WEB_PATH
@ -132,7 +128,6 @@ impl Router {
"404 Not Found", "404 Not Found",
"Requested content was not found.", "Requested content was not found.",
None, None,
self.embeddable_on.clone(),
).into()))) ).into())))
} }
}, },
@ -161,20 +156,19 @@ impl Router {
"404 Not Found", "404 Not Found",
"Requested content was not found.", "Requested content was not found.",
None, None,
self.embeddable_on.clone(),
).into()))) ).into())))
}, },
}) }
} }
} }
impl http::RequestMiddleware for Router { impl http::RequestMiddleware for Router {
fn on_request(&self, req: hyper::Request) -> http::RequestMiddlewareAction { fn on_request(&self, req: hyper::Request) -> http::RequestMiddlewareAction {
let is_origin_set = req.headers().get::<header::Origin>().is_some(); let is_origin_set = req.headers().get::<header::Origin>().is_some();
let (is_utils, response) = self.resolve_request(req, self.endpoints.is_some()); let response = self.resolve_request(req, self.endpoints.is_some());
match response { match response {
Response::Some(response) => http::RequestMiddlewareAction::Respond { Response::Some(response) => http::RequestMiddlewareAction::Respond {
should_validate_hosts: !is_utils, should_validate_hosts: true,
response, response,
}, },
Response::None(request) => http::RequestMiddlewareAction::Proceed { Response::None(request) => http::RequestMiddlewareAction::Proceed {
@ -190,14 +184,12 @@ impl Router {
content_fetcher: Arc<Fetcher>, content_fetcher: Arc<Fetcher>,
endpoints: Option<Endpoints>, endpoints: Option<Endpoints>,
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>, special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
embeddable_on: Embeddable,
dapps_domain: String, dapps_domain: String,
) -> Self { ) -> Self {
Router { Router {
endpoints: endpoints, endpoints: endpoints,
fetch: content_fetcher, fetch: content_fetcher,
special: special, special: special,
embeddable_on: embeddable_on,
dapps_domain: format!(".{}", dapps_domain), dapps_domain: format!(".{}", dapps_domain),
} }
} }
@ -250,7 +242,6 @@ fn extract_endpoint(url: &Uri, extra_host: Option<&header::Host>, dapps_domain:
match path[0].as_ref() { match path[0].as_ref() {
apps::RPC_PATH => SpecialEndpoint::Rpc, apps::RPC_PATH => SpecialEndpoint::Rpc,
apps::API_PATH => SpecialEndpoint::Api, apps::API_PATH => SpecialEndpoint::Api,
apps::UTILS_PATH => SpecialEndpoint::Utils,
apps::HOME_PAGE => SpecialEndpoint::Home, apps::HOME_PAGE => SpecialEndpoint::Home,
_ => SpecialEndpoint::None, _ => SpecialEndpoint::None,
} }
@ -351,30 +342,6 @@ mod tests {
}), SpecialEndpoint::Rpc) }), SpecialEndpoint::Rpc)
); );
assert_eq!(
extract_endpoint(&"http://my.status.web3.site/parity-utils/inject.js".parse().unwrap(), None, dapps_domain),
(Some(EndpointPath {
app_id: "status".to_owned(),
app_params: vec!["my".into(), "inject.js".into()],
query: None,
host: "my.status.web3.site".to_owned(),
port: 80,
using_dapps_domains: true,
}), SpecialEndpoint::Utils)
);
assert_eq!(
extract_endpoint(&"http://my.status.web3.site/inject.js".parse().unwrap(), None, dapps_domain),
(Some(EndpointPath {
app_id: "status".to_owned(),
app_params: vec!["my".into(), "inject.js".into()],
query: None,
host: "my.status.web3.site".to_owned(),
port: 80,
using_dapps_domains: true,
}), SpecialEndpoint::None)
);
// By Subdomain // By Subdomain
assert_eq!( assert_eq!(
extract_endpoint(&"http://status.web3.site/test.html".parse().unwrap(), None, dapps_domain), extract_endpoint(&"http://status.web3.site/test.html".parse().unwrap(), None, dapps_domain),

View File

@ -19,7 +19,7 @@ use rustc_hex::FromHex;
use tests::helpers::{ use tests::helpers::{
serve_with_registrar, serve_with_registrar_and_sync, serve_with_fetch, serve_with_registrar, serve_with_registrar_and_sync, serve_with_fetch,
serve_with_registrar_and_fetch, serve_with_registrar_and_fetch,
request, assert_security_headers_for_embed, request, assert_security_headers
}; };
#[test] #[test]
@ -40,7 +40,7 @@ fn should_resolve_dapp() {
// then // then
response.assert_status("HTTP/1.1 404 Not Found"); response.assert_status("HTTP/1.1 404 Not Found");
assert_eq!(registrar.calls.lock().len(), 4); assert_eq!(registrar.calls.lock().len(), 4);
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
} }
#[test] #[test]
@ -61,7 +61,7 @@ fn should_return_503_when_syncing_but_should_make_the_calls() {
// then // then
response.assert_status("HTTP/1.1 503 Service Unavailable"); response.assert_status("HTTP/1.1 503 Service Unavailable");
assert_eq!(registrar.calls.lock().len(), 2); assert_eq!(registrar.calls.lock().len(), 2);
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
} }
const GAVCOIN_DAPP: &'static str = "00000000000000000000000000000000000000000000000000000000000000609faf32e1e3845e237cc6efd27187cee13b3b99db000000000000000000000000000000000000000000000000d8bd350823e28ff75e74a34215faefdc8a52fd8e00000000000000000000000000000000000000000000000000000000000000116761766f66796f726b2f676176636f696e000000000000000000000000000000"; const GAVCOIN_DAPP: &'static str = "00000000000000000000000000000000000000000000000000000000000000609faf32e1e3845e237cc6efd27187cee13b3b99db000000000000000000000000000000000000000000000000d8bd350823e28ff75e74a34215faefdc8a52fd8e00000000000000000000000000000000000000000000000000000000000000116761766f66796f726b2f676176636f696e000000000000000000000000000000";
@ -95,7 +95,7 @@ fn should_return_502_on_hash_mismatch() {
response.assert_status("HTTP/1.1 502 Bad Gateway"); response.assert_status("HTTP/1.1 502 Bad Gateway");
assert!(response.body.contains("HashMismatch"), "Expected hash mismatch response, got: {:?}", response.body); assert!(response.body.contains("HashMismatch"), "Expected hash mismatch response, got: {:?}", response.body);
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
} }
#[test] #[test]
@ -126,7 +126,7 @@ fn should_return_error_for_invalid_dapp_zip() {
response.assert_status("HTTP/1.1 502 Bad Gateway"); response.assert_status("HTTP/1.1 502 Bad Gateway");
assert!(response.body.contains("InvalidArchive"), "Expected invalid zip response, got: {:?}", response.body); assert!(response.body.contains("InvalidArchive"), "Expected invalid zip response, got: {:?}", response.body);
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
} }
#[test] #[test]
@ -165,7 +165,7 @@ fn should_return_fetched_dapp_content() {
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
response1.assert_status("HTTP/1.1 200 OK"); response1.assert_status("HTTP/1.1 200 OK");
assert_security_headers_for_embed(&response1.headers); assert_security_headers(&response1.headers);
assert!( assert!(
response1.body.contains(r#"18 response1.body.contains(r#"18
<h1>Hello Gavcoin!</h1> <h1>Hello Gavcoin!</h1>
@ -178,7 +178,7 @@ fn should_return_fetched_dapp_content() {
); );
response2.assert_status("HTTP/1.1 200 OK"); response2.assert_status("HTTP/1.1 200 OK");
assert_security_headers_for_embed(&response2.headers); assert_security_headers(&response2.headers);
assert_eq!( assert_eq!(
response2.body, response2.body,
r#"EA r#"EA
@ -331,7 +331,7 @@ fn should_stream_web_content() {
// then // then
response.assert_status("HTTP/1.1 200 OK"); response.assert_status("HTTP/1.1 200 OK");
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
fetch.assert_requested("https://parity.io/"); fetch.assert_requested("https://parity.io/");
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
@ -354,7 +354,7 @@ fn should_support_base32_encoded_web_urls() {
// then // then
response.assert_status("HTTP/1.1 200 OK"); response.assert_status("HTTP/1.1 200 OK");
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
fetch.assert_requested("https://parity.io/styles.css?test=123"); fetch.assert_requested("https://parity.io/styles.css?test=123");
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
@ -377,7 +377,7 @@ fn should_correctly_handle_long_label_when_splitted() {
// then // then
response.assert_status("HTTP/1.1 200 OK"); response.assert_status("HTTP/1.1 200 OK");
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
fetch.assert_requested("https://contribution.melonport.com/styles.css?test=123"); fetch.assert_requested("https://contribution.melonport.com/styles.css?test=123");
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
@ -400,7 +400,7 @@ fn should_support_base32_encoded_web_urls_as_path() {
// then // then
response.assert_status("HTTP/1.1 200 OK"); response.assert_status("HTTP/1.1 200 OK");
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
fetch.assert_requested("https://parity.io/styles.css?test=123"); fetch.assert_requested("https://parity.io/styles.css?test=123");
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
@ -423,7 +423,7 @@ fn should_return_error_on_non_whitelisted_domain() {
// then // then
response.assert_status("HTTP/1.1 400 Bad Request"); response.assert_status("HTTP/1.1 400 Bad Request");
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
} }
@ -445,7 +445,7 @@ fn should_return_error_on_invalid_token() {
// then // then
response.assert_status("HTTP/1.1 400 Bad Request"); response.assert_status("HTTP/1.1 400 Bad Request");
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
} }
@ -467,7 +467,7 @@ fn should_return_error_on_invalid_protocol() {
// then // then
response.assert_status("HTTP/1.1 400 Bad Request"); response.assert_status("HTTP/1.1 400 Bad Request");
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
} }
@ -492,7 +492,7 @@ fn should_disallow_non_get_requests() {
// then // then
response.assert_status("HTTP/1.1 405 Method Not Allowed"); response.assert_status("HTTP/1.1 405 Method Not Allowed");
assert_security_headers_for_embed(&response.headers); assert_security_headers(&response.headers);
fetch.assert_no_more_requests(); fetch.assert_no_more_requests();
} }

View File

@ -36,8 +36,6 @@ mod fetch;
use self::registrar::FakeRegistrar; use self::registrar::FakeRegistrar;
use self::fetch::FakeFetch; use self::fetch::FakeFetch;
const SIGNER_PORT: u16 = 18180;
#[derive(Debug)] #[derive(Debug)]
struct FakeSync(bool); struct FakeSync(bool);
impl SyncStatus for FakeSync { impl SyncStatus for FakeSync {
@ -63,8 +61,7 @@ pub fn init_server<F, B>(process: F, io: IoHandler) -> (Server, Arc<FakeRegistra
let mut dapps_path = env::temp_dir(); let mut dapps_path = env::temp_dir();
dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading"); dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading");
let mut builder = ServerBuilder::new(FetchClient::new().unwrap(), &dapps_path, registrar.clone()); let builder = ServerBuilder::new(FetchClient::new().unwrap(), &dapps_path, registrar.clone());
builder.signer_address = Some(("127.0.0.1".into(), SIGNER_PORT));
let server = process(builder).start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), io).unwrap(); let server = process(builder).start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), io).unwrap();
( (
server, server,
@ -122,13 +119,6 @@ pub fn serve() -> Server {
init_server(|builder| builder, Default::default()).0 init_server(|builder| builder, Default::default()).0
} }
pub fn serve_ui() -> Server {
init_server(|mut builder| {
builder.serve_ui = true;
builder
}, Default::default()).0
}
pub fn request(server: Server, request: &str) -> http_client::Response { pub fn request(server: Server, request: &str) -> http_client::Response {
http_client::request(server.addr(), request) http_client::request(server.addr(), request)
} }
@ -136,9 +126,6 @@ pub fn request(server: Server, request: &str) -> http_client::Response {
pub fn assert_security_headers(headers: &[String]) { pub fn assert_security_headers(headers: &[String]) {
http_client::assert_security_headers_present(headers, None) http_client::assert_security_headers_present(headers, None)
} }
pub fn assert_security_headers_for_embed(headers: &[String]) {
http_client::assert_security_headers_present(headers, Some(SIGNER_PORT))
}
/// Webapps HTTP+RPC server build. /// Webapps HTTP+RPC server build.
pub struct ServerBuilder<T: Fetch = FetchClient> { pub struct ServerBuilder<T: Fetch = FetchClient> {
@ -146,10 +133,8 @@ pub struct ServerBuilder<T: Fetch = FetchClient> {
registrar: Arc<RegistrarClient<Call=Asynchronous>>, registrar: Arc<RegistrarClient<Call=Asynchronous>>,
sync_status: Arc<SyncStatus>, sync_status: Arc<SyncStatus>,
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
signer_address: Option<(String, u16)>,
allowed_hosts: DomainsValidation<Host>, allowed_hosts: DomainsValidation<Host>,
fetch: T, fetch: T,
serve_ui: bool,
} }
impl ServerBuilder { impl ServerBuilder {
@ -160,10 +145,8 @@ impl ServerBuilder {
registrar: registrar, registrar: registrar,
sync_status: Arc::new(FakeSync(false)), sync_status: Arc::new(FakeSync(false)),
web_proxy_tokens: Arc::new(|_| None), web_proxy_tokens: Arc::new(|_| None),
signer_address: None,
allowed_hosts: DomainsValidation::Disabled, allowed_hosts: DomainsValidation::Disabled,
fetch: fetch, fetch: fetch,
serve_ui: false,
} }
} }
} }
@ -176,10 +159,8 @@ impl<T: Fetch> ServerBuilder<T> {
registrar: self.registrar, registrar: self.registrar,
sync_status: self.sync_status, sync_status: self.sync_status,
web_proxy_tokens: self.web_proxy_tokens, web_proxy_tokens: self.web_proxy_tokens,
signer_address: self.signer_address,
allowed_hosts: self.allowed_hosts, allowed_hosts: self.allowed_hosts,
fetch: fetch, fetch: fetch,
serve_ui: self.serve_ui,
} }
} }
@ -190,7 +171,6 @@ impl<T: Fetch> ServerBuilder<T> {
addr, addr,
io, io,
self.allowed_hosts, self.allowed_hosts,
self.signer_address,
self.dapps_path, self.dapps_path,
vec![], vec![],
self.registrar, self.registrar,
@ -198,7 +178,6 @@ impl<T: Fetch> ServerBuilder<T> {
self.web_proxy_tokens, self.web_proxy_tokens,
Remote::new_sync(), Remote::new_sync(),
self.fetch, self.fetch,
self.serve_ui,
) )
} }
} }
@ -215,7 +194,6 @@ impl Server {
addr: &SocketAddr, addr: &SocketAddr,
io: IoHandler, io: IoHandler,
allowed_hosts: DomainsValidation<Host>, allowed_hosts: DomainsValidation<Host>,
signer_address: Option<(String, u16)>,
dapps_path: PathBuf, dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>, extra_dapps: Vec<PathBuf>,
registrar: Arc<RegistrarClient<Call=Asynchronous>>, registrar: Arc<RegistrarClient<Call=Asynchronous>>,
@ -223,7 +201,6 @@ impl Server {
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
remote: Remote, remote: Remote,
fetch: F, fetch: F,
serve_ui: bool,
) -> io::Result<Server> { ) -> io::Result<Server> {
let health = NodeHealth::new( let health = NodeHealth::new(
sync_status.clone(), sync_status.clone(),
@ -231,23 +208,10 @@ impl Server {
remote.clone(), remote.clone(),
); );
let pool = ::futures_cpupool::CpuPool::new(1); let pool = ::futures_cpupool::CpuPool::new(1);
let middleware = if serve_ui { let middleware =
Middleware::ui(
pool,
health,
DAPPS_DOMAIN.into(),
registrar,
sync_status,
fetch,
false,
)
} else {
Middleware::dapps( Middleware::dapps(
pool, pool,
health, health,
signer_address,
vec![],
vec![],
dapps_path, dapps_path,
extra_dapps, extra_dapps,
DAPPS_DOMAIN.into(), DAPPS_DOMAIN.into(),
@ -255,8 +219,7 @@ impl Server {
sync_status, sync_status,
web_proxy_tokens, web_proxy_tokens,
fetch, fetch,
) );
};
let mut allowed_hosts: Option<Vec<Host>> = allowed_hosts.into(); let mut allowed_hosts: Option<Vec<Host>> = allowed_hosts.into();
allowed_hosts.as_mut().map(|hosts| { allowed_hosts.as_mut().map(|hosts| {

View File

@ -1,62 +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://www.gnu.org/licenses/>.
use tests::helpers::{serve_ui, request, assert_security_headers};
#[test]
fn should_serve_home_js() {
// given
let server = serve_ui();
// when
let response = request(server,
"\
GET /inject.js 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 200 OK");
response.assert_header("Content-Type", "application/javascript");
assert_eq!(response.body.contains("function(){"), true, "Expected function in: {}", response.body);
assert_security_headers(&response.headers);
}
#[test]
fn should_serve_home() {
// given
let server = serve_ui();
// 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 200 OK");
response.assert_header("Content-Type", "text/html");
assert_security_headers(&response.headers);
}

View File

@ -20,7 +20,5 @@ mod helpers;
mod api; mod api;
mod fetch; mod fetch;
mod home;
mod redirection;
mod rpc; mod rpc;
mod validation; mod validation;

View File

@ -1,206 +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://www.gnu.org/licenses/>.
use tests::helpers::{serve, request, assert_security_headers, assert_security_headers_for_embed};
#[test]
fn should_redirect_to_home() {
// given
let server = serve();
// 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 302 Found");
assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180");
}
#[test]
fn should_redirect_to_home_with_domain() {
// given
let server = serve();
// when
let response = request(server,
"\
GET / HTTP/1.1\r\n\
Host: home.web3.site\r\n\
Connection: close\r\n\
\r\n\
"
);
// then
response.assert_status("HTTP/1.1 302 Found");
assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180");
}
#[test]
fn should_redirect_to_home_when_trailing_slash_is_missing() {
// given
let server = serve();
// when
let response = request(server,
"\
GET /app 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 302 Found");
assert_eq!(response.headers.get(0).unwrap(), "Location: http://127.0.0.1:18180");
}
#[test]
fn should_display_404_on_invalid_dapp() {
// given
let server = serve();
// when
let response = request(server,
"\
GET /invaliddapp/ 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");
assert_security_headers_for_embed(&response.headers);
}
#[test]
fn should_display_404_on_invalid_dapp_with_domain() {
// given
let server = serve();
// when
let response = request(server,
"\
GET / HTTP/1.1\r\n\
Host: invaliddapp.web3.site\r\n\
Connection: close\r\n\
\r\n\
"
);
// then
response.assert_status("HTTP/1.1 404 Not Found");
assert_security_headers_for_embed(&response.headers);
}
#[test]
fn should_serve_rpc() {
// given
let server = serve();
// when
let response = request(server,
"\
POST / HTTP/1.1\r\n\
Host: 127.0.0.1:8080\r\n\
Connection: close\r\n\
Content-Type: application/json\r\n
\r\n\
{}
"
);
// then
response.assert_status("HTTP/1.1 200 OK");
assert_eq!(response.body, format!("4C\n{}\n\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#));
}
#[test]
fn should_serve_rpc_at_slash_rpc() {
// given
let server = serve();
// when
let response = request(server,
"\
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
\r\n\
{}
"
);
// then
response.assert_status("HTTP/1.1 200 OK");
assert_eq!(response.body, format!("4C\n{}\n\n0\n\n", r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#));
}
#[test]
fn should_serve_proxy_pac() {
// given
let server = serve();
// when
let response = request(server,
"\
GET /proxy/proxy.pac 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 200 OK");
assert_eq!(response.body, "DB\n\nfunction FindProxyForURL(url, host) {\n\tif (shExpMatch(host, \"home.web3.site\"))\n\t{\n\t\treturn \"PROXY 127.0.0.1:18180\";\n\t}\n\n\tif (shExpMatch(host, \"*.web3.site\"))\n\t{\n\t\treturn \"PROXY 127.0.0.1:8080\";\n\t}\n\n\treturn \"DIRECT\";\n}\n\n0\n\n".to_owned());
assert_security_headers(&response.headers);
}
#[test]
fn should_serve_utils() {
// given
let server = serve();
// when
let response = request(server,
"\
GET /parity-utils/inject.js 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 200 OK");
response.assert_header("Content-Type", "application/javascript");
assert_eq!(response.body.contains("function(){"), true, "Expected function in: {}", response.body);
assert_security_headers(&response.headers);
}

View File

@ -37,26 +37,6 @@ fn should_reject_invalid_host() {
assert!(response.body.contains("Provided Host header is not whitelisted."), response.body); assert!(response.body.contains("Provided Host header is not whitelisted."), response.body);
} }
#[test]
fn should_allow_valid_host() {
// given
let server = serve_hosts(Some(vec!["localhost:8080".into()]));
// when
let response = request(server,
"\
GET /ui/ 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");
}
#[test] #[test]
fn should_serve_dapps_domains() { fn should_serve_dapps_domains() {
// given // given
@ -66,28 +46,7 @@ fn should_serve_dapps_domains() {
let response = request(server, let response = request(server,
"\ "\
GET / HTTP/1.1\r\n\ GET / HTTP/1.1\r\n\
Host: ui.web3.site\r\n\ Host: proxy.web3.site\r\n\
Connection: close\r\n\
\r\n\
{}
"
);
// then
response.assert_status("HTTP/1.1 200 OK");
}
#[test]
// NOTE [todr] This is required for error pages to be styled properly.
fn should_allow_parity_utils_even_on_invalid_domain() {
// given
let server = serve_hosts(Some(vec!["localhost:8080".into()]));
// when
let response = request(server,
"\
GET /parity-utils/styles.css HTTP/1.1\r\n\
Host: 127.0.0.1:8080\r\n\
Connection: close\r\n\ Connection: close\r\n\
\r\n\ \r\n\
{} {}

View File

@ -30,10 +30,9 @@ use handlers::{
ContentFetcherHandler, ContentHandler, ContentValidator, ValidatorResponse, ContentFetcherHandler, ContentHandler, ContentValidator, ValidatorResponse,
StreamingHandler, StreamingHandler,
}; };
use {Embeddable, WebProxyTokens}; use WebProxyTokens;
pub struct Web<F> { pub struct Web<F> {
embeddable_on: Embeddable,
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
fetch: F, fetch: F,
pool: CpuPool, pool: CpuPool,
@ -41,13 +40,11 @@ pub struct Web<F> {
impl<F: Fetch> Web<F> { impl<F: Fetch> Web<F> {
pub fn boxed( pub fn boxed(
embeddable_on: Embeddable,
web_proxy_tokens: Arc<WebProxyTokens>, web_proxy_tokens: Arc<WebProxyTokens>,
fetch: F, fetch: F,
pool: CpuPool, pool: CpuPool,
) -> Box<Endpoint> { ) -> Box<Endpoint> {
Box::new(Web { Box::new(Web {
embeddable_on,
web_proxy_tokens, web_proxy_tokens,
fetch, fetch,
pool, pool,
@ -64,7 +61,6 @@ impl<F: Fetch> Web<F> {
"Invalid parameter", "Invalid parameter",
"Couldn't parse given parameter:", "Couldn't parse given parameter:",
path.app_params.get(0).map(String::as_str), path.app_params.get(0).map(String::as_str),
self.embeddable_on.clone()
))?; ))?;
let mut token_it = token_and_url.split('+'); let mut token_it = token_and_url.split('+');
@ -76,7 +72,7 @@ impl<F: Fetch> Web<F> {
Some(domain) => domain, Some(domain) => domain,
_ => { _ => {
return Err(ContentHandler::error( return Err(ContentHandler::error(
StatusCode::BadRequest, "Invalid Access Token", "Invalid or old web proxy access token supplied.", Some("Try refreshing the page."), self.embeddable_on.clone() StatusCode::BadRequest, "Invalid Access Token", "Invalid or old web proxy access token supplied.", Some("Try refreshing the page."),
)); ));
} }
}; };
@ -86,14 +82,14 @@ impl<F: Fetch> Web<F> {
Some(url) if url.starts_with("http://") || url.starts_with("https://") => url.to_owned(), Some(url) if url.starts_with("http://") || url.starts_with("https://") => url.to_owned(),
_ => { _ => {
return Err(ContentHandler::error( return Err(ContentHandler::error(
StatusCode::BadRequest, "Invalid Protocol", "Invalid protocol used.", None, self.embeddable_on.clone() StatusCode::BadRequest, "Invalid Protocol", "Invalid protocol used.", None,
)); ));
} }
}; };
if !target_url.starts_with(&*domain) { if !target_url.starts_with(&*domain) {
return Err(ContentHandler::error( return Err(ContentHandler::error(
StatusCode::BadRequest, "Invalid Domain", "Dapp attempted to access invalid domain.", Some(&target_url), self.embeddable_on.clone(), StatusCode::BadRequest, "Invalid Domain", "Dapp attempted to access invalid domain.", Some(&target_url),
)); ));
} }
@ -128,10 +124,8 @@ impl<F: Fetch> Endpoint for Web<F> {
&target_url, &target_url,
path, path,
WebInstaller { WebInstaller {
embeddable_on: self.embeddable_on.clone(),
token, token,
}, },
self.embeddable_on.clone(),
self.fetch.clone(), self.fetch.clone(),
self.pool.clone(), self.pool.clone(),
)) ))
@ -139,7 +133,6 @@ impl<F: Fetch> Endpoint for Web<F> {
} }
struct WebInstaller { struct WebInstaller {
embeddable_on: Embeddable,
token: String, token: String,
} }
@ -154,12 +147,10 @@ impl ContentValidator for WebInstaller {
fetch::BodyReader::new(response), fetch::BodyReader::new(response),
status, status,
mime, mime,
self.embeddable_on,
); );
if is_html { if is_html {
handler.set_initial_content(&format!( handler.set_initial_content(&format!(
r#"<script src="/{}/inject.js"></script><script>history.replaceState({{}}, "", "/?{}{}/{}")</script>"#, r#"<script>history.replaceState({{}}, "", "/?{}{}/{}")</script>"#,
apps::UTILS_PATH,
apps::URL_REFERER, apps::URL_REFERER,
apps::WEB_PATH, apps::WEB_PATH,
&self.token, &self.token,

View File

@ -1,18 +0,0 @@
[package]
description = "Parity UI deprecation notice."
name = "parity-ui-deprecation"
version = "1.10.0"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
[features]
default = ["with-syntex", "use-precompiled-js"]
use-precompiled-js = ["parity-dapps-glue/use-precompiled-js"]
with-syntex = ["parity-dapps-glue/with-syntex"]
[build-dependencies]
parity-dapps-glue = "1.9"
[dependencies]
parity-dapps-glue = "1.9"

View File

@ -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 <http://www.gnu.org/licenses/>.
extern crate parity_dapps_glue;
fn main() {
parity_dapps_glue::generate();
}

View File

@ -1,119 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Parity</title>
<style>
/* 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://www.gnu.org/licenses/>.
*/
:root, :root body {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
background: rgb(95, 95, 95);
color: rgba(255, 255, 255, 0.75);
font-size: 16px;
font-family: 'Roboto', sans-serif;
font-weight: 300;
}
:root a, :root a:visited {
text-decoration: none;
cursor: pointer;
color: rgb(0, 151, 167); /* #f80 */
}
:root a:hover {
color: rgb(0, 174, 193);
}
h1,h2,h3,h4,h5,h6 {
font-weight: 300;
text-transform: uppercase;
text-decoration: none;
}
h1 {
font-size: 24px;
line-height: 36px;
color: rgb(0, 151, 167);
}
h2 {
font-size: 20px;
line-height: 34px;
}
code,kbd,pre,samp {
font-family: 'Roboto Mono', monospace;
}
.parity-navbar {
background: rgb(65, 65, 65);
height: 72px;
padding: 0 1rem;
display: flex;
justify-content: space-between;
}
.parity-status {
clear: both;
padding: 1rem;
margin: 1rem 0;
text-align: right;
opacity: 0.75;
}
.parity-box {
margin: 1rem;
padding: 1rem;
background-color: rgb(48, 48, 48);
box-sizing: border-box;
box-shadow: rgba(0, 0, 0, 0.117647) 0px 1px 6px, rgba(0, 0, 0, 0.117647) 0px 1px 4px;
border-radius: 2px;
z-index: 1;
color: #aaa;
}
.parity-box h1,
.parity-box h2,
.parity-box h3,
.parity-box h4,
.parity-box h5,
.parity-box h6 {
margin: 0;
}
</style>
</head>
<body>
<div class="parity-navbar">
</div>
<div class="parity-box">
<h1>The Parity UI has been split off into a standalone project.</h1>
<h3>Get the standalone Parity UI from <a href="https://github.com/Parity-JS/shell/releases">here</a></h3>
<p>
</p>
</div>
<div class="parity-status">
</div>
</body>
</html>

View File

@ -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 <http://www.gnu.org/licenses/>.
#[cfg(feature = "with-syntex")]
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
#[cfg(not(feature = "with-syntex"))]
include!("lib.rs.in");

View File

@ -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 <http://www.gnu.org/licenses/>.
extern crate parity_dapps_glue;
use std::collections::HashMap;
use parity_dapps_glue::{WebApp, File, Info};
#[derive(WebAppFiles)]
#[webapp(path = "../build")]
pub struct App {
pub files: HashMap<&'static str, File>,
}
impl Default for App {
fn default() -> App {
App {
files: Self::files(),
}
}
}
impl WebApp for App {
fn file(&self, path: &str) -> Option<&File> {
self.files.get(path)
}
fn info(&self) -> Info {
Info {
name: "Parity Wallet info page",
version: env!("CARGO_PKG_VERSION"),
author: "Parity <admin@parity.io>",
description: "Deprecation notice for Parity Wallet",
icon_url: "icon.png",
}
}
}
#[test]
fn test_js() {
parity_dapps_glue::js::build(env!("CARGO_MANIFEST_DIR"), "build");
}

View File

@ -1,20 +0,0 @@
[package]
description = "Ethcore Parity UI"
homepage = "http://parity.io"
license = "GPL-3.0"
name = "parity-ui"
version = "1.12.0"
authors = ["Parity Technologies <admin@parity.io>"]
[build-dependencies]
rustc_version = "0.2"
[dependencies]
parity-ui-dev = { git = "https://github.com/parity-js/shell.git", rev = "eecaadcb9e421bce31e91680d14a20bbd38f92a2", optional = true }
parity-ui-old-dev = { git = "https://github.com/parity-js/dapp-wallet.git", rev = "65deb02e7c007a0fd8aab0c089c93e3fd1de6f87", optional = true }
parity-ui-precompiled = { git = "https://github.com/js-dist-paritytech/parity-master-1-10-shell.git", rev="bd25b41cd642c6b822d820dded3aa601a29aa079", optional = true }
parity-ui-old-precompiled = { git = "https://github.com/js-dist-paritytech/parity-master-1-10-wallet.git", rev="4b6f112412716cd05123d32eeb7fda448288a6c6", optional = true }
[features]
no-precompiled-js = ["parity-ui-dev", "parity-ui-old-dev"]
use-precompiled-js = ["parity-ui-precompiled", "parity-ui-old-precompiled"]

View File

@ -1,45 +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://www.gnu.org/licenses/>.
#[cfg(feature = "parity-ui-dev")]
mod inner {
extern crate parity_ui_dev;
pub use self::parity_ui_dev::*;
}
#[cfg(feature = "parity-ui-precompiled")]
mod inner {
extern crate parity_ui_precompiled;
pub use self::parity_ui_precompiled::*;
}
#[cfg(feature = "parity-ui-old-dev")]
pub mod old {
extern crate parity_ui_old_dev;
pub use self::parity_ui_old_dev::*;
}
#[cfg(feature = "parity-ui-old-precompiled")]
pub mod old {
extern crate parity_ui_old_precompiled;
pub use self::parity_ui_old_precompiled::*;
}
pub use self::inner::*;

View File

@ -26,10 +26,6 @@ usage! {
// Arguments must start with arg_ // Arguments must start with arg_
// Flags must start with flag_ // Flags must start with flag_
CMD cmd_ui {
"Manage ui",
}
CMD cmd_dapp CMD cmd_dapp
{ {
"Manage dapps", "Manage dapps",
@ -376,35 +372,10 @@ usage! {
"Provide a file containing passwords for unlocking accounts (signer, private account, validators).", "Provide a file containing passwords for unlocking accounts (signer, private account, validators).",
["UI options"] ["UI options"]
FLAG flag_force_ui: (bool) = false, or |c: &Config| c.ui.as_ref()?.force.clone(),
"--force-ui",
"Enable Trusted UI WebSocket endpoint, even when --unlock is in use.",
FLAG flag_no_ui: (bool) = false, or |c: &Config| c.ui.as_ref()?.disable.clone(),
"--no-ui",
"Disable Trusted UI WebSocket endpoint.",
// NOTE [todr] For security reasons don't put this to config files
FLAG flag_ui_no_validation: (bool) = false, or |_| None,
"--ui-no-validation",
"Disable Origin and Host headers validation for Trusted UI. WARNING: INSECURE. Used only for development.",
ARG arg_ui_interface: (String) = "local", or |c: &Config| c.ui.as_ref()?.interface.clone(),
"--ui-interface=[IP]",
"Specify the hostname portion of the Trusted UI server, IP should be an interface's IP address, or local.",
ARG arg_ui_hosts: (String) = "none", or |c: &Config| c.ui.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")),
"--ui-hosts=[HOSTS]",
"List of allowed Host header values. This option will validate the Host header sent by the browser, it is additional security against some attack vectors. Special options: \"all\", \"none\",.",
ARG arg_ui_path: (String) = "$BASE/signer", or |c: &Config| c.ui.as_ref()?.path.clone(), ARG arg_ui_path: (String) = "$BASE/signer", or |c: &Config| c.ui.as_ref()?.path.clone(),
"--ui-path=[PATH]", "--ui-path=[PATH]",
"Specify directory where Trusted UIs tokens should be stored.", "Specify directory where Trusted UIs tokens should be stored.",
ARG arg_ui_port: (u16) = 8180u16, or |c: &Config| c.ui.as_ref()?.port.clone(),
"--ui-port=[PORT]",
"Specify the port of Trusted UI server.",
["Networking options"] ["Networking options"]
FLAG flag_no_warp: (bool) = false, or |c: &Config| c.network.as_ref()?.warp.clone().map(|w| !w), FLAG flag_no_warp: (bool) = false, or |c: &Config| c.network.as_ref()?.warp.clone().map(|w| !w),
"--no-warp", "--no-warp",
@ -948,6 +919,30 @@ usage! {
"--public-node", "--public-node",
"Does nothing; Public node is removed from Parity.", "Does nothing; Public node is removed from Parity.",
FLAG flag_force_ui: (bool) = false, or |_| None,
"--force-ui",
"Does nothing; UI is now a separate project.",
FLAG flag_no_ui: (bool) = false, or |_| None,
"--no-ui",
"Does nothing; UI is now a separate project.",
FLAG flag_ui_no_validation: (bool) = false, or |_| None,
"--ui-no-validation",
"Does nothing; UI is now a separate project.",
ARG arg_ui_interface: (String) = "local", or |_| None,
"--ui-interface=[IP]",
"Does nothing; UI is now a separate project.",
ARG arg_ui_hosts: (String) = "none", or |_| None,
"--ui-hosts=[HOSTS]",
"Does nothing; UI is now a separate project.",
ARG arg_ui_port: (u16) = 8180u16, or |_| None,
"--ui-port=[PORT]",
"Does nothing; UI is now a separate project.",
ARG arg_dapps_port: (Option<u16>) = None, or |c: &Config| c.dapps.as_ref()?.port.clone(), ARG arg_dapps_port: (Option<u16>) = None, or |c: &Config| c.dapps.as_ref()?.port.clone(),
"--dapps-port=[PORT]", "--dapps-port=[PORT]",
"Dapps server is merged with RPC server. Use --jsonrpc-port.", "Dapps server is merged with RPC server. Use --jsonrpc-port.",
@ -1111,12 +1106,18 @@ struct PrivateTransactions {
#[derive(Default, Debug, PartialEq, Deserialize)] #[derive(Default, Debug, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct Ui { struct Ui {
force: Option<bool>,
disable: Option<bool>,
port: Option<u16>,
interface: Option<String>,
hosts: Option<Vec<String>>,
path: Option<String>, path: Option<String>,
#[serde(rename="force")]
_legacy_force: Option<bool>,
#[serde(rename="disable")]
_legacy_disable: Option<bool>,
#[serde(rename="port")]
_legacy_port: Option<u16>,
#[serde(rename="interface")]
_legacy_interface: Option<String>,
#[serde(rename="hosts")]
_legacy_hosts: Option<Vec<String>>,
} }
#[derive(Default, Debug, PartialEq, Deserialize)] #[derive(Default, Debug, PartialEq, Deserialize)]
@ -1404,15 +1405,13 @@ mod tests {
let args = Args::parse(&["parity", "--secretstore-nodes", "abc@127.0.0.1:3333,cde@10.10.10.10:4444"]).unwrap(); let args = Args::parse(&["parity", "--secretstore-nodes", "abc@127.0.0.1:3333,cde@10.10.10.10:4444"]).unwrap();
assert_eq!(args.arg_secretstore_nodes, "abc@127.0.0.1:3333,cde@10.10.10.10:4444"); assert_eq!(args.arg_secretstore_nodes, "abc@127.0.0.1:3333,cde@10.10.10.10:4444");
let args = Args::parse(&["parity", "--password", "~/.safe/1", "--password", "~/.safe/2", "--ui-port", "8123", "ui"]).unwrap(); let args = Args::parse(&["parity", "--password", "~/.safe/1", "--password", "~/.safe/2", "--ui-port", "8123"]).unwrap();
assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]); assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]);
assert_eq!(args.arg_ui_port, 8123); assert_eq!(args.arg_ui_port, 8123);
assert_eq!(args.cmd_ui, true);
let args = Args::parse(&["parity", "--password", "~/.safe/1,~/.safe/2", "--ui-port", "8123", "ui"]).unwrap(); let args = Args::parse(&["parity", "--password", "~/.safe/1,~/.safe/2", "--ui-port", "8123"]).unwrap();
assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]); assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]);
assert_eq!(args.arg_ui_port, 8123); assert_eq!(args.arg_ui_port, 8123);
assert_eq!(args.cmd_ui, true);
} }
#[test] #[test]
@ -1476,7 +1475,6 @@ mod tests {
// then // then
assert_eq!(args, Args { assert_eq!(args, Args {
// Commands // Commands
cmd_ui: false,
cmd_dapp: false, cmd_dapp: false,
cmd_daemon: false, cmd_daemon: false,
cmd_account: false, cmd_account: false,
@ -1566,7 +1564,7 @@ mod tests {
flag_force_ui: false, flag_force_ui: false,
flag_no_ui: false, flag_no_ui: false,
arg_ui_port: 8180u16, arg_ui_port: 8180u16,
arg_ui_interface: "127.0.0.1".into(), arg_ui_interface: "local".into(),
arg_ui_hosts: "none".into(), arg_ui_hosts: "none".into(),
arg_ui_path: "$HOME/.parity/signer".into(), arg_ui_path: "$HOME/.parity/signer".into(),
flag_ui_no_validation: false, flag_ui_no_validation: false,
@ -1820,12 +1818,12 @@ mod tests {
fast_unlock: None, fast_unlock: None,
}), }),
ui: Some(Ui { ui: Some(Ui {
force: None,
disable: Some(true),
port: None,
interface: None,
hosts: None,
path: None, path: None,
_legacy_force: None,
_legacy_disable: Some(true),
_legacy_port: None,
_legacy_interface: None,
_legacy_hosts: None,
}), }),
network: Some(Network { network: Some(Network {
warp: Some(false), warp: Some(false),

View File

@ -20,7 +20,6 @@ use std::net::SocketAddr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::cmp; use std::cmp;
use std::str::FromStr;
use cli::{Args, ArgsError}; use cli::{Args, ArgsError};
use hash::keccak; use hash::keccak;
use ethereum_types::{U256, H256, Address}; use ethereum_types::{U256, H256, Address};
@ -34,7 +33,7 @@ use ethcore::miner::{stratum, MinerOptions};
use ethcore::verification::queue::VerifierSettings; use ethcore::verification::queue::VerifierSettings;
use miner::pool; use miner::pool;
use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration}; use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration};
use parity_rpc::NetworkSettings; use parity_rpc::NetworkSettings;
use cache::CacheConfig; use cache::CacheConfig;
use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization, passwords_from_files}; use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_queue_strategy, to_queue_penalization, passwords_from_files};
@ -65,7 +64,7 @@ pub enum Cmd {
Account(AccountCmd), Account(AccountCmd),
ImportPresaleWallet(ImportWallet), ImportPresaleWallet(ImportWallet),
Blockchain(BlockchainCmd), Blockchain(BlockchainCmd),
SignerToken(WsConfiguration, UiConfiguration, LogConfig), SignerToken(WsConfiguration, LogConfig),
SignerSign { SignerSign {
id: Option<usize>, id: Option<usize>,
pwfile: Option<PathBuf>, pwfile: Option<PathBuf>,
@ -130,7 +129,6 @@ impl Configuration {
let http_conf = self.http_config()?; let http_conf = self.http_config()?;
let ipc_conf = self.ipc_config()?; let ipc_conf = self.ipc_config()?;
let net_conf = self.net_config()?; let net_conf = self.net_config()?;
let ui_conf = self.ui_config();
let network_id = self.network_id(); let network_id = self.network_id();
let cache_config = self.cache_config(); let cache_config = self.cache_config();
let tracing = self.args.arg_tracing.parse()?; let tracing = self.args.arg_tracing.parse()?;
@ -150,7 +148,7 @@ impl Configuration {
let authfile = ::signer::codes_path(&ws_conf.signer_path); let authfile = ::signer::codes_path(&ws_conf.signer_path);
if self.args.cmd_signer_new_token { if self.args.cmd_signer_new_token {
Cmd::SignerToken(ws_conf, ui_conf, logger_config.clone()) Cmd::SignerToken(ws_conf, logger_config.clone())
} else if self.args.cmd_signer_sign { } else if self.args.cmd_signer_sign {
let pwfile = self.accounts_config()?.password_files.first().map(|pwfile| { let pwfile = self.accounts_config()?.password_files.first().map(|pwfile| {
PathBuf::from(pwfile) PathBuf::from(pwfile)
@ -381,13 +379,11 @@ impl Configuration {
net_settings: self.network_settings()?, net_settings: self.network_settings()?,
dapps_conf: dapps_conf, dapps_conf: dapps_conf,
ipfs_conf: ipfs_conf, ipfs_conf: ipfs_conf,
ui_conf: ui_conf,
secretstore_conf: secretstore_conf, secretstore_conf: secretstore_conf,
private_provider_conf: private_provider_conf, private_provider_conf: private_provider_conf,
private_encryptor_conf: private_enc_conf, private_encryptor_conf: private_enc_conf,
private_tx_enabled, private_tx_enabled,
dapp: self.dapp_to_open()?, dapp: self.dapp_to_open()?,
ui: self.args.cmd_ui,
name: self.args.arg_identity, name: self.args.arg_identity,
custom_bootnodes: self.args.arg_bootnodes.is_some(), custom_bootnodes: self.args.arg_bootnodes.is_some(),
no_periodic_snapshot: self.args.flag_no_periodic_snapshot, no_periodic_snapshot: self.args.flag_no_periodic_snapshot,
@ -588,29 +584,11 @@ impl Configuration {
}) })
} }
fn ui_port(&self) -> u16 {
self.args.arg_ports_shift + self.args.arg_ui_port
}
fn ntp_servers(&self) -> Vec<String> { fn ntp_servers(&self) -> Vec<String> {
self.args.arg_ntp_servers.split(",").map(str::to_owned).collect() self.args.arg_ntp_servers.split(",").map(str::to_owned).collect()
} }
fn ui_config(&self) -> UiConfiguration {
let ui = self.ui_enabled();
UiConfiguration {
enabled: ui.enabled,
interface: self.ui_interface(),
port: self.ui_port(),
hosts: self.ui_hosts(),
info_page_only: ui.info_page_only,
}
}
fn dapps_config(&self) -> DappsConfiguration { fn dapps_config(&self) -> DappsConfiguration {
let dev_ui = if self.args.flag_ui_no_validation { vec![("127.0.0.1".to_owned(), 3000)] } else { vec![] };
let ui_port = self.ui_port();
DappsConfiguration { DappsConfiguration {
enabled: self.dapps_enabled(), enabled: self.dapps_enabled(),
dapps_path: PathBuf::from(self.directories().dapps), dapps_path: PathBuf::from(self.directories().dapps),
@ -619,31 +597,6 @@ impl Configuration {
} else { } else {
vec![] vec![]
}, },
extra_embed_on: {
let mut extra_embed = dev_ui.clone();
match self.ui_hosts() {
// In case host validation is disabled allow all frame ancestors
None => {
// NOTE Chrome does not seem to support "*:<port>"
// we use `http(s)://*:<port>` instead.
extra_embed.push(("http://*".to_owned(), ui_port));
extra_embed.push(("https://*".to_owned(), ui_port));
},
Some(hosts) => extra_embed.extend(hosts.into_iter().filter_map(|host| {
let mut it = host.split(":");
let host = it.next();
let port = it.next().and_then(|v| u16::from_str(v).ok());
match (host, port) {
(Some(host), Some(port)) => Some((host.into(), port)),
(Some(host), None) => Some((host.into(), ui_port)),
_ => None,
}
})),
}
extra_embed
},
extra_script_src: dev_ui,
} }
} }
@ -863,10 +816,6 @@ impl Configuration {
Some(hosts) Some(hosts)
} }
fn ui_hosts(&self) -> Option<Vec<String>> {
self.hosts(&self.args.arg_ui_hosts, &self.ui_interface())
}
fn rpc_hosts(&self) -> Option<Vec<String>> { fn rpc_hosts(&self) -> Option<Vec<String>> {
self.hosts(&self.args.arg_jsonrpc_hosts, &self.rpc_interface()) self.hosts(&self.args.arg_jsonrpc_hosts, &self.rpc_interface())
} }
@ -876,7 +825,7 @@ impl Configuration {
} }
fn ws_origins(&self) -> Option<Vec<String>> { fn ws_origins(&self) -> Option<Vec<String>> {
if self.args.flag_unsafe_expose || self.args.flag_ui_no_validation { if self.args.flag_unsafe_expose {
return None; return None;
} }
@ -925,7 +874,6 @@ impl Configuration {
} }
fn ws_config(&self) -> Result<WsConfiguration, String> { fn ws_config(&self) -> Result<WsConfiguration, String> {
let ui = self.ui_config();
let http = self.http_config()?; let http = self.http_config()?;
let support_token_api = let support_token_api =
@ -941,7 +889,6 @@ impl Configuration {
origins: self.ws_origins(), origins: self.ws_origins(),
signer_path: self.directories().signer.into(), signer_path: self.directories().signer.into(),
support_token_api, support_token_api,
ui_address: ui.address(),
dapps_address: http.address(), dapps_address: http.address(),
max_connections: self.args.arg_ws_max_connections, max_connections: self.args.arg_ws_max_connections,
}; };
@ -1065,10 +1012,6 @@ impl Configuration {
}.into() }.into()
} }
fn ui_interface(&self) -> String {
self.interface(&self.args.arg_ui_interface)
}
fn rpc_interface(&self) -> String { fn rpc_interface(&self) -> String {
let rpc_interface = self.args.arg_rpcaddr.clone().unwrap_or(self.args.arg_jsonrpc_interface.clone()); let rpc_interface = self.args.arg_rpcaddr.clone().unwrap_or(self.args.arg_jsonrpc_interface.clone());
self.interface(&rpc_interface) self.interface(&rpc_interface)
@ -1184,24 +1127,6 @@ impl Configuration {
into_secretstore_service_contract_address(self.args.arg_secretstore_doc_sretr_contract.as_ref()) into_secretstore_service_contract_address(self.args.arg_secretstore_doc_sretr_contract.as_ref())
} }
fn ui_enabled(&self) -> UiEnabled {
if self.args.flag_force_ui {
return UiEnabled {
enabled: true,
info_page_only: false,
};
}
let ui_disabled = self.args.arg_unlock.is_some() ||
self.args.flag_geth ||
self.args.flag_no_ui;
return UiEnabled {
enabled: (self.args.cmd_ui || !ui_disabled) && cfg!(feature = "ui-enabled"),
info_page_only: !self.args.cmd_ui,
}
}
fn verifier_settings(&self) -> VerifierSettings { fn verifier_settings(&self) -> VerifierSettings {
let mut settings = VerifierSettings::default(); let mut settings = VerifierSettings::default();
settings.scale_verifiers = self.args.flag_scale_verifiers; settings.scale_verifiers = self.args.flag_scale_verifiers;
@ -1220,12 +1145,6 @@ impl Configuration {
} }
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
struct UiEnabled {
pub enabled: bool,
pub info_page_only: bool,
}
fn into_secretstore_service_contract_address(s: &str) -> Result<Option<SecretStoreContractAddress>, String> { fn into_secretstore_service_contract_address(s: &str) -> Result<Option<SecretStoreContractAddress>, String> {
match s { match s {
"none" => Ok(None), "none" => Ok(None),
@ -1254,7 +1173,7 @@ mod tests {
use helpers::{default_network_config}; use helpers::{default_network_config};
use params::SpecType; use params::SpecType;
use presale::ImportWallet; use presale::ImportWallet;
use rpc::{WsConfiguration, UiConfiguration}; use rpc::WsConfiguration;
use rpc_apis::ApiSet; use rpc_apis::ApiSet;
use run::RunCmd; use run::RunCmd;
@ -1438,16 +1357,9 @@ mod tests {
origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]), origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]),
hosts: Some(vec![]), hosts: Some(vec![]),
signer_path: expected.into(), signer_path: expected.into(),
ui_address: Some("127.0.0.1:8180".into()),
dapps_address: Some("127.0.0.1:8545".into()), dapps_address: Some("127.0.0.1:8545".into()),
support_token_api: true, support_token_api: true,
max_connections: 100, max_connections: 100,
}, UiConfiguration {
enabled: true,
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
info_page_only: true,
}, LogConfig { }, LogConfig {
color: true, color: true,
mode: None, mode: None,
@ -1516,12 +1428,10 @@ mod tests {
net_settings: Default::default(), net_settings: Default::default(),
dapps_conf: Default::default(), dapps_conf: Default::default(),
ipfs_conf: Default::default(), ipfs_conf: Default::default(),
ui_conf: Default::default(),
secretstore_conf: Default::default(), secretstore_conf: Default::default(),
private_provider_conf: Default::default(), private_provider_conf: Default::default(),
private_encryptor_conf: Default::default(), private_encryptor_conf: Default::default(),
private_tx_enabled: false, private_tx_enabled: false,
ui: false,
dapp: None, dapp: None,
name: "".into(), name: "".into(),
custom_bootnodes: false, custom_bootnodes: false,
@ -1704,49 +1614,6 @@ mod tests {
assert_eq!(conf2.ipfs_cors(), Some(vec!["http://parity.io".into(),"http://something.io".into()])); assert_eq!(conf2.ipfs_cors(), Some(vec!["http://parity.io".into(),"http://something.io".into()]));
} }
#[test]
fn should_disable_signer_in_geth_compat() {
// given
// when
let conf0 = parse(&["parity", "--geth"]);
let conf1 = parse(&["parity", "--geth", "--force-ui"]);
let conf2 = parse(&["parity", "--geth", "ui"]);
let conf3 = parse(&["parity"]);
// then
assert_eq!(conf0.ui_enabled(), UiEnabled {
enabled: false,
info_page_only: true,
});
assert_eq!(conf1.ui_enabled(), UiEnabled {
enabled: true,
info_page_only: false,
});
assert_eq!(conf2.ui_enabled(), UiEnabled {
enabled: true,
info_page_only: false,
});
assert_eq!(conf3.ui_enabled(), UiEnabled {
enabled: true,
info_page_only: true,
});
}
#[test]
fn should_disable_signer_when_account_is_unlocked() {
// given
// when
let conf0 = parse(&["parity", "--unlock", "0x0"]);
// then
assert_eq!(conf0.ui_enabled(), UiEnabled {
enabled: false,
info_page_only: true,
});
}
#[test] #[test]
fn should_parse_ui_configuration() { fn should_parse_ui_configuration() {
// given // given
@ -1757,69 +1624,22 @@ mod tests {
let conf2 = parse(&["parity", "--ui-path=signer", "--ui-port", "3123"]); let conf2 = parse(&["parity", "--ui-path=signer", "--ui-port", "3123"]);
let conf3 = parse(&["parity", "--ui-path=signer", "--ui-interface", "test"]); let conf3 = parse(&["parity", "--ui-path=signer", "--ui-interface", "test"]);
let conf4 = parse(&["parity", "--ui-path=signer", "--force-ui"]); let conf4 = parse(&["parity", "--ui-path=signer", "--force-ui"]);
let conf5 = parse(&["parity", "--ui-path=signer", "ui"]);
// then // then
assert_eq!(conf0.directories().signer, "signer".to_owned()); assert_eq!(conf0.directories().signer, "signer".to_owned());
assert_eq!(conf0.ui_config(), UiConfiguration {
enabled: true,
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
info_page_only: true,
});
assert!(conf1.ws_config().unwrap().hosts.is_some()); assert!(conf1.ws_config().unwrap().hosts.is_some());
assert_eq!(conf1.ws_config().unwrap().origins, None); assert_eq!(conf1.ws_config().unwrap().origins, Some(vec!["parity://*".into(), "chrome-extension://*".into(), "moz-extension://*".into()]));
assert_eq!(conf1.directories().signer, "signer".to_owned()); assert_eq!(conf1.directories().signer, "signer".to_owned());
assert_eq!(conf1.ui_config(), UiConfiguration {
enabled: true,
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
info_page_only: true,
});
assert_eq!(conf1.dapps_config().extra_embed_on, vec![("127.0.0.1".to_owned(), 3000)]);
assert!(conf2.ws_config().unwrap().hosts.is_some()); assert!(conf2.ws_config().unwrap().hosts.is_some());
assert_eq!(conf2.directories().signer, "signer".to_owned()); assert_eq!(conf2.directories().signer, "signer".to_owned());
assert_eq!(conf2.ui_config(), UiConfiguration {
enabled: true,
interface: "127.0.0.1".into(),
port: 3123,
hosts: Some(vec![]),
info_page_only: true,
});
assert!(conf3.ws_config().unwrap().hosts.is_some()); assert!(conf3.ws_config().unwrap().hosts.is_some());
assert_eq!(conf3.directories().signer, "signer".to_owned()); assert_eq!(conf3.directories().signer, "signer".to_owned());
assert_eq!(conf3.ui_config(), UiConfiguration {
enabled: true,
interface: "test".into(),
port: 8180,
hosts: Some(vec![]),
info_page_only: true,
});
assert!(conf4.ws_config().unwrap().hosts.is_some()); assert!(conf4.ws_config().unwrap().hosts.is_some());
assert_eq!(conf4.directories().signer, "signer".to_owned()); assert_eq!(conf4.directories().signer, "signer".to_owned());
assert_eq!(conf4.ui_config(), UiConfiguration {
enabled: true,
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
info_page_only: false,
});
assert!(conf5.ws_config().unwrap().hosts.is_some());
assert_eq!(conf5.directories().signer, "signer".to_owned());
assert_eq!(conf5.ui_config(), UiConfiguration {
enabled: true,
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
info_page_only: false,
});
} }
#[test] #[test]
@ -1976,7 +1796,6 @@ mod tests {
assert_eq!(conf0.network_settings().unwrap().rpc_port, 8546); assert_eq!(conf0.network_settings().unwrap().rpc_port, 8546);
assert_eq!(conf0.http_config().unwrap().port, 8546); assert_eq!(conf0.http_config().unwrap().port, 8546);
assert_eq!(conf0.ws_config().unwrap().port, 8547); assert_eq!(conf0.ws_config().unwrap().port, 8547);
assert_eq!(conf0.ui_config().port, 8181);
assert_eq!(conf0.secretstore_config().unwrap().port, 8084); assert_eq!(conf0.secretstore_config().unwrap().port, 8084);
assert_eq!(conf0.secretstore_config().unwrap().http_port, 8083); assert_eq!(conf0.secretstore_config().unwrap().http_port, 8083);
assert_eq!(conf0.ipfs_config().port, 5002); assert_eq!(conf0.ipfs_config().port, 5002);
@ -1987,7 +1806,6 @@ mod tests {
assert_eq!(conf1.network_settings().unwrap().rpc_port, 8545); assert_eq!(conf1.network_settings().unwrap().rpc_port, 8545);
assert_eq!(conf1.http_config().unwrap().port, 8545); assert_eq!(conf1.http_config().unwrap().port, 8545);
assert_eq!(conf1.ws_config().unwrap().port, 8547); assert_eq!(conf1.ws_config().unwrap().port, 8547);
assert_eq!(conf1.ui_config().port, 8181);
assert_eq!(conf1.secretstore_config().unwrap().port, 8084); assert_eq!(conf1.secretstore_config().unwrap().port, 8084);
assert_eq!(conf1.secretstore_config().unwrap().http_port, 8083); assert_eq!(conf1.secretstore_config().unwrap().http_port, 8083);
assert_eq!(conf1.ipfs_config().port, 5002); assert_eq!(conf1.ipfs_config().port, 5002);
@ -2007,8 +1825,6 @@ mod tests {
assert_eq!(&conf0.ws_config().unwrap().interface, "0.0.0.0"); assert_eq!(&conf0.ws_config().unwrap().interface, "0.0.0.0");
assert_eq!(conf0.ws_config().unwrap().hosts, None); assert_eq!(conf0.ws_config().unwrap().hosts, None);
assert_eq!(conf0.ws_config().unwrap().origins, None); assert_eq!(conf0.ws_config().unwrap().origins, None);
assert_eq!(&conf0.ui_config().interface, "0.0.0.0");
assert_eq!(conf0.ui_config().hosts, None);
assert_eq!(&conf0.secretstore_config().unwrap().interface, "0.0.0.0"); assert_eq!(&conf0.secretstore_config().unwrap().interface, "0.0.0.0");
assert_eq!(&conf0.secretstore_config().unwrap().http_interface, "0.0.0.0"); assert_eq!(&conf0.secretstore_config().unwrap().http_interface, "0.0.0.0");
assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0"); assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0");

View File

@ -39,8 +39,6 @@ pub struct Configuration {
pub enabled: bool, pub enabled: bool,
pub dapps_path: PathBuf, pub dapps_path: PathBuf,
pub extra_dapps: Vec<PathBuf>, pub extra_dapps: Vec<PathBuf>,
pub extra_embed_on: Vec<(String, u16)>,
pub extra_script_src: Vec<(String, u16)>,
} }
impl Default for Configuration { impl Default for Configuration {
@ -50,8 +48,6 @@ impl Default for Configuration {
enabled: true, enabled: true,
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(), dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
extra_dapps: vec![], extra_dapps: vec![],
extra_embed_on: vec![],
extra_script_src: vec![],
} }
} }
} }
@ -163,8 +159,6 @@ pub struct Dependencies {
pub fetch: FetchClient, pub fetch: FetchClient,
pub pool: CpuPool, pub pool: CpuPool,
pub signer: Arc<SignerService>, pub signer: Arc<SignerService>,
pub ui_address: Option<(String, u16)>,
pub info_page_only: bool,
} }
pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Middleware>, String> { pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Middleware>, String> {
@ -177,19 +171,6 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Mi
configuration.dapps_path, configuration.dapps_path,
configuration.extra_dapps, configuration.extra_dapps,
rpc::DAPPS_DOMAIN, rpc::DAPPS_DOMAIN,
configuration.extra_embed_on,
configuration.extra_script_src,
).map(Some)
}
pub fn new_ui(enabled: bool, deps: Dependencies) -> Result<Option<Middleware>, String> {
if !enabled {
return Ok(None);
}
server::ui_middleware(
deps,
rpc::DAPPS_DOMAIN,
).map(Some) ).map(Some)
} }
@ -215,19 +196,10 @@ mod server {
_dapps_path: PathBuf, _dapps_path: PathBuf,
_extra_dapps: Vec<PathBuf>, _extra_dapps: Vec<PathBuf>,
_dapps_domain: &str, _dapps_domain: &str,
_extra_embed_on: Vec<(String, u16)>,
_extra_script_src: Vec<(String, u16)>,
) -> Result<Middleware, String> { ) -> Result<Middleware, String> {
Err("Your Parity version has been compiled without WebApps support.".into()) Err("Your Parity version has been compiled without WebApps support.".into())
} }
pub fn ui_middleware(
_deps: Dependencies,
_dapps_domain: &str,
) -> Result<Middleware, String> {
Err("Your Parity version has been compiled without UI support.".into())
}
pub fn service(_: &Option<Middleware>) -> Option<Arc<rpc_apis::DappsService>> { pub fn service(_: &Option<Middleware>) -> Option<Arc<rpc_apis::DappsService>> {
None None
} }
@ -249,8 +221,6 @@ mod server {
dapps_path: PathBuf, dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>, extra_dapps: Vec<PathBuf>,
dapps_domain: &str, dapps_domain: &str,
extra_embed_on: Vec<(String, u16)>,
extra_script_src: Vec<(String, u16)>,
) -> Result<Middleware, String> { ) -> Result<Middleware, String> {
let signer = deps.signer; let signer = deps.signer;
let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token)); let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token));
@ -258,9 +228,6 @@ mod server {
Ok(parity_dapps::Middleware::dapps( Ok(parity_dapps::Middleware::dapps(
deps.pool, deps.pool,
deps.node_health, deps.node_health,
deps.ui_address,
extra_embed_on,
extra_script_src,
dapps_path, dapps_path,
extra_dapps, extra_dapps,
dapps_domain, dapps_domain,
@ -271,21 +238,6 @@ mod server {
)) ))
} }
pub fn ui_middleware(
deps: Dependencies,
dapps_domain: &str,
) -> Result<Middleware, String> {
Ok(parity_dapps::Middleware::ui(
deps.pool,
deps.node_health,
dapps_domain,
deps.contract_client,
deps.sync_status,
deps.fetch,
deps.info_page_only,
))
}
pub fn service(middleware: &Option<Middleware>) -> Option<Arc<rpc_apis::DappsService>> { pub fn service(middleware: &Option<Middleware>) -> Option<Arc<rpc_apis::DappsService>> {
middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper { middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper {
endpoints: m.endpoints().clone(), endpoints: m.endpoints().clone(),

View File

@ -118,15 +118,13 @@ mod user_defaults;
mod whisper; mod whisper;
mod db; mod db;
use std::net::{TcpListener};
use std::io::BufReader; use std::io::BufReader;
use std::fs::File; use std::fs::File;
use ansi_term::Style;
use hash::keccak_buffer; use hash::keccak_buffer;
use cli::Args; use cli::Args;
use configuration::{Cmd, Execute}; use configuration::{Cmd, Execute};
use deprecated::find_deprecated; use deprecated::find_deprecated;
use ethcore_logger::{Config as LogConfig, setup_log}; use ethcore_logger::setup_log;
pub use self::configuration::Configuration; pub use self::configuration::Configuration;
pub use self::run::RunningClient; pub use self::run::RunningClient;
@ -195,24 +193,6 @@ fn execute<Cr, Rr>(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res
match command.cmd { match command.cmd {
Cmd::Run(run_cmd) => { Cmd::Run(run_cmd) => {
if run_cmd.ui_conf.enabled && !run_cmd.ui_conf.info_page_only {
warn!("{}", Style::new().bold().paint("Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead."));
warn!("{}", Style::new().bold().paint("Standalone Parity UI: https://github.com/Parity-JS/shell/releases"));
}
if run_cmd.ui && run_cmd.dapps_conf.enabled {
// Check if Parity is already running
let addr = format!("{}:{}", run_cmd.ui_conf.interface, run_cmd.ui_conf.port);
if !TcpListener::bind(&addr as &str).is_ok() {
return open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config).map(|_| ExecutionAction::Instant(None));
}
}
// start ui
if run_cmd.ui {
open_ui(&run_cmd.ws_conf, &run_cmd.ui_conf, &run_cmd.logger_config)?;
}
if let Some(ref dapp) = run_cmd.dapp { if let Some(ref dapp) = run_cmd.dapp {
open_dapp(&run_cmd.dapps_conf, &run_cmd.http_conf, dapp)?; open_dapp(&run_cmd.dapps_conf, &run_cmd.http_conf, dapp)?;
} }
@ -225,7 +205,7 @@ fn execute<Cr, Rr>(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res
Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| ExecutionAction::Instant(Some(s))), Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| ExecutionAction::Instant(Some(s))),
Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| ExecutionAction::Instant(Some(s))), Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| ExecutionAction::Instant(Some(s))),
Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| ExecutionAction::Instant(None)), Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| ExecutionAction::Instant(None)),
Cmd::SignerToken(ws_conf, ui_conf, logger_config) => signer::execute(ws_conf, ui_conf, logger_config).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerToken(ws_conf, logger_config) => signer::execute(ws_conf, logger_config).map(|s| ExecutionAction::Instant(Some(s))),
Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| ExecutionAction::Instant(Some(s))),
Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| ExecutionAction::Instant(Some(s))),
Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| ExecutionAction::Instant(Some(s))), Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| ExecutionAction::Instant(Some(s))),
@ -257,19 +237,6 @@ pub fn start<Cr, Rr>(conf: Configuration, on_client_rq: Cr, on_updater_rq: Rr) -
execute(conf.into_command()?, on_client_rq, on_updater_rq) execute(conf.into_command()?, on_client_rq, on_updater_rq)
} }
fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<(), String> {
if !ui_conf.enabled {
return Err("Cannot use UI command with UI turned off.".into())
}
let token = signer::generate_token_and_url(ws_conf, ui_conf, logger_config)?;
// Open a browser
url::open(&token.url).map_err(|e| format!("{}", e))?;
// Print a message
println!("{}", token.message);
Ok(())
}
fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> { fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> {
if !dapps_conf.enabled { if !dapps_conf.enabled {
return Err("Cannot use DAPP command with Dapps turned off.".into()) return Err("Cannot use DAPP command with Dapps turned off.".into())

View File

@ -68,58 +68,6 @@ impl Default for HttpConfiguration {
} }
} }
#[derive(Debug, PartialEq, Clone)]
pub struct UiConfiguration {
pub enabled: bool,
pub interface: String,
pub port: u16,
pub hosts: Option<Vec<String>>,
pub info_page_only: bool,
}
impl UiConfiguration {
pub fn address(&self) -> Option<rpc::Host> {
address(self.enabled, &self.interface, self.port, &self.hosts)
}
pub fn redirection_address(&self) -> Option<(String, u16)> {
self.address().map(|host| {
let mut it = host.split(':');
let hostname: Option<String> = it.next().map(|s| s.to_owned());
let port: Option<u16> = it.next().and_then(|s| s.parse().ok());
(hostname.unwrap_or_else(|| "localhost".into()), port.unwrap_or(8180))
})
}
}
impl From<UiConfiguration> for HttpConfiguration {
fn from(conf: UiConfiguration) -> Self {
HttpConfiguration {
enabled: conf.enabled,
interface: conf.interface,
port: conf.port,
apis: rpc_apis::ApiSet::UnsafeContext,
cors: Some(vec![]),
hosts: conf.hosts,
server_threads: 1,
processing_threads: 0,
}
}
}
impl Default for UiConfiguration {
fn default() -> Self {
UiConfiguration {
enabled: cfg!(feature = "ui-enabled"),
port: 8180,
interface: "127.0.0.1".into(),
hosts: Some(vec![]),
info_page_only: true,
}
}
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct IpcConfiguration { pub struct IpcConfiguration {
pub enabled: bool, pub enabled: bool,
@ -153,7 +101,6 @@ pub struct WsConfiguration {
pub hosts: Option<Vec<String>>, pub hosts: Option<Vec<String>>,
pub signer_path: PathBuf, pub signer_path: PathBuf,
pub support_token_api: bool, pub support_token_api: bool,
pub ui_address: Option<rpc::Host>,
pub dapps_address: Option<rpc::Host>, pub dapps_address: Option<rpc::Host>,
} }
@ -170,7 +117,6 @@ impl Default for WsConfiguration {
hosts: Some(Vec::new()), hosts: Some(Vec::new()),
signer_path: replace_home(&data_dir, "$BASE/signer").into(), signer_path: replace_home(&data_dir, "$BASE/signer").into(),
support_token_api: true, support_token_api: true,
ui_address: Some("127.0.0.1:8180".into()),
dapps_address: Some("127.0.0.1:8545".into()), dapps_address: Some("127.0.0.1:8545".into()),
} }
} }
@ -225,9 +171,8 @@ pub fn new_ws<D: rpc_apis::Dependencies>(
}; };
let remote = deps.remote.clone(); let remote = deps.remote.clone();
let ui_address = conf.ui_address.clone(); let allowed_origins = into_domains(with_domain(conf.origins, domain, &conf.dapps_address));
let allowed_origins = into_domains(with_domain(conf.origins, domain, &ui_address, &conf.dapps_address)); let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into())));
let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()), &None));
let signer_path; let signer_path;
let path = match conf.support_token_api { let path = match conf.support_token_api {
@ -276,7 +221,7 @@ pub fn new_http<D: rpc_apis::Dependencies>(
let remote = deps.remote.clone(); let remote = deps.remote.clone();
let cors_domains = into_domains(conf.cors); let cors_domains = into_domains(conf.cors);
let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into()), &None)); let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into())));
let start_result = rpc::start_http( let start_result = rpc::start_http(
&addr, &addr,
@ -328,7 +273,7 @@ fn into_domains<T: From<String>>(items: Option<Vec<String>>) -> DomainsValidatio
items.map(|vals| vals.into_iter().map(T::from).collect()).into() items.map(|vals| vals.into_iter().map(T::from).collect()).into()
} }
fn with_domain(items: Option<Vec<String>>, domain: &str, ui_address: &Option<rpc::Host>, dapps_address: &Option<rpc::Host>) -> Option<Vec<String>> { fn with_domain(items: Option<Vec<String>>, domain: &str, dapps_address: &Option<rpc::Host>) -> Option<Vec<String>> {
fn extract_port(s: &str) -> Option<u16> { fn extract_port(s: &str) -> Option<u16> {
s.split(':').nth(1).and_then(|s| s.parse().ok()) s.split(':').nth(1).and_then(|s| s.parse().ok())
} }
@ -347,7 +292,6 @@ fn with_domain(items: Option<Vec<String>>, domain: &str, ui_address: &Option<rpc
} }
}; };
add_hosts(ui_address);
add_hosts(dapps_address); add_hosts(dapps_address);
} }
items.into_iter().collect() items.into_iter().collect()

View File

@ -112,13 +112,11 @@ pub struct RunCmd {
pub net_settings: NetworkSettings, pub net_settings: NetworkSettings,
pub dapps_conf: dapps::Configuration, pub dapps_conf: dapps::Configuration,
pub ipfs_conf: ipfs::Configuration, pub ipfs_conf: ipfs::Configuration,
pub ui_conf: rpc::UiConfiguration,
pub secretstore_conf: secretstore::Configuration, pub secretstore_conf: secretstore::Configuration,
pub private_provider_conf: ProviderConfig, pub private_provider_conf: ProviderConfig,
pub private_encryptor_conf: EncryptorConfig, pub private_encryptor_conf: EncryptorConfig,
pub private_tx_enabled: bool, pub private_tx_enabled: bool,
pub dapp: Option<String>, pub dapp: Option<String>,
pub ui: bool,
pub name: String, pub name: String,
pub custom_bootnodes: bool, pub custom_bootnodes: bool,
pub stratum: Option<stratum::Options>, pub stratum: Option<stratum::Options>,
@ -185,7 +183,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?;
// create dirs used by parity // create dirs used by parity
cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?; cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.acc_conf.unlocked_accounts.len() == 0, cmd.secretstore_conf.enabled)?;
//print out running parity environment //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, &cmd.dapps_conf);
@ -323,13 +321,10 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
fetch: fetch.clone(), fetch: fetch.clone(),
pool: cpu_pool.clone(), pool: cpu_pool.clone(),
signer: signer_service.clone(), signer: signer_service.clone(),
ui_address: cmd.ui_conf.redirection_address(),
info_page_only: cmd.ui_conf.info_page_only,
}) })
}; };
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?;
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
// start RPCs // start RPCs
let dapps_service = dapps::service(&dapps_middleware); let dapps_service = dapps::service(&dapps_middleware);
@ -373,7 +368,6 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
let ws_server = rpc::new_ws(cmd.ws_conf, &dependencies)?; let ws_server = rpc::new_ws(cmd.ws_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, dapps_middleware)?;
let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
let ui_server = rpc::new_http("Parity Wallet (UI)", "ui", cmd.ui_conf.clone().into(), &dependencies, ui_middleware)?;
// the informant // the informant
let informant = Arc::new(Informant::new( let informant = Arc::new(Informant::new(
@ -394,7 +388,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
rpc: rpc_direct, rpc: rpc_direct,
informant, informant,
client, client,
keep_alive: Box::new((event_loop, service, ws_server, http_server, ipc_server, ui_server)), keep_alive: Box::new((event_loop, service, ws_server, http_server, ipc_server)),
} }
}) })
} }
@ -444,7 +438,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?; execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?;
// create dirs used by parity // create dirs used by parity
cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?; cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.acc_conf.unlocked_accounts.len() == 0, cmd.secretstore_conf.enabled)?;
// run in daemon mode // run in daemon mode
if let Some(pid_file) = cmd.daemon { if let Some(pid_file) = cmd.daemon {
@ -756,12 +750,9 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
fetch: fetch.clone(), fetch: fetch.clone(),
pool: cpu_pool.clone(), pool: cpu_pool.clone(),
signer: signer_service.clone(), signer: signer_service.clone(),
ui_address: cmd.ui_conf.redirection_address(),
info_page_only: cmd.ui_conf.info_page_only,
}) })
}; };
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?;
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
let dapps_service = dapps::service(&dapps_middleware); let dapps_service = dapps::service(&dapps_middleware);
let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies { let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies {
@ -807,8 +798,6 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
let ws_server = rpc::new_ws(cmd.ws_conf.clone(), &dependencies)?; let ws_server = rpc::new_ws(cmd.ws_conf.clone(), &dependencies)?;
let ipc_server = rpc::new_ipc(cmd.ipc_conf, &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, dapps_middleware)?;
// the ui server
let ui_server = rpc::new_http("UI WALLET", "ui", cmd.ui_conf.clone().into(), &dependencies, ui_middleware)?;
// secret store key server // secret store key server
let secretstore_deps = secretstore::Dependencies { let secretstore_deps = secretstore::Dependencies {
@ -881,7 +870,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
informant, informant,
client, client,
client_service: Arc::new(service), client_service: Arc::new(service),
keep_alive: Box::new((watcher, updater, ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop)), keep_alive: Box::new((watcher, updater, ws_server, http_server, ipc_server, secretstore_key_server, ipfs_server, event_loop)),
} }
}) })
} }

View File

@ -28,7 +28,6 @@ pub const CODES_FILENAME: &'static str = "authcodes";
pub struct NewToken { pub struct NewToken {
pub token: String, pub token: String,
pub url: String,
pub message: String, pub message: String,
} }
@ -49,45 +48,26 @@ pub fn codes_path(path: &Path) -> PathBuf {
p p
} }
pub fn execute(ws_conf: rpc::WsConfiguration, ui_conf: rpc::UiConfiguration, logger_config: LogConfig) -> Result<String, String> { pub fn execute(ws_conf: rpc::WsConfiguration, logger_config: LogConfig) -> Result<String, String> {
Ok(generate_token_and_url(&ws_conf, &ui_conf, &logger_config)?.message) Ok(generate_token_and_url(&ws_conf, &logger_config)?.message)
} }
pub fn generate_token_and_url(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration, logger_config: &LogConfig) -> Result<NewToken, String> { pub fn generate_token_and_url(ws_conf: &rpc::WsConfiguration, logger_config: &LogConfig) -> Result<NewToken, String> {
let code = generate_new_token(&ws_conf.signer_path, logger_config.color).map_err(|err| format!("Error generating token: {:?}", err))?; let code = generate_new_token(&ws_conf.signer_path, logger_config.color).map_err(|err| format!("Error generating token: {:?}", err))?;
let auth_url = format!("http://{}:{}/#/auth?token={}", ui_conf.interface, ui_conf.port, code);
let colored = |s: String| match logger_config.color { let colored = |s: String| match logger_config.color {
true => format!("{}", White.bold().paint(s)), true => format!("{}", White.bold().paint(s)),
false => s, false => s,
}; };
if !ui_conf.enabled { Ok(NewToken {
return Ok(NewToken { token: code.clone(),
token: code.clone(), message: format!(
url: auth_url.clone(), r#"
message: format!(
r#"
Generated token: Generated token:
{} {}
"#, "#,
colored(code) colored(code)
), ),
})
}
// And print in to the console
Ok(NewToken {
token: code.clone(),
url: auth_url.clone(),
message: format!(
r#"
Open: {}
to authorize your browser.
Or use the generated token:
{}"#,
colored(auth_url),
code
)
}) })
} }