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
This commit is contained in:
Nicolas Gotchac 2017-12-13 07:56:35 +01:00 committed by Svyatoslav Nikolsky
parent f3297dd44a
commit 82d7fc54b3
6 changed files with 125 additions and 45 deletions

View File

@ -200,39 +200,57 @@ impl<R: URLHint + 'static, F: Fetch> Endpoint for ContentFetcher<F, R> {
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)
},

View File

@ -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<T: DappFile> PageHandler<T> {
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#"<script src="/{}/inject.js"></script>"#,
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)
}

View File

@ -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
<h1>Hello Gavcoin!</h1>
0
"#
"#),
"Expected Gavcoin body: {}",
response1.body
);
response2.assert_status("HTTP/1.1 200 OK");

View File

@ -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"></script>"#),
true,
"Expected inject script tag in: {}",
response.body
);
assert_security_headers(&response.headers);
}

View File

@ -150,6 +150,9 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
URLHintResult::Dapp(dapp) => {
dapp.url()
},
URLHintResult::GithubDapp(content) => {
content.url
},
URLHintResult::Content(content) => {
content.url
},

View File

@ -32,6 +32,10 @@ use bytes::Bytes;
pub type BoxFuture<A, B> = Box<Future<Item = A, Error = B> + 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<URLHintResult> {
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) = {