From 82d7fc54b33b1ca4ce9769dd89a0b013e87e9f8f Mon Sep 17 00:00:00 2001 From: Nicolas Gotchac Date: Wed, 13 Dec 2017 07:56:35 +0100 Subject: [PATCH] Inject parity script to all dapps // Expand dapps to any ZIP file (#7260) * Inject Parity script to all HTML dapps pages * Small glitch * Add injection test * Add Special GHH commit value for serving ZIP files as DAPPS * Refactor GithubDapp fetcher * PR Grumbles --- dapps/src/apps/fetcher/mod.rs | 84 +++++++++++++++++++++-------------- dapps/src/page/handler.rs | 16 ++++++- dapps/src/tests/fetch.rs | 9 ++-- dapps/src/tests/home.rs | 29 ++++++++++++ hash-fetch/src/client.rs | 3 ++ hash-fetch/src/urlhint.rs | 29 +++++++++--- 6 files changed, 125 insertions(+), 45 deletions(-) diff --git a/dapps/src/apps/fetcher/mod.rs b/dapps/src/apps/fetcher/mod.rs index c75569c51..797b69947 100644 --- a/dapps/src/apps/fetcher/mod.rs +++ b/dapps/src/apps/fetcher/mod.rs @@ -200,39 +200,57 @@ impl Endpoint for ContentFetcher { Some(URLHintResult::Dapp(_)) if self.only_content => { (None, Self::dapps_disabled(self.embeddable_on.clone())) }, - Some(URLHintResult::Dapp(dapp)) => { - let handler = ContentFetcherHandler::new( - req.method(), - &dapp.url(), - path, - installers::Dapp::new( - 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(), - ); - - (Some(ContentStatus::Fetching(handler.fetch_control())), Box::new(handler) as endpoint::Response) - }, - Some(URLHintResult::Content(content)) => { - let handler = ContentFetcherHandler::new( - req.method(), - &content.url, - path, - installers::Content::new( - content_id.clone(), - content.mime, - self.cache_path.clone(), - Box::new(on_done), - self.pool.clone(), - ), - self.embeddable_on.clone(), - self.fetch.clone(), - ); + Some(content) => { + let handler = match content { + URLHintResult::Dapp(dapp) => { + ContentFetcherHandler::new( + req.method(), + &dapp.url(), + path, + installers::Dapp::new( + content_id.clone(), + self.cache_path.clone(), + Box::new(on_done), + self.embeddable_on.clone(), + self.pool.clone(), + ), + self.embeddable_on.clone(), + self.fetch.clone(), + ) + }, + URLHintResult::GithubDapp(content) => { + ContentFetcherHandler::new( + req.method(), + &content.url, + path, + installers::Dapp::new( + content_id.clone(), + self.cache_path.clone(), + Box::new(on_done), + self.embeddable_on.clone(), + self.pool.clone(), + ), + self.embeddable_on.clone(), + self.fetch.clone(), + ) + }, + URLHintResult::Content(content) => { + ContentFetcherHandler::new( + req.method(), + &content.url, + path, + installers::Content::new( + content_id.clone(), + content.mime, + self.cache_path.clone(), + Box::new(on_done), + self.pool.clone(), + ), + self.embeddable_on.clone(), + self.fetch.clone(), + ) + }, + }; (Some(ContentStatus::Fetching(handler.fetch_control())), Box::new(handler) as endpoint::Response) }, diff --git a/dapps/src/page/handler.rs b/dapps/src/page/handler.rs index 56c9a4e1d..576455115 100644 --- a/dapps/src/page/handler.rs +++ b/dapps/src/page/handler.rs @@ -17,8 +17,9 @@ use std::io; use std::time::{Duration, SystemTime}; use hyper::{self, header, StatusCode}; -use hyper::mime::Mime; +use hyper::mime::{self, Mime}; +use apps; use handlers::{Reader, ContentHandler, add_security_headers}; use {Embeddable}; @@ -95,7 +96,18 @@ impl PageHandler { add_security_headers(&mut headers, self.safe_to_embed_on); } - let (reader, body) = Reader::pair(file.into_reader(), Vec::new()); + let initial_content = if file.content_type().to_owned() == mime::TEXT_HTML { + let content = &format!( + r#""#, + apps::UTILS_PATH, + ); + + content.as_bytes().to_vec() + } else { + Vec::new() + }; + + let (reader, body) = Reader::pair(file.into_reader(), initial_content); res.set_body(body); (Some(reader), res) } diff --git a/dapps/src/tests/fetch.rs b/dapps/src/tests/fetch.rs index 69e407dfa..c6ae401e7 100644 --- a/dapps/src/tests/fetch.rs +++ b/dapps/src/tests/fetch.rs @@ -166,14 +166,15 @@ fn should_return_fetched_dapp_content() { response1.assert_status("HTTP/1.1 200 OK"); assert_security_headers_for_embed(&response1.headers); - assert_eq!( - response1.body, - r#"18 + assert!( + response1.body.contains(r#"18

Hello Gavcoin!

0 -"# +"#), + "Expected Gavcoin body: {}", + response1.body ); response2.assert_status("HTTP/1.1 200 OK"); diff --git a/dapps/src/tests/home.rs b/dapps/src/tests/home.rs index fa5c5b4c4..0ee065364 100644 --- a/dapps/src/tests/home.rs +++ b/dapps/src/tests/home.rs @@ -60,3 +60,32 @@ fn should_serve_home() { response.assert_header("Content-Type", "text/html"); assert_security_headers(&response.headers); } + + +#[test] +fn should_inject_js() { + // 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_eq!( + response.body.contains(r#"/inject.js">"#), + true, + "Expected inject script tag in: {}", + response.body + ); + assert_security_headers(&response.headers); +} diff --git a/hash-fetch/src/client.rs b/hash-fetch/src/client.rs index 6a756aa82..65b9d0d22 100644 --- a/hash-fetch/src/client.rs +++ b/hash-fetch/src/client.rs @@ -150,6 +150,9 @@ impl HashFetch for Client { URLHintResult::Dapp(dapp) => { dapp.url() }, + URLHintResult::GithubDapp(content) => { + content.url + }, URLHintResult::Content(content) => { content.url }, diff --git a/hash-fetch/src/urlhint.rs b/hash-fetch/src/urlhint.rs index 0670266df..c629cd8da 100644 --- a/hash-fetch/src/urlhint.rs +++ b/hash-fetch/src/urlhint.rs @@ -32,6 +32,10 @@ use bytes::Bytes; pub type BoxFuture = Box + Send>; const COMMIT_LEN: usize = 20; +/// GithubHint entries with commit set as `0x0..01` should be treated +/// as Github Dapp, downloadable zip files, than can be extracted, containing +/// the manifest.json file along with the dapp +static GITHUB_DAPP_COMMIT: &[u8; COMMIT_LEN] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; /// RAW Contract interface. /// Should execute transaction using current blockchain state. @@ -93,6 +97,8 @@ pub struct Content { pub enum URLHintResult { /// Dapp Dapp(GithubApp), + /// GithubDapp + GithubDapp(Content), /// Content Content(Content), } @@ -122,6 +128,15 @@ impl URLHintContract { } } +fn get_urlhint_content(account_slash_repo: String, owner: Address) -> Content { + let mime = guess_mime_type(&account_slash_repo).unwrap_or(mime::APPLICATION_JSON); + Content { + url: account_slash_repo, + mime, + owner, + } +} + fn decode_urlhint_output(output: (String, ::bigint::hash::H160, Address)) -> Option { let (account_slash_repo, commit, owner) = output; @@ -130,13 +145,15 @@ fn decode_urlhint_output(output: (String, ::bigint::hash::H160, Address)) -> Opt } let commit = GithubApp::commit(&commit); + if commit == Some(Default::default()) { - let mime = guess_mime_type(&account_slash_repo).unwrap_or(mime::APPLICATION_JSON); - return Some(URLHintResult::Content(Content { - url: account_slash_repo, - mime: mime, - owner: owner, - })); + let content = get_urlhint_content(account_slash_repo, owner); + return Some(URLHintResult::Content(content)); + } + + if commit == Some(*GITHUB_DAPP_COMMIT) { + let content = get_urlhint_content(account_slash_repo, owner); + return Some(URLHintResult::GithubDapp(content)); } let (account, repo) = {