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:
parent
114d4433a9
commit
a5190449da
56
Cargo.lock
generated
56
Cargo.lock
generated
@ -2071,8 +2071,6 @@ dependencies = [
|
||||
"parity-dapps-glue 1.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-hash-fetch 1.12.0",
|
||||
"parity-reactor 0.1.0",
|
||||
"parity-ui 1.12.0",
|
||||
"parity-ui-deprecation 1.10.0",
|
||||
"parity-version 1.12.0",
|
||||
"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)",
|
||||
@ -2283,56 +2281,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "parity-updater"
|
||||
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 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-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-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"
|
||||
|
11
Cargo.toml
11
Cargo.toml
@ -88,16 +88,7 @@ winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] }
|
||||
daemonize = { git = "https://github.com/paritytech/daemonize" }
|
||||
|
||||
[features]
|
||||
default = ["ui-precompiled"]
|
||||
ui = [
|
||||
"ui-enabled",
|
||||
"parity-dapps/ui",
|
||||
]
|
||||
ui-precompiled = [
|
||||
"ui-enabled",
|
||||
"parity-dapps/ui-precompiled",
|
||||
]
|
||||
ui-enabled = ["dapps"]
|
||||
default = ["dapps"]
|
||||
dapps = ["parity-dapps"]
|
||||
json-tests = ["ethcore/json-tests"]
|
||||
test-heavy = ["ethcore/test-heavy"]
|
||||
|
@ -34,8 +34,6 @@ fetch = { path = "../util/fetch" }
|
||||
node-health = { path = "./node-health" }
|
||||
parity-hash-fetch = { path = "../hash-fetch" }
|
||||
parity-reactor = { path = "../util/reactor" }
|
||||
parity-ui = { path = "./ui" }
|
||||
parity-ui-deprecation = { path = "./ui-deprecation" }
|
||||
keccak-hash = { path = "../util/hash" }
|
||||
parity-version = { path = "../util/version" }
|
||||
registrar = { path = "../registrar" }
|
||||
@ -43,7 +41,3 @@ registrar = { path = "../registrar" }
|
||||
[dev-dependencies]
|
||||
env_logger = "0.4"
|
||||
ethcore-devtools = { path = "../devtools" }
|
||||
|
||||
[features]
|
||||
ui = ["parity-ui/no-precompiled-js"]
|
||||
ui-precompiled = ["parity-ui/use-precompiled-js"]
|
||||
|
@ -27,7 +27,6 @@ use mime_guess::Mime;
|
||||
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest, serialize_manifest, Manifest};
|
||||
use handlers::{ContentValidator, ValidatorResponse};
|
||||
use page::{local, PageCache};
|
||||
use Embeddable;
|
||||
|
||||
type OnDone = Box<Fn(Option<local::Dapp>) + Send>;
|
||||
|
||||
@ -124,17 +123,15 @@ pub struct Dapp {
|
||||
id: String,
|
||||
dapps_path: PathBuf,
|
||||
on_done: OnDone,
|
||||
embeddable_on: Embeddable,
|
||||
pool: CpuPool,
|
||||
}
|
||||
|
||||
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 {
|
||||
id,
|
||||
dapps_path,
|
||||
on_done,
|
||||
embeddable_on,
|
||||
pool,
|
||||
}
|
||||
}
|
||||
@ -170,7 +167,6 @@ impl ContentValidator for Dapp {
|
||||
fn validate_and_install(self, response: fetch::Response) -> Result<ValidatorResponse, ValidationError> {
|
||||
let id = self.id.clone();
|
||||
let pool = self.pool;
|
||||
let embeddable_on = self.embeddable_on;
|
||||
let validate = move |dapp_path: PathBuf| {
|
||||
let (file, zip_path) = write_response_and_check_hash(&id, dapp_path.clone(), &format!("{}.zip", id), response)?;
|
||||
trace!(target: "dapps", "Opening dapp bundle at {:?}", zip_path);
|
||||
@ -210,7 +206,7 @@ impl ContentValidator for Dapp {
|
||||
let mut manifest_file = fs::File::create(manifest_path)?;
|
||||
manifest_file.write_all(manifest_str.as_bytes())?;
|
||||
// Create endpoint
|
||||
let endpoint = local::Dapp::new(pool, dapp_path, manifest.into(), PageCache::Enabled, embeddable_on);
|
||||
let endpoint = local::Dapp::new(pool, dapp_path, manifest.into(), PageCache::Enabled);
|
||||
Ok(endpoint)
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,7 @@ use hash_fetch::urlhint::{URLHintContract, URLHint, URLHintResult};
|
||||
use hyper::StatusCode;
|
||||
|
||||
use ethereum_types::H256;
|
||||
use {Embeddable, SyncStatus, random_filename};
|
||||
use {SyncStatus, random_filename};
|
||||
use parking_lot::Mutex;
|
||||
use page::local;
|
||||
use handlers::{ContentHandler, ContentFetcherHandler};
|
||||
@ -50,7 +50,6 @@ pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + 'static = URLHint
|
||||
resolver: R,
|
||||
cache: Arc<Mutex<ContentCache>>,
|
||||
sync: Arc<SyncStatus>,
|
||||
embeddable_on: Embeddable,
|
||||
fetch: F,
|
||||
pool: CpuPool,
|
||||
only_content: bool,
|
||||
@ -78,7 +77,6 @@ impl<R: URLHint + 'static, F: Fetch> ContentFetcher<F, R> {
|
||||
resolver,
|
||||
sync,
|
||||
cache: Arc::new(Mutex::new(ContentCache::default())),
|
||||
embeddable_on: None,
|
||||
fetch,
|
||||
pool,
|
||||
only_content: true,
|
||||
@ -90,38 +88,30 @@ impl<R: URLHint + 'static, F: Fetch> ContentFetcher<F, R> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn embeddable_on(mut self, embeddable_on: Embeddable) -> Self {
|
||||
self.embeddable_on = embeddable_on;
|
||||
self
|
||||
}
|
||||
|
||||
fn not_found(embeddable: Embeddable) -> endpoint::Response {
|
||||
fn not_found() -> endpoint::Response {
|
||||
Box::new(future::ok(ContentHandler::error(
|
||||
StatusCode::NotFound,
|
||||
"Resource Not Found",
|
||||
"Requested resource was not found.",
|
||||
None,
|
||||
embeddable,
|
||||
).into()))
|
||||
}
|
||||
|
||||
fn still_syncing(embeddable: Embeddable) -> endpoint::Response {
|
||||
fn still_syncing() -> endpoint::Response {
|
||||
Box::new(future::ok(ContentHandler::error(
|
||||
StatusCode::ServiceUnavailable,
|
||||
"Sync In Progress",
|
||||
"Your node is still syncing. We cannot resolve any content before it's fully synced.",
|
||||
Some("<a href=\"javascript:window.location.reload()\">Refresh</a>"),
|
||||
embeddable,
|
||||
).into()))
|
||||
}
|
||||
|
||||
fn dapps_disabled(address: Embeddable) -> endpoint::Response {
|
||||
fn dapps_disabled() -> endpoint::Response {
|
||||
Box::new(future::ok(ContentHandler::error(
|
||||
StatusCode::ServiceUnavailable,
|
||||
"Network Dapps Not Available",
|
||||
"This interface doesn't support network dapps for security reasons.",
|
||||
None,
|
||||
address,
|
||||
).into()))
|
||||
}
|
||||
|
||||
@ -195,10 +185,10 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
|
||||
match content {
|
||||
// Don't serve dapps if we are still syncing (but serve content)
|
||||
Some(URLHintResult::Dapp(_)) if self.sync.is_major_importing() => {
|
||||
(None, Self::still_syncing(self.embeddable_on.clone()))
|
||||
(None, Self::still_syncing())
|
||||
},
|
||||
Some(URLHintResult::Dapp(_)) if self.only_content => {
|
||||
(None, Self::dapps_disabled(self.embeddable_on.clone()))
|
||||
(None, Self::dapps_disabled())
|
||||
},
|
||||
Some(content) => {
|
||||
let handler = match content {
|
||||
@ -211,10 +201,8 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
|
||||
content_id.clone(),
|
||||
self.cache_path.clone(),
|
||||
Box::new(on_done),
|
||||
self.embeddable_on.clone(),
|
||||
self.pool.clone(),
|
||||
),
|
||||
self.embeddable_on.clone(),
|
||||
self.fetch.clone(),
|
||||
self.pool.clone(),
|
||||
)
|
||||
@ -228,10 +216,8 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
|
||||
content_id.clone(),
|
||||
self.cache_path.clone(),
|
||||
Box::new(on_done),
|
||||
self.embeddable_on.clone(),
|
||||
self.pool.clone(),
|
||||
),
|
||||
self.embeddable_on.clone(),
|
||||
self.fetch.clone(),
|
||||
self.pool.clone(),
|
||||
)
|
||||
@ -248,7 +234,6 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
|
||||
Box::new(on_done),
|
||||
self.pool.clone(),
|
||||
),
|
||||
self.embeddable_on.clone(),
|
||||
self.fetch.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)
|
||||
},
|
||||
None if self.sync.is_major_importing() => {
|
||||
(None, Self::still_syncing(self.embeddable_on.clone()))
|
||||
(None, Self::still_syncing())
|
||||
},
|
||||
None => {
|
||||
// This may happen when sync status changes in between
|
||||
// `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(),
|
||||
local_url: Some("".into()),
|
||||
allow_js_eval: None,
|
||||
}, Default::default(), None);
|
||||
}, Default::default());
|
||||
|
||||
// when
|
||||
fetcher.set_status("test", ContentStatus::Ready(handler));
|
||||
|
@ -24,7 +24,6 @@ use futures_cpupool::CpuPool;
|
||||
use apps::manifest::{MANIFEST_FILENAME, deserialize_manifest};
|
||||
use endpoint::{Endpoint, EndpointInfo};
|
||||
use page::{local, PageCache};
|
||||
use Embeddable;
|
||||
|
||||
struct LocalDapp {
|
||||
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.
|
||||
/// Parses the path to extract last component (for name).
|
||||
/// `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();
|
||||
path.canonicalize().ok().and_then(|path| {
|
||||
let name = path.file_name().and_then(|name| name.to_str());
|
||||
name.map(|name| {
|
||||
let dapp = local_dapp(name.into(), path.clone());
|
||||
(dapp.id, Box::new(local::Dapp::new(
|
||||
pool.clone(), dapp.path, dapp.info, PageCache::Disabled, 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.
|
||||
/// 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();
|
||||
for dapp in local_dapps(dapps_path.as_ref()) {
|
||||
pages.insert(
|
||||
dapp.id,
|
||||
Box::new(local::Dapp::new(pool.clone(), dapp.path, dapp.info, PageCache::Disabled, embeddable.clone()))
|
||||
Box::new(local::Dapp::new(pool.clone(), dapp.path, dapp.info, PageCache::Disabled))
|
||||
);
|
||||
}
|
||||
pages
|
||||
|
@ -17,17 +17,15 @@
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use endpoint::{Endpoints, Endpoint};
|
||||
use endpoint::Endpoints;
|
||||
use futures_cpupool::CpuPool;
|
||||
use page;
|
||||
use proxypac::ProxyPac;
|
||||
use web::Web;
|
||||
use fetch::Fetch;
|
||||
use {WebProxyTokens, ParentFrameSettings};
|
||||
use WebProxyTokens;
|
||||
|
||||
mod app;
|
||||
mod cache;
|
||||
mod ui;
|
||||
pub mod fs;
|
||||
pub mod fetcher;
|
||||
pub mod manifest;
|
||||
@ -37,68 +35,35 @@ pub use self::app::App;
|
||||
pub const HOME_PAGE: &'static str = "home";
|
||||
pub const RPC_PATH: &'static str = "rpc";
|
||||
pub const API_PATH: &'static str = "api";
|
||||
pub const UTILS_PATH: &'static str = "parity-utils";
|
||||
pub const WEB_PATH: &'static str = "web";
|
||||
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>(
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
dapps_domain: &str,
|
||||
embeddable: Option<ParentFrameSettings>,
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
fetch: F,
|
||||
pool: CpuPool,
|
||||
) -> (Vec<String>, Endpoints) {
|
||||
// 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();
|
||||
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);
|
||||
} else {
|
||||
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(
|
||||
"proxy".into(),
|
||||
ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned())
|
||||
ProxyPac::boxed(dapps_domain.to_owned())
|
||||
);
|
||||
pages.insert(
|
||||
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)
|
||||
|
@ -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()
|
||||
}))
|
||||
}
|
||||
}
|
@ -4,7 +4,88 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<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>
|
||||
<body>
|
||||
<div class="parity-navbar">
|
||||
|
@ -22,14 +22,12 @@ use hyper::StatusCode;
|
||||
use parity_version::version;
|
||||
|
||||
use handlers::add_security_headers;
|
||||
use Embeddable;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ContentHandler {
|
||||
code: StatusCode,
|
||||
content: String,
|
||||
mimetype: mime::Mime,
|
||||
safe_to_embed_on: Embeddable,
|
||||
}
|
||||
|
||||
impl ContentHandler {
|
||||
@ -37,8 +35,8 @@ impl ContentHandler {
|
||||
Self::new(StatusCode::Ok, content, mimetype)
|
||||
}
|
||||
|
||||
pub fn html(code: StatusCode, content: String, embeddable_on: Embeddable) -> Self {
|
||||
Self::new_embeddable(code, content, mime::TEXT_HTML, embeddable_on)
|
||||
pub fn html(code: StatusCode, content: String) -> Self {
|
||||
Self::new(code, content, mime::TEXT_HTML)
|
||||
}
|
||||
|
||||
pub fn error(
|
||||
@ -46,7 +44,6 @@ impl ContentHandler {
|
||||
title: &str,
|
||||
message: &str,
|
||||
details: Option<&str>,
|
||||
embeddable_on: Embeddable,
|
||||
) -> Self {
|
||||
Self::html(code, format!(
|
||||
include_str!("../error_tpl.html"),
|
||||
@ -54,24 +51,18 @@ impl ContentHandler {
|
||||
message=message,
|
||||
details=details.unwrap_or_else(|| ""),
|
||||
version=version(),
|
||||
), embeddable_on)
|
||||
))
|
||||
}
|
||||
|
||||
pub fn new(code: StatusCode, content: String, mimetype: mime::Mime) -> Self {
|
||||
Self::new_embeddable(code, content, mimetype, None)
|
||||
}
|
||||
|
||||
pub fn new_embeddable(
|
||||
pub fn new(
|
||||
code: StatusCode,
|
||||
content: String,
|
||||
mimetype: mime::Mime,
|
||||
safe_to_embed_on: Embeddable,
|
||||
) -> Self {
|
||||
ContentHandler {
|
||||
code,
|
||||
content,
|
||||
mimetype,
|
||||
safe_to_embed_on,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,7 +73,7 @@ impl Into<hyper::Response> for ContentHandler {
|
||||
.with_status(self.code)
|
||||
.with_header(header::ContentType(self.mimetype))
|
||||
.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
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ impl Into<hyper::Response> for EchoHandler {
|
||||
.with_header(content_type.unwrap_or(header::ContentType::json()))
|
||||
.with_body(self.request.body());
|
||||
|
||||
add_security_headers(res.headers_mut(), None, false);
|
||||
add_security_headers(res.headers_mut(), false);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
66
dapps/src/handlers/errors.rs
Normal file
66
dapps/src/handlers/errors.rs
Normal 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,
|
||||
)
|
||||
}
|
@ -19,20 +19,17 @@
|
||||
use std::{fmt, mem};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::{Instant, Duration};
|
||||
use std::time::Instant;
|
||||
use fetch::{self, Fetch};
|
||||
use futures::sync::oneshot;
|
||||
use futures::{self, Future};
|
||||
use futures_cpupool::CpuPool;
|
||||
use hyper::{self, StatusCode};
|
||||
use hyper;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use endpoint::{self, EndpointPath};
|
||||
use handlers::{ContentHandler, StreamingHandler};
|
||||
use handlers::{ContentHandler, StreamingHandler, FETCH_TIMEOUT, errors};
|
||||
use page::local;
|
||||
use {Embeddable};
|
||||
|
||||
const FETCH_TIMEOUT: Duration = Duration::from_secs(300);
|
||||
|
||||
pub enum ValidatorResponse {
|
||||
Local(local::Dapp),
|
||||
@ -134,8 +131,7 @@ impl Future for WaitingHandler {
|
||||
return Ok(futures::Async::Ready(handler.into()));
|
||||
},
|
||||
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) => {
|
||||
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 {
|
||||
Error(ContentHandler),
|
||||
InProgress(Box<Future<Item=FetchState, Error=()> + Send>),
|
||||
@ -237,7 +176,6 @@ impl fmt::Debug for FetchState {
|
||||
pub struct ContentFetcherHandler {
|
||||
fetch_control: FetchControl,
|
||||
status: FetchState,
|
||||
errors: Errors,
|
||||
}
|
||||
|
||||
impl ContentFetcherHandler {
|
||||
@ -250,12 +188,10 @@ impl ContentFetcherHandler {
|
||||
url: &str,
|
||||
path: EndpointPath,
|
||||
installer: H,
|
||||
embeddable_on: Embeddable,
|
||||
fetch: F,
|
||||
pool: CpuPool,
|
||||
) -> Self {
|
||||
let fetch_control = FetchControl::default();
|
||||
let errors = Errors { embeddable_on };
|
||||
|
||||
// Validation of method
|
||||
let status = match *method {
|
||||
@ -268,18 +204,16 @@ impl ContentFetcherHandler {
|
||||
url,
|
||||
fetch_control.abort.clone(),
|
||||
path,
|
||||
errors.clone(),
|
||||
installer,
|
||||
))
|
||||
},
|
||||
// or return error
|
||||
_ => FetchState::Error(errors.method_not_allowed()),
|
||||
_ => FetchState::Error(errors::method_not_allowed()),
|
||||
};
|
||||
|
||||
ContentFetcherHandler {
|
||||
fetch_control,
|
||||
status,
|
||||
errors,
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,7 +223,6 @@ impl ContentFetcherHandler {
|
||||
url: &str,
|
||||
abort: Arc<AtomicBool>,
|
||||
path: EndpointPath,
|
||||
errors: Errors,
|
||||
installer: H,
|
||||
) -> Box<Future<Item=FetchState, Error=()> + Send> {
|
||||
// Start fetching the content
|
||||
@ -311,12 +244,12 @@ impl ContentFetcherHandler {
|
||||
},
|
||||
Err(e) => {
|
||||
trace!(target: "dapps", "Error while validating content: {:?}", e);
|
||||
FetchState::Error(errors.invalid_content(e))
|
||||
FetchState::Error(errors::invalid_content(e))
|
||||
},
|
||||
},
|
||||
Err(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
|
||||
FetchState::InProgress(_) if self.fetch_control.is_deadline_reached() => {
|
||||
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) => {
|
||||
// Check if there is a response
|
||||
|
@ -22,6 +22,7 @@ mod fetch;
|
||||
mod reader;
|
||||
mod redirect;
|
||||
mod streaming;
|
||||
mod errors;
|
||||
|
||||
pub use self::content::ContentHandler;
|
||||
pub use self::echo::EchoHandler;
|
||||
@ -30,20 +31,16 @@ pub use self::reader::Reader;
|
||||
pub use self::redirect::Redirection;
|
||||
pub use self::streaming::StreamingHandler;
|
||||
|
||||
use std::iter;
|
||||
use itertools::Itertools;
|
||||
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.
|
||||
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-Content-Type-Options", "nosniff");
|
||||
|
||||
// Embedding header:
|
||||
if let None = embeddable_on {
|
||||
headers.set_raw("X-Frame-Options", "SAMEORIGIN");
|
||||
}
|
||||
|
||||
// Content Security Policy headers
|
||||
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';"
|
||||
// Allow scripts
|
||||
+ {
|
||||
let script_src = embeddable_on.as_ref()
|
||||
.map(|e| e.extra_script_src.iter()
|
||||
.map(|&(ref host, port)| address(host, port))
|
||||
.join(" ")
|
||||
).unwrap_or_default();
|
||||
let script_src = "";
|
||||
let eval = if allow_js_eval { " 'unsafe-eval'" } else { "" };
|
||||
|
||||
&format!(
|
||||
@ -93,29 +86,6 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd
|
||||
// Never allow mixed content
|
||||
+ "block-all-mixed-content;"
|
||||
// Specify if the site can be embedded.
|
||||
+ &match embeddable_on {
|
||||
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';"),
|
||||
}
|
||||
+ "frame-ancestors 'self';"
|
||||
);
|
||||
}
|
||||
|
@ -20,24 +20,21 @@ use std::io;
|
||||
use hyper::{self, header, mime, StatusCode};
|
||||
|
||||
use handlers::{add_security_headers, Reader};
|
||||
use Embeddable;
|
||||
|
||||
pub struct StreamingHandler<R> {
|
||||
initial: Vec<u8>,
|
||||
content: R,
|
||||
status: StatusCode,
|
||||
mimetype: mime::Mime,
|
||||
safe_to_embed_on: Embeddable,
|
||||
}
|
||||
|
||||
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 {
|
||||
initial: Vec::new(),
|
||||
content,
|
||||
status,
|
||||
mimetype,
|
||||
safe_to_embed_on,
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +48,7 @@ impl<R: io::Read> StreamingHandler<R> {
|
||||
.with_status(self.status)
|
||||
.with_header(header::ContentType(self.mimetype))
|
||||
.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)
|
||||
}
|
||||
|
119
dapps/src/lib.rs
119
dapps/src/lib.rs
@ -38,8 +38,6 @@ extern crate fetch;
|
||||
extern crate node_health;
|
||||
extern crate parity_dapps_glue as parity_dapps;
|
||||
extern crate parity_hash_fetch as hash_fetch;
|
||||
extern crate parity_ui;
|
||||
extern crate parity_ui_deprecation;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate parity_version;
|
||||
extern crate registrar;
|
||||
@ -84,6 +82,7 @@ use node_health::NodeHealth;
|
||||
|
||||
pub use registrar::{RegistrarClient, Asynchronous};
|
||||
pub use node_health::SyncStatus;
|
||||
pub use page::builtin::Dapp;
|
||||
|
||||
/// Validates Web Proxy tokens
|
||||
pub trait WebProxyTokens: Send + Sync {
|
||||
@ -101,7 +100,6 @@ pub struct Endpoints {
|
||||
local_endpoints: Arc<RwLock<Vec<String>>>,
|
||||
endpoints: Arc<RwLock<endpoint::Endpoints>>,
|
||||
dapps_path: PathBuf,
|
||||
embeddable: Option<ParentFrameSettings>,
|
||||
pool: Option<CpuPool>,
|
||||
}
|
||||
|
||||
@ -119,7 +117,7 @@ impl Endpoints {
|
||||
None => return,
|
||||
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 (_, to_remove): (_, Vec<_>) = old_local
|
||||
.into_iter()
|
||||
@ -151,69 +149,10 @@ impl Middleware {
|
||||
&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.
|
||||
pub fn dapps<F: Fetch>(
|
||||
pool: CpuPool,
|
||||
health: NodeHealth,
|
||||
ui_address: Option<(String, u16)>,
|
||||
extra_embed_on: Vec<(String, u16)>,
|
||||
extra_script_src: Vec<(String, u16)>,
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
dapps_domain: &str,
|
||||
@ -222,18 +161,16 @@ impl Middleware {
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
fetch: F,
|
||||
) -> Self {
|
||||
let embeddable = as_embeddable(ui_address, extra_embed_on, extra_script_src, dapps_domain);
|
||||
let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
|
||||
hash_fetch::urlhint::URLHintContract::new(registrar),
|
||||
sync_status.clone(),
|
||||
fetch.clone(),
|
||||
pool.clone(),
|
||||
).embeddable_on(embeddable.clone()).allow_dapps(true));
|
||||
).allow_dapps(true));
|
||||
let (local_endpoints, endpoints) = apps::all_endpoints(
|
||||
dapps_path.clone(),
|
||||
extra_dapps,
|
||||
dapps_domain,
|
||||
embeddable.clone(),
|
||||
web_proxy_tokens,
|
||||
fetch.clone(),
|
||||
pool.clone(),
|
||||
@ -242,28 +179,18 @@ impl Middleware {
|
||||
endpoints: Arc::new(RwLock::new(endpoints)),
|
||||
dapps_path,
|
||||
local_endpoints: Arc::new(RwLock::new(local_endpoints)),
|
||||
embeddable: embeddable.clone(),
|
||||
pool: Some(pool.clone()),
|
||||
};
|
||||
|
||||
let special = {
|
||||
let mut special = special_endpoints(
|
||||
pool.clone(),
|
||||
let special = special_endpoints(
|
||||
health,
|
||||
content_fetcher.clone(),
|
||||
);
|
||||
special.insert(
|
||||
router::SpecialEndpoint::Home,
|
||||
Some(apps::ui_redirection(embeddable.clone())),
|
||||
);
|
||||
special
|
||||
};
|
||||
|
||||
let router = router::Router::new(
|
||||
content_fetcher,
|
||||
Some(endpoints.clone()),
|
||||
special,
|
||||
embeddable,
|
||||
dapps_domain.to_owned(),
|
||||
);
|
||||
|
||||
@ -281,13 +208,11 @@ impl http::RequestMiddleware for Middleware {
|
||||
}
|
||||
|
||||
fn special_endpoints(
|
||||
pool: CpuPool,
|
||||
health: NodeHealth,
|
||||
content_fetcher: Arc<apps::fetcher::Fetcher>,
|
||||
) -> HashMap<router::SpecialEndpoint, Option<Box<endpoint::Endpoint>>> {
|
||||
let mut special = HashMap::new();
|
||||
special.insert(router::SpecialEndpoint::Rpc, None);
|
||||
special.insert(router::SpecialEndpoint::Utils, Some(apps::utils(pool)));
|
||||
special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new(
|
||||
content_fetcher,
|
||||
health,
|
||||
@ -295,45 +220,9 @@ fn special_endpoints(
|
||||
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
|
||||
fn random_filename() -> String {
|
||||
use ::rand::Rng;
|
||||
let mut rng = ::rand::OsRng::new().unwrap();
|
||||
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,
|
||||
}
|
||||
|
@ -23,15 +23,13 @@ use parity_dapps::{WebApp, Info};
|
||||
|
||||
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response};
|
||||
use page::{handler, PageCache};
|
||||
use Embeddable;
|
||||
|
||||
/// Represents a builtin Dapp.
|
||||
pub struct Dapp<T: WebApp + 'static> {
|
||||
/// futures cpu pool
|
||||
pool: CpuPool,
|
||||
/// Content of the files
|
||||
app: T,
|
||||
/// Safe to be loaded in frame by other origin. (use wisely!)
|
||||
safe_to_embed_on: Embeddable,
|
||||
info: EndpointInfo,
|
||||
fallback_to_index_html: bool,
|
||||
}
|
||||
@ -43,7 +41,6 @@ impl<T: WebApp + 'static> Dapp<T> {
|
||||
Dapp {
|
||||
pool,
|
||||
app,
|
||||
safe_to_embed_on: None,
|
||||
info: EndpointInfo::from(info),
|
||||
fallback_to_index_html: false,
|
||||
}
|
||||
@ -56,26 +53,11 @@ impl<T: WebApp + 'static> Dapp<T> {
|
||||
Dapp {
|
||||
pool,
|
||||
app,
|
||||
safe_to_embed_on: None,
|
||||
info: EndpointInfo::from(info),
|
||||
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.
|
||||
pub fn allow_js_eval(&mut self) {
|
||||
self.info.allow_js_eval = Some(true);
|
||||
@ -121,7 +103,6 @@ impl<T: WebApp> Endpoint for Dapp<T> {
|
||||
let (reader, response) = handler::PageHandler {
|
||||
file,
|
||||
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),
|
||||
}.into_response();
|
||||
|
||||
|
@ -20,7 +20,6 @@ use hyper::{self, header, StatusCode};
|
||||
use hyper::mime::{Mime};
|
||||
|
||||
use handlers::{Reader, ContentHandler, add_security_headers};
|
||||
use {Embeddable};
|
||||
|
||||
/// Represents a file that can be sent to client.
|
||||
/// Implementation should keep track of bytes already sent internally.
|
||||
@ -54,8 +53,6 @@ impl Default for PageCache {
|
||||
pub struct PageHandler<T: DappFile> {
|
||||
/// File currently being served
|
||||
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.
|
||||
pub cache: PageCache,
|
||||
/// Allow JS unsafe-eval.
|
||||
@ -70,7 +67,6 @@ impl<T: DappFile> PageHandler<T> {
|
||||
"File not found",
|
||||
"Requested file has not been found.",
|
||||
None,
|
||||
self.safe_to_embed_on,
|
||||
).into()),
|
||||
Some(file) => file,
|
||||
};
|
||||
@ -94,7 +90,7 @@ impl<T: DappFile> PageHandler<T> {
|
||||
|
||||
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());
|
||||
|
@ -22,7 +22,6 @@ use futures_cpupool::CpuPool;
|
||||
use page::handler::{self, PageCache};
|
||||
use endpoint::{Endpoint, EndpointInfo, EndpointPath, Request, Response};
|
||||
use hyper::mime::Mime;
|
||||
use Embeddable;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Dapp {
|
||||
@ -31,7 +30,6 @@ pub struct Dapp {
|
||||
mime: Option<Mime>,
|
||||
info: Option<EndpointInfo>,
|
||||
cache: PageCache,
|
||||
embeddable_on: Embeddable,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Dapp {
|
||||
@ -41,20 +39,18 @@ impl fmt::Debug for Dapp {
|
||||
.field("mime", &self.mime)
|
||||
.field("info", &self.info)
|
||||
.field("cache", &self.cache)
|
||||
.field("embeddable_on", &self.embeddable_on)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
pool,
|
||||
path,
|
||||
mime: None,
|
||||
info: Some(info),
|
||||
cache,
|
||||
embeddable_on,
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +61,6 @@ impl Dapp {
|
||||
mime: Some(mime),
|
||||
info: None,
|
||||
cache,
|
||||
embeddable_on: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,7 +91,6 @@ impl Dapp {
|
||||
let (reader, response) = handler::PageHandler {
|
||||
file: self.get_file(path),
|
||||
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),
|
||||
}.into_response();
|
||||
|
||||
|
@ -21,25 +21,20 @@ use endpoint::{Endpoint, Request, Response, EndpointPath};
|
||||
use futures::future;
|
||||
use handlers::ContentHandler;
|
||||
use hyper::mime;
|
||||
use {address, Embeddable};
|
||||
|
||||
pub struct ProxyPac {
|
||||
embeddable: Embeddable,
|
||||
dapps_domain: String,
|
||||
}
|
||||
|
||||
impl ProxyPac {
|
||||
pub fn boxed(embeddable: Embeddable, dapps_domain: String) -> Box<Endpoint> {
|
||||
Box::new(ProxyPac { embeddable, dapps_domain })
|
||||
pub fn boxed(dapps_domain: String) -> Box<Endpoint> {
|
||||
Box::new(ProxyPac { dapps_domain })
|
||||
}
|
||||
}
|
||||
|
||||
impl Endpoint for ProxyPac {
|
||||
fn respond(&self, path: EndpointPath, _req: Request) -> Response {
|
||||
let ui = self.embeddable
|
||||
.as_ref()
|
||||
.map(|ref parent| address(&parent.host, parent.port))
|
||||
.unwrap_or_else(|| format!("{}:{}", path.host, path.port));
|
||||
let ui = format!("{}:{}", path.host, path.port);
|
||||
|
||||
let content = format!(
|
||||
r#"
|
||||
|
@ -29,14 +29,12 @@ use apps::fetcher::Fetcher;
|
||||
use endpoint::{self, Endpoint, EndpointPath};
|
||||
use Endpoints;
|
||||
use handlers;
|
||||
use Embeddable;
|
||||
|
||||
/// Special endpoints are accessible on every domain (every dapp)
|
||||
#[derive(Debug, PartialEq, Hash, Eq)]
|
||||
pub enum SpecialEndpoint {
|
||||
Rpc,
|
||||
Api,
|
||||
Utils,
|
||||
Home,
|
||||
None,
|
||||
}
|
||||
@ -52,16 +50,14 @@ pub struct Router {
|
||||
endpoints: Option<Endpoints>,
|
||||
fetch: Arc<Fetcher>,
|
||||
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
|
||||
embeddable_on: Embeddable,
|
||||
dapps_domain: String,
|
||||
}
|
||||
|
||||
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
|
||||
let endpoint = extract_endpoint(req.uri(), req.headers().get(), &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_head_request = *req.method() == hyper::Method::Head;
|
||||
let has_dapp = |dapp: &str| self.endpoints
|
||||
@ -71,7 +67,7 @@ impl Router {
|
||||
trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", req.uri(), req);
|
||||
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
|
||||
(ref path, SpecialEndpoint::None, Some(ref referer))
|
||||
if referer.app_id == apps::WEB_PATH
|
||||
@ -132,7 +128,6 @@ impl Router {
|
||||
"404 Not Found",
|
||||
"Requested content was not found.",
|
||||
None,
|
||||
self.embeddable_on.clone(),
|
||||
).into())))
|
||||
}
|
||||
},
|
||||
@ -161,20 +156,19 @@ impl Router {
|
||||
"404 Not Found",
|
||||
"Requested content was not found.",
|
||||
None,
|
||||
self.embeddable_on.clone(),
|
||||
).into())))
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl http::RequestMiddleware for Router {
|
||||
fn on_request(&self, req: hyper::Request) -> http::RequestMiddlewareAction {
|
||||
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 {
|
||||
Response::Some(response) => http::RequestMiddlewareAction::Respond {
|
||||
should_validate_hosts: !is_utils,
|
||||
should_validate_hosts: true,
|
||||
response,
|
||||
},
|
||||
Response::None(request) => http::RequestMiddlewareAction::Proceed {
|
||||
@ -190,14 +184,12 @@ impl Router {
|
||||
content_fetcher: Arc<Fetcher>,
|
||||
endpoints: Option<Endpoints>,
|
||||
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
|
||||
embeddable_on: Embeddable,
|
||||
dapps_domain: String,
|
||||
) -> Self {
|
||||
Router {
|
||||
endpoints: endpoints,
|
||||
fetch: content_fetcher,
|
||||
special: special,
|
||||
embeddable_on: embeddable_on,
|
||||
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() {
|
||||
apps::RPC_PATH => SpecialEndpoint::Rpc,
|
||||
apps::API_PATH => SpecialEndpoint::Api,
|
||||
apps::UTILS_PATH => SpecialEndpoint::Utils,
|
||||
apps::HOME_PAGE => SpecialEndpoint::Home,
|
||||
_ => SpecialEndpoint::None,
|
||||
}
|
||||
@ -351,30 +342,6 @@ mod tests {
|
||||
}), 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
|
||||
assert_eq!(
|
||||
extract_endpoint(&"http://status.web3.site/test.html".parse().unwrap(), None, dapps_domain),
|
||||
|
@ -19,7 +19,7 @@ use rustc_hex::FromHex;
|
||||
use tests::helpers::{
|
||||
serve_with_registrar, serve_with_registrar_and_sync, serve_with_fetch,
|
||||
serve_with_registrar_and_fetch,
|
||||
request, assert_security_headers_for_embed,
|
||||
request, assert_security_headers
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -40,7 +40,7 @@ fn should_resolve_dapp() {
|
||||
// then
|
||||
response.assert_status("HTTP/1.1 404 Not Found");
|
||||
assert_eq!(registrar.calls.lock().len(), 4);
|
||||
assert_security_headers_for_embed(&response.headers);
|
||||
assert_security_headers(&response.headers);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -61,7 +61,7 @@ fn should_return_503_when_syncing_but_should_make_the_calls() {
|
||||
// then
|
||||
response.assert_status("HTTP/1.1 503 Service Unavailable");
|
||||
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";
|
||||
@ -95,7 +95,7 @@ fn should_return_502_on_hash_mismatch() {
|
||||
|
||||
response.assert_status("HTTP/1.1 502 Bad Gateway");
|
||||
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]
|
||||
@ -126,7 +126,7 @@ fn should_return_error_for_invalid_dapp_zip() {
|
||||
|
||||
response.assert_status("HTTP/1.1 502 Bad Gateway");
|
||||
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]
|
||||
@ -165,7 +165,7 @@ fn should_return_fetched_dapp_content() {
|
||||
fetch.assert_no_more_requests();
|
||||
|
||||
response1.assert_status("HTTP/1.1 200 OK");
|
||||
assert_security_headers_for_embed(&response1.headers);
|
||||
assert_security_headers(&response1.headers);
|
||||
assert!(
|
||||
response1.body.contains(r#"18
|
||||
<h1>Hello Gavcoin!</h1>
|
||||
@ -178,7 +178,7 @@ fn should_return_fetched_dapp_content() {
|
||||
);
|
||||
|
||||
response2.assert_status("HTTP/1.1 200 OK");
|
||||
assert_security_headers_for_embed(&response2.headers);
|
||||
assert_security_headers(&response2.headers);
|
||||
assert_eq!(
|
||||
response2.body,
|
||||
r#"EA
|
||||
@ -331,7 +331,7 @@ fn should_stream_web_content() {
|
||||
|
||||
// then
|
||||
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_no_more_requests();
|
||||
@ -354,7 +354,7 @@ fn should_support_base32_encoded_web_urls() {
|
||||
|
||||
// then
|
||||
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_no_more_requests();
|
||||
@ -377,7 +377,7 @@ fn should_correctly_handle_long_label_when_splitted() {
|
||||
|
||||
// then
|
||||
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_no_more_requests();
|
||||
@ -400,7 +400,7 @@ fn should_support_base32_encoded_web_urls_as_path() {
|
||||
|
||||
// then
|
||||
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_no_more_requests();
|
||||
@ -423,7 +423,7 @@ fn should_return_error_on_non_whitelisted_domain() {
|
||||
|
||||
// then
|
||||
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();
|
||||
}
|
||||
@ -445,7 +445,7 @@ fn should_return_error_on_invalid_token() {
|
||||
|
||||
// then
|
||||
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();
|
||||
}
|
||||
@ -467,7 +467,7 @@ fn should_return_error_on_invalid_protocol() {
|
||||
|
||||
// then
|
||||
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();
|
||||
}
|
||||
@ -492,7 +492,7 @@ fn should_disallow_non_get_requests() {
|
||||
|
||||
// then
|
||||
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();
|
||||
}
|
||||
|
@ -36,8 +36,6 @@ mod fetch;
|
||||
use self::registrar::FakeRegistrar;
|
||||
use self::fetch::FakeFetch;
|
||||
|
||||
const SIGNER_PORT: u16 = 18180;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FakeSync(bool);
|
||||
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();
|
||||
dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading");
|
||||
|
||||
let mut builder = ServerBuilder::new(FetchClient::new().unwrap(), &dapps_path, registrar.clone());
|
||||
builder.signer_address = Some(("127.0.0.1".into(), SIGNER_PORT));
|
||||
let builder = ServerBuilder::new(FetchClient::new().unwrap(), &dapps_path, registrar.clone());
|
||||
let server = process(builder).start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), io).unwrap();
|
||||
(
|
||||
server,
|
||||
@ -122,13 +119,6 @@ pub fn serve() -> Server {
|
||||
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 {
|
||||
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]) {
|
||||
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.
|
||||
pub struct ServerBuilder<T: Fetch = FetchClient> {
|
||||
@ -146,10 +133,8 @@ pub struct ServerBuilder<T: Fetch = FetchClient> {
|
||||
registrar: Arc<RegistrarClient<Call=Asynchronous>>,
|
||||
sync_status: Arc<SyncStatus>,
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
signer_address: Option<(String, u16)>,
|
||||
allowed_hosts: DomainsValidation<Host>,
|
||||
fetch: T,
|
||||
serve_ui: bool,
|
||||
}
|
||||
|
||||
impl ServerBuilder {
|
||||
@ -160,10 +145,8 @@ impl ServerBuilder {
|
||||
registrar: registrar,
|
||||
sync_status: Arc::new(FakeSync(false)),
|
||||
web_proxy_tokens: Arc::new(|_| None),
|
||||
signer_address: None,
|
||||
allowed_hosts: DomainsValidation::Disabled,
|
||||
fetch: fetch,
|
||||
serve_ui: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,10 +159,8 @@ impl<T: Fetch> ServerBuilder<T> {
|
||||
registrar: self.registrar,
|
||||
sync_status: self.sync_status,
|
||||
web_proxy_tokens: self.web_proxy_tokens,
|
||||
signer_address: self.signer_address,
|
||||
allowed_hosts: self.allowed_hosts,
|
||||
fetch: fetch,
|
||||
serve_ui: self.serve_ui,
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +171,6 @@ impl<T: Fetch> ServerBuilder<T> {
|
||||
addr,
|
||||
io,
|
||||
self.allowed_hosts,
|
||||
self.signer_address,
|
||||
self.dapps_path,
|
||||
vec![],
|
||||
self.registrar,
|
||||
@ -198,7 +178,6 @@ impl<T: Fetch> ServerBuilder<T> {
|
||||
self.web_proxy_tokens,
|
||||
Remote::new_sync(),
|
||||
self.fetch,
|
||||
self.serve_ui,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -215,7 +194,6 @@ impl Server {
|
||||
addr: &SocketAddr,
|
||||
io: IoHandler,
|
||||
allowed_hosts: DomainsValidation<Host>,
|
||||
signer_address: Option<(String, u16)>,
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
registrar: Arc<RegistrarClient<Call=Asynchronous>>,
|
||||
@ -223,7 +201,6 @@ impl Server {
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
remote: Remote,
|
||||
fetch: F,
|
||||
serve_ui: bool,
|
||||
) -> io::Result<Server> {
|
||||
let health = NodeHealth::new(
|
||||
sync_status.clone(),
|
||||
@ -231,23 +208,10 @@ impl Server {
|
||||
remote.clone(),
|
||||
);
|
||||
let pool = ::futures_cpupool::CpuPool::new(1);
|
||||
let middleware = if serve_ui {
|
||||
Middleware::ui(
|
||||
pool,
|
||||
health,
|
||||
DAPPS_DOMAIN.into(),
|
||||
registrar,
|
||||
sync_status,
|
||||
fetch,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
let middleware =
|
||||
Middleware::dapps(
|
||||
pool,
|
||||
health,
|
||||
signer_address,
|
||||
vec![],
|
||||
vec![],
|
||||
dapps_path,
|
||||
extra_dapps,
|
||||
DAPPS_DOMAIN.into(),
|
||||
@ -255,8 +219,7 @@ impl Server {
|
||||
sync_status,
|
||||
web_proxy_tokens,
|
||||
fetch,
|
||||
)
|
||||
};
|
||||
);
|
||||
|
||||
let mut allowed_hosts: Option<Vec<Host>> = allowed_hosts.into();
|
||||
allowed_hosts.as_mut().map(|hosts| {
|
||||
|
@ -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);
|
||||
}
|
@ -20,7 +20,5 @@ mod helpers;
|
||||
|
||||
mod api;
|
||||
mod fetch;
|
||||
mod home;
|
||||
mod redirection;
|
||||
mod rpc;
|
||||
mod validation;
|
||||
|
@ -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);
|
||||
}
|
@ -37,26 +37,6 @@ fn should_reject_invalid_host() {
|
||||
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]
|
||||
fn should_serve_dapps_domains() {
|
||||
// given
|
||||
@ -66,28 +46,7 @@ fn should_serve_dapps_domains() {
|
||||
let response = request(server,
|
||||
"\
|
||||
GET / HTTP/1.1\r\n\
|
||||
Host: ui.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\
|
||||
Host: proxy.web3.site\r\n\
|
||||
Connection: close\r\n\
|
||||
\r\n\
|
||||
{}
|
||||
|
@ -30,10 +30,9 @@ use handlers::{
|
||||
ContentFetcherHandler, ContentHandler, ContentValidator, ValidatorResponse,
|
||||
StreamingHandler,
|
||||
};
|
||||
use {Embeddable, WebProxyTokens};
|
||||
use WebProxyTokens;
|
||||
|
||||
pub struct Web<F> {
|
||||
embeddable_on: Embeddable,
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
fetch: F,
|
||||
pool: CpuPool,
|
||||
@ -41,13 +40,11 @@ pub struct Web<F> {
|
||||
|
||||
impl<F: Fetch> Web<F> {
|
||||
pub fn boxed(
|
||||
embeddable_on: Embeddable,
|
||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||
fetch: F,
|
||||
pool: CpuPool,
|
||||
) -> Box<Endpoint> {
|
||||
Box::new(Web {
|
||||
embeddable_on,
|
||||
web_proxy_tokens,
|
||||
fetch,
|
||||
pool,
|
||||
@ -64,7 +61,6 @@ impl<F: Fetch> Web<F> {
|
||||
"Invalid parameter",
|
||||
"Couldn't parse given parameter:",
|
||||
path.app_params.get(0).map(String::as_str),
|
||||
self.embeddable_on.clone()
|
||||
))?;
|
||||
|
||||
let mut token_it = token_and_url.split('+');
|
||||
@ -76,7 +72,7 @@ impl<F: Fetch> Web<F> {
|
||||
Some(domain) => domain,
|
||||
_ => {
|
||||
return Err(ContentHandler::error(
|
||||
StatusCode::BadRequest, "Invalid Access Token", "Invalid or old web proxy access token supplied.", Some("Try refreshing the page."), 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(),
|
||||
_ => {
|
||||
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) {
|
||||
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,
|
||||
path,
|
||||
WebInstaller {
|
||||
embeddable_on: self.embeddable_on.clone(),
|
||||
token,
|
||||
},
|
||||
self.embeddable_on.clone(),
|
||||
self.fetch.clone(),
|
||||
self.pool.clone(),
|
||||
))
|
||||
@ -139,7 +133,6 @@ impl<F: Fetch> Endpoint for Web<F> {
|
||||
}
|
||||
|
||||
struct WebInstaller {
|
||||
embeddable_on: Embeddable,
|
||||
token: String,
|
||||
}
|
||||
|
||||
@ -154,12 +147,10 @@ impl ContentValidator for WebInstaller {
|
||||
fetch::BodyReader::new(response),
|
||||
status,
|
||||
mime,
|
||||
self.embeddable_on,
|
||||
);
|
||||
if is_html {
|
||||
handler.set_initial_content(&format!(
|
||||
r#"<script src="/{}/inject.js"></script><script>history.replaceState({{}}, "", "/?{}{}/{}")</script>"#,
|
||||
apps::UTILS_PATH,
|
||||
r#"<script>history.replaceState({{}}, "", "/?{}{}/{}")</script>"#,
|
||||
apps::URL_REFERER,
|
||||
apps::WEB_PATH,
|
||||
&self.token,
|
||||
|
@ -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"
|
@ -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();
|
||||
}
|
@ -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>
|
@ -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");
|
@ -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");
|
||||
}
|
@ -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"]
|
@ -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::*;
|
@ -26,10 +26,6 @@ usage! {
|
||||
// Arguments must start with arg_
|
||||
// Flags must start with flag_
|
||||
|
||||
CMD cmd_ui {
|
||||
"Manage ui",
|
||||
}
|
||||
|
||||
CMD cmd_dapp
|
||||
{
|
||||
"Manage dapps",
|
||||
@ -376,35 +372,10 @@ usage! {
|
||||
"Provide a file containing passwords for unlocking accounts (signer, private account, validators).",
|
||||
|
||||
["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(),
|
||||
"--ui-path=[PATH]",
|
||||
"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"]
|
||||
FLAG flag_no_warp: (bool) = false, or |c: &Config| c.network.as_ref()?.warp.clone().map(|w| !w),
|
||||
"--no-warp",
|
||||
@ -948,6 +919,30 @@ usage! {
|
||||
"--public-node",
|
||||
"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(),
|
||||
"--dapps-port=[PORT]",
|
||||
"Dapps server is merged with RPC server. Use --jsonrpc-port.",
|
||||
@ -1111,12 +1106,18 @@ struct PrivateTransactions {
|
||||
#[derive(Default, Debug, PartialEq, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct Ui {
|
||||
force: Option<bool>,
|
||||
disable: Option<bool>,
|
||||
port: Option<u16>,
|
||||
interface: Option<String>,
|
||||
hosts: Option<Vec<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)]
|
||||
@ -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();
|
||||
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_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_ui_port, 8123);
|
||||
assert_eq!(args.cmd_ui, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1476,7 +1475,6 @@ mod tests {
|
||||
// then
|
||||
assert_eq!(args, Args {
|
||||
// Commands
|
||||
cmd_ui: false,
|
||||
cmd_dapp: false,
|
||||
cmd_daemon: false,
|
||||
cmd_account: false,
|
||||
@ -1566,7 +1564,7 @@ mod tests {
|
||||
flag_force_ui: false,
|
||||
flag_no_ui: false,
|
||||
arg_ui_port: 8180u16,
|
||||
arg_ui_interface: "127.0.0.1".into(),
|
||||
arg_ui_interface: "local".into(),
|
||||
arg_ui_hosts: "none".into(),
|
||||
arg_ui_path: "$HOME/.parity/signer".into(),
|
||||
flag_ui_no_validation: false,
|
||||
@ -1820,12 +1818,12 @@ mod tests {
|
||||
fast_unlock: None,
|
||||
}),
|
||||
ui: Some(Ui {
|
||||
force: None,
|
||||
disable: Some(true),
|
||||
port: None,
|
||||
interface: None,
|
||||
hosts: None,
|
||||
path: None,
|
||||
_legacy_force: None,
|
||||
_legacy_disable: Some(true),
|
||||
_legacy_port: None,
|
||||
_legacy_interface: None,
|
||||
_legacy_hosts: None,
|
||||
}),
|
||||
network: Some(Network {
|
||||
warp: Some(false),
|
||||
|
@ -20,7 +20,6 @@ use std::net::SocketAddr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::collections::BTreeMap;
|
||||
use std::cmp;
|
||||
use std::str::FromStr;
|
||||
use cli::{Args, ArgsError};
|
||||
use hash::keccak;
|
||||
use ethereum_types::{U256, H256, Address};
|
||||
@ -34,7 +33,7 @@ use ethcore::miner::{stratum, MinerOptions};
|
||||
use ethcore::verification::queue::VerifierSettings;
|
||||
use miner::pool;
|
||||
|
||||
use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration};
|
||||
use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration};
|
||||
use parity_rpc::NetworkSettings;
|
||||
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};
|
||||
@ -65,7 +64,7 @@ pub enum Cmd {
|
||||
Account(AccountCmd),
|
||||
ImportPresaleWallet(ImportWallet),
|
||||
Blockchain(BlockchainCmd),
|
||||
SignerToken(WsConfiguration, UiConfiguration, LogConfig),
|
||||
SignerToken(WsConfiguration, LogConfig),
|
||||
SignerSign {
|
||||
id: Option<usize>,
|
||||
pwfile: Option<PathBuf>,
|
||||
@ -130,7 +129,6 @@ impl Configuration {
|
||||
let http_conf = self.http_config()?;
|
||||
let ipc_conf = self.ipc_config()?;
|
||||
let net_conf = self.net_config()?;
|
||||
let ui_conf = self.ui_config();
|
||||
let network_id = self.network_id();
|
||||
let cache_config = self.cache_config();
|
||||
let tracing = self.args.arg_tracing.parse()?;
|
||||
@ -150,7 +148,7 @@ impl Configuration {
|
||||
let authfile = ::signer::codes_path(&ws_conf.signer_path);
|
||||
|
||||
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 {
|
||||
let pwfile = self.accounts_config()?.password_files.first().map(|pwfile| {
|
||||
PathBuf::from(pwfile)
|
||||
@ -381,13 +379,11 @@ impl Configuration {
|
||||
net_settings: self.network_settings()?,
|
||||
dapps_conf: dapps_conf,
|
||||
ipfs_conf: ipfs_conf,
|
||||
ui_conf: ui_conf,
|
||||
secretstore_conf: secretstore_conf,
|
||||
private_provider_conf: private_provider_conf,
|
||||
private_encryptor_conf: private_enc_conf,
|
||||
private_tx_enabled,
|
||||
dapp: self.dapp_to_open()?,
|
||||
ui: self.args.cmd_ui,
|
||||
name: self.args.arg_identity,
|
||||
custom_bootnodes: self.args.arg_bootnodes.is_some(),
|
||||
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> {
|
||||
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 {
|
||||
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 {
|
||||
enabled: self.dapps_enabled(),
|
||||
dapps_path: PathBuf::from(self.directories().dapps),
|
||||
@ -619,31 +597,6 @@ impl Configuration {
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
|
||||
fn ui_hosts(&self) -> Option<Vec<String>> {
|
||||
self.hosts(&self.args.arg_ui_hosts, &self.ui_interface())
|
||||
}
|
||||
|
||||
fn rpc_hosts(&self) -> Option<Vec<String>> {
|
||||
self.hosts(&self.args.arg_jsonrpc_hosts, &self.rpc_interface())
|
||||
}
|
||||
@ -876,7 +825,7 @@ impl Configuration {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -925,7 +874,6 @@ impl Configuration {
|
||||
}
|
||||
|
||||
fn ws_config(&self) -> Result<WsConfiguration, String> {
|
||||
let ui = self.ui_config();
|
||||
let http = self.http_config()?;
|
||||
|
||||
let support_token_api =
|
||||
@ -941,7 +889,6 @@ impl Configuration {
|
||||
origins: self.ws_origins(),
|
||||
signer_path: self.directories().signer.into(),
|
||||
support_token_api,
|
||||
ui_address: ui.address(),
|
||||
dapps_address: http.address(),
|
||||
max_connections: self.args.arg_ws_max_connections,
|
||||
};
|
||||
@ -1065,10 +1012,6 @@ impl Configuration {
|
||||
}.into()
|
||||
}
|
||||
|
||||
fn ui_interface(&self) -> String {
|
||||
self.interface(&self.args.arg_ui_interface)
|
||||
}
|
||||
|
||||
fn rpc_interface(&self) -> String {
|
||||
let rpc_interface = self.args.arg_rpcaddr.clone().unwrap_or(self.args.arg_jsonrpc_interface.clone());
|
||||
self.interface(&rpc_interface)
|
||||
@ -1184,24 +1127,6 @@ impl Configuration {
|
||||
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 {
|
||||
let mut settings = VerifierSettings::default();
|
||||
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> {
|
||||
match s {
|
||||
"none" => Ok(None),
|
||||
@ -1254,7 +1173,7 @@ mod tests {
|
||||
use helpers::{default_network_config};
|
||||
use params::SpecType;
|
||||
use presale::ImportWallet;
|
||||
use rpc::{WsConfiguration, UiConfiguration};
|
||||
use rpc::WsConfiguration;
|
||||
use rpc_apis::ApiSet;
|
||||
use run::RunCmd;
|
||||
|
||||
@ -1438,16 +1357,9 @@ mod tests {
|
||||
origins: Some(vec!["parity://*".into(),"chrome-extension://*".into(), "moz-extension://*".into()]),
|
||||
hosts: Some(vec![]),
|
||||
signer_path: expected.into(),
|
||||
ui_address: Some("127.0.0.1:8180".into()),
|
||||
dapps_address: Some("127.0.0.1:8545".into()),
|
||||
support_token_api: true,
|
||||
max_connections: 100,
|
||||
}, UiConfiguration {
|
||||
enabled: true,
|
||||
interface: "127.0.0.1".into(),
|
||||
port: 8180,
|
||||
hosts: Some(vec![]),
|
||||
info_page_only: true,
|
||||
}, LogConfig {
|
||||
color: true,
|
||||
mode: None,
|
||||
@ -1516,12 +1428,10 @@ mod tests {
|
||||
net_settings: Default::default(),
|
||||
dapps_conf: Default::default(),
|
||||
ipfs_conf: Default::default(),
|
||||
ui_conf: Default::default(),
|
||||
secretstore_conf: Default::default(),
|
||||
private_provider_conf: Default::default(),
|
||||
private_encryptor_conf: Default::default(),
|
||||
private_tx_enabled: false,
|
||||
ui: false,
|
||||
dapp: None,
|
||||
name: "".into(),
|
||||
custom_bootnodes: false,
|
||||
@ -1704,49 +1614,6 @@ mod tests {
|
||||
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]
|
||||
fn should_parse_ui_configuration() {
|
||||
// given
|
||||
@ -1757,69 +1624,22 @@ mod tests {
|
||||
let conf2 = parse(&["parity", "--ui-path=signer", "--ui-port", "3123"]);
|
||||
let conf3 = parse(&["parity", "--ui-path=signer", "--ui-interface", "test"]);
|
||||
let conf4 = parse(&["parity", "--ui-path=signer", "--force-ui"]);
|
||||
let conf5 = parse(&["parity", "--ui-path=signer", "ui"]);
|
||||
|
||||
// then
|
||||
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_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.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_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_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_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]
|
||||
@ -1976,7 +1796,6 @@ mod tests {
|
||||
assert_eq!(conf0.network_settings().unwrap().rpc_port, 8546);
|
||||
assert_eq!(conf0.http_config().unwrap().port, 8546);
|
||||
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().http_port, 8083);
|
||||
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.http_config().unwrap().port, 8545);
|
||||
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().http_port, 8083);
|
||||
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().hosts, 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().http_interface, "0.0.0.0");
|
||||
assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0");
|
||||
|
@ -39,8 +39,6 @@ pub struct Configuration {
|
||||
pub enabled: bool,
|
||||
pub dapps_path: PathBuf,
|
||||
pub extra_dapps: Vec<PathBuf>,
|
||||
pub extra_embed_on: Vec<(String, u16)>,
|
||||
pub extra_script_src: Vec<(String, u16)>,
|
||||
}
|
||||
|
||||
impl Default for Configuration {
|
||||
@ -50,8 +48,6 @@ impl Default for Configuration {
|
||||
enabled: true,
|
||||
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
|
||||
extra_dapps: vec![],
|
||||
extra_embed_on: vec![],
|
||||
extra_script_src: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -163,8 +159,6 @@ pub struct Dependencies {
|
||||
pub fetch: FetchClient,
|
||||
pub pool: CpuPool,
|
||||
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> {
|
||||
@ -177,19 +171,6 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Mi
|
||||
configuration.dapps_path,
|
||||
configuration.extra_dapps,
|
||||
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)
|
||||
}
|
||||
|
||||
@ -215,19 +196,10 @@ mod server {
|
||||
_dapps_path: PathBuf,
|
||||
_extra_dapps: Vec<PathBuf>,
|
||||
_dapps_domain: &str,
|
||||
_extra_embed_on: Vec<(String, u16)>,
|
||||
_extra_script_src: Vec<(String, u16)>,
|
||||
) -> Result<Middleware, String> {
|
||||
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>> {
|
||||
None
|
||||
}
|
||||
@ -249,8 +221,6 @@ mod server {
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
dapps_domain: &str,
|
||||
extra_embed_on: Vec<(String, u16)>,
|
||||
extra_script_src: Vec<(String, u16)>,
|
||||
) -> Result<Middleware, String> {
|
||||
let signer = deps.signer;
|
||||
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(
|
||||
deps.pool,
|
||||
deps.node_health,
|
||||
deps.ui_address,
|
||||
extra_embed_on,
|
||||
extra_script_src,
|
||||
dapps_path,
|
||||
extra_dapps,
|
||||
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>> {
|
||||
middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper {
|
||||
endpoints: m.endpoints().clone(),
|
||||
|
@ -118,15 +118,13 @@ mod user_defaults;
|
||||
mod whisper;
|
||||
mod db;
|
||||
|
||||
use std::net::{TcpListener};
|
||||
use std::io::BufReader;
|
||||
use std::fs::File;
|
||||
use ansi_term::Style;
|
||||
use hash::keccak_buffer;
|
||||
use cli::Args;
|
||||
use configuration::{Cmd, Execute};
|
||||
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::run::RunningClient;
|
||||
@ -195,24 +193,6 @@ fn execute<Cr, Rr>(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res
|
||||
|
||||
match command.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 {
|
||||
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::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::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::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))),
|
||||
@ -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)
|
||||
}
|
||||
|
||||
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> {
|
||||
if !dapps_conf.enabled {
|
||||
return Err("Cannot use DAPP command with Dapps turned off.".into())
|
||||
|
@ -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)]
|
||||
pub struct IpcConfiguration {
|
||||
pub enabled: bool,
|
||||
@ -153,7 +101,6 @@ pub struct WsConfiguration {
|
||||
pub hosts: Option<Vec<String>>,
|
||||
pub signer_path: PathBuf,
|
||||
pub support_token_api: bool,
|
||||
pub ui_address: Option<rpc::Host>,
|
||||
pub dapps_address: Option<rpc::Host>,
|
||||
}
|
||||
|
||||
@ -170,7 +117,6 @@ impl Default for WsConfiguration {
|
||||
hosts: Some(Vec::new()),
|
||||
signer_path: replace_home(&data_dir, "$BASE/signer").into(),
|
||||
support_token_api: true,
|
||||
ui_address: Some("127.0.0.1:8180".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 ui_address = conf.ui_address.clone();
|
||||
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()), &None));
|
||||
let allowed_origins = into_domains(with_domain(conf.origins, domain, &conf.dapps_address));
|
||||
let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &Some(url.clone().into())));
|
||||
|
||||
let signer_path;
|
||||
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 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(
|
||||
&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()
|
||||
}
|
||||
|
||||
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> {
|
||||
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);
|
||||
}
|
||||
items.into_iter().collect()
|
||||
|
@ -112,13 +112,11 @@ pub struct RunCmd {
|
||||
pub net_settings: NetworkSettings,
|
||||
pub dapps_conf: dapps::Configuration,
|
||||
pub ipfs_conf: ipfs::Configuration,
|
||||
pub ui_conf: rpc::UiConfiguration,
|
||||
pub secretstore_conf: secretstore::Configuration,
|
||||
pub private_provider_conf: ProviderConfig,
|
||||
pub private_encryptor_conf: EncryptorConfig,
|
||||
pub private_tx_enabled: bool,
|
||||
pub dapp: Option<String>,
|
||||
pub ui: bool,
|
||||
pub name: String,
|
||||
pub custom_bootnodes: bool,
|
||||
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)?;
|
||||
|
||||
// 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_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(),
|
||||
pool: cpu_pool.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 ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
|
||||
|
||||
// start RPCs
|
||||
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 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 ui_server = rpc::new_http("Parity Wallet (UI)", "ui", cmd.ui_conf.clone().into(), &dependencies, ui_middleware)?;
|
||||
|
||||
// the informant
|
||||
let informant = Arc::new(Informant::new(
|
||||
@ -394,7 +388,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
|
||||
rpc: rpc_direct,
|
||||
informant,
|
||||
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)?;
|
||||
|
||||
// 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
|
||||
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(),
|
||||
pool: cpu_pool.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 ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
|
||||
|
||||
let dapps_service = dapps::service(&dapps_middleware);
|
||||
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 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)?;
|
||||
// the ui server
|
||||
let ui_server = rpc::new_http("UI WALLET", "ui", cmd.ui_conf.clone().into(), &dependencies, ui_middleware)?;
|
||||
|
||||
// secret store key server
|
||||
let secretstore_deps = secretstore::Dependencies {
|
||||
@ -881,7 +870,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
informant,
|
||||
client,
|
||||
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)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ pub const CODES_FILENAME: &'static str = "authcodes";
|
||||
|
||||
pub struct NewToken {
|
||||
pub token: String,
|
||||
pub url: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
@ -49,22 +48,19 @@ pub fn codes_path(path: &Path) -> PathBuf {
|
||||
p
|
||||
}
|
||||
|
||||
pub fn execute(ws_conf: rpc::WsConfiguration, ui_conf: rpc::UiConfiguration, logger_config: LogConfig) -> Result<String, String> {
|
||||
Ok(generate_token_and_url(&ws_conf, &ui_conf, &logger_config)?.message)
|
||||
pub fn execute(ws_conf: rpc::WsConfiguration, logger_config: LogConfig) -> Result<String, String> {
|
||||
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 auth_url = format!("http://{}:{}/#/auth?token={}", ui_conf.interface, ui_conf.port, code);
|
||||
let colored = |s: String| match logger_config.color {
|
||||
true => format!("{}", White.bold().paint(s)),
|
||||
false => s,
|
||||
};
|
||||
|
||||
if !ui_conf.enabled {
|
||||
return Ok(NewToken {
|
||||
Ok(NewToken {
|
||||
token: code.clone(),
|
||||
url: auth_url.clone(),
|
||||
message: format!(
|
||||
r#"
|
||||
Generated token:
|
||||
@ -75,22 +71,6 @@ Generated token:
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_new_token(path: &Path, logger_config_color: bool) -> io::Result<String> {
|
||||
let path = codes_path(path);
|
||||
let mut codes = parity_rpc::AuthCodes::from_file(&path)?;
|
||||
|
Loading…
Reference in New Issue
Block a user