merge main

This commit is contained in:
Bryce Miller 2023-06-05 20:21:44 -04:00
commit 29561372de
No known key found for this signature in database
GPG key ID: F1E97BF8DF152350
126 changed files with 3728 additions and 2429 deletions

View file

@ -7,6 +7,11 @@ use std::path::{Path, PathBuf};
use std::{fmt, io};
use ven_pretty::{text, BoxAllocator, DocAllocator, DocBuilder, Render, RenderAnnotated};
#[cfg(not(target_family = "wasm"))]
use byte_unit::Byte;
#[cfg(not(target_family = "wasm"))]
use roc_packaging::https::Problem;
pub use crate::error::canonicalize::can_problem;
pub use crate::error::parse::parse_problem;
pub use crate::error::r#type::type_problem;
@ -1075,6 +1080,471 @@ where
}
}
#[cfg(not(target_family = "wasm"))]
pub fn to_https_problem_report_string(url: &str, https_problem: Problem) -> String {
let src_lines: Vec<&str> = Vec::new();
let mut module_ids = ModuleIds::default();
let module_id = module_ids.get_or_insert(&"find module name somehow?".into());
let interns = Interns::default();
// Report parsing and canonicalization problems
let alloc = RocDocAllocator::new(&src_lines, module_id, &interns);
let mut buf = String::new();
let palette = DEFAULT_PALETTE;
let report = to_https_problem_report(&alloc, url, https_problem);
report.render_color_terminal(&mut buf, &alloc, &palette);
buf
}
#[cfg(not(target_family = "wasm"))]
pub fn to_https_problem_report<'b>(
alloc: &'b RocDocAllocator<'b>,
url: &'b str,
https_problem: Problem,
) -> Report<'b> {
match https_problem {
Problem::UnsupportedEncoding(not_supported_encoding) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc.string((&url).to_string()).annotate(Annotation::Url).indent(4),
alloc.concat([
alloc.reflow(r"But the server replied with a "),
alloc.reflow(r"content encoding").annotate(Annotation::Emphasized),
alloc.reflow(r" that I do not understand ("),
alloc.string(not_supported_encoding).annotate(Annotation::Emphasized),
alloc.reflow(r")."),
]),
alloc.concat([
alloc.reflow(r"The supported content encodings are "),
alloc.keyword(r"br"),
alloc.reflow(r", "),
alloc.keyword(r"gzip"),
alloc.reflow(r" and "),
alloc.keyword(r"deflate"),
]),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Perhaps you can check if the URL is correctly formed, or if the server is correctly configured."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "UNSUPPORTED ENCODING".to_string(),
severity: Severity::Fatal,
}
}
Problem::MultipleEncodings(multiple_encodings) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc.string((&url).to_string()).annotate(Annotation::Url).indent(4),
alloc.concat([
alloc.reflow(r"But the server replied with multiple "),
alloc.reflow(r"content encodings").annotate(Annotation::Emphasized),
alloc.reflow(r": "),
alloc.string(multiple_encodings).annotate(Annotation::Emphasized),
alloc.reflow(r"."),
]),
alloc.concat([
alloc.reflow(r"The supported content encodings are "),
alloc.keyword(r"br"),
alloc.reflow(r", "),
alloc.keyword(r"gzip"),
alloc.reflow(r" and "),
alloc.keyword(r"deflate"),
alloc.reflow(r". However, the server reply can only contain "),
alloc.reflow(r"one").annotate(Annotation::Emphasized),
alloc.reflow(r"."),
]),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Perhaps you can check if the URL is correctly formed, or if the server is correctly configured."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "MULTIPLE ENCODINGS".to_string(),
severity: Severity::Fatal,
}
}
Problem::InvalidContentHash { expected, actual } => {
let doc = alloc.stack([
alloc.reflow(r"I was able to download this URL:"),
alloc.string((&url).to_string()).annotate(Annotation::Url).indent(4),
alloc.concat([
alloc.reflow(r"I use a mechanism to detect if the file might "),
alloc.reflow(r"have been tampered with. This could happen if "),
alloc.reflow(r"the server or domain have been compromised."),
]),
alloc.concat([
alloc.reflow(r"This is the content signature I was "),
alloc.reflow(r"expecting").annotate(Annotation::Emphasized),
alloc.reflow(r":"),
]),
alloc.string(expected).annotate(Annotation::PlainText).indent(4),
alloc.concat([
alloc.reflow(r"However, this is the content signature I "),
alloc.reflow(r"obtained").annotate(Annotation::Emphasized),
alloc.reflow(r":"),
]),
alloc.string(actual).annotate(Annotation::PlainText).indent(4),
alloc.reflow(r"To keep you secure, I will not execute this untrusted code."),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Check if the URL is correctly formed and if this is the server you are expecting to connect to."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "INVALID CONTENT HASH".to_string(),
severity: Severity::Fatal,
}
}
// TODO: The reporting text for IoErr and FsExtraErr could probably be unified
Problem::IoErr(io_error) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.reflow(r"But I encountered an IO (input/output) error:"),
alloc
.string(io_error.to_string())
.annotate(Annotation::PlainText)
.indent(4),
// TODO: What should the tip for IO errors be?
// alloc.concat([
// alloc.tip(),
// alloc.reflow(r"Check the error message."),
// ]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "IO ERROR".to_string(),
severity: Severity::Fatal,
}
}
// TODO: The reporting text for IoErr and FsExtraErr could probably be unified
Problem::FsExtraErr(fs_extra_error) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.reflow(r"But I encountered an IO (input/output) error:"),
alloc
.string(fs_extra_error.to_string())
.annotate(Annotation::PlainText)
.indent(4),
// TODO: What should the tip for IO errors be?
// alloc.concat([
// alloc.tip(),
// alloc.reflow(r"Check the error message."),
// ]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "IO ERROR".to_string(),
severity: Severity::Fatal,
}
}
Problem::HttpErr(reqwest_error) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.reflow(r"But I encountered a network error:"),
alloc
.string(reqwest_error.to_string())
.annotate(Annotation::PlainText)
.indent(4),
// TODO: What should the tip for HTTP IO errors be?
// Should we import reqwest and check stuff like
// reqwest_error.{ is_redirect(), is_status(), is_timeout(), ... } ?
//
// alloc.concat([
// alloc.tip(),
// alloc.reflow(r"Check the error message."),
// ]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "HTTP ERROR".to_string(),
severity: Severity::Fatal,
}
}
Problem::InvalidUrl(roc_packaging::https::UrlProblem::InvalidExtensionSuffix(
invalid_suffix,
)) => {
let (suffix_text, annotation_style) = if invalid_suffix.is_empty() {
(r"empty".to_string(), Annotation::PlainText)
} else {
(invalid_suffix, Annotation::Emphasized)
};
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.concat([
alloc.reflow(r"However, this file's extension ("),
alloc.string(suffix_text).annotate(annotation_style),
alloc.reflow(r") is not a supported extension."),
]),
alloc.concat([
alloc.reflow(r"The supported extensions are "),
alloc.keyword(r".tar"),
alloc.reflow(r", "),
alloc.keyword(r".tar.gz"),
alloc.reflow(r" and "),
alloc.keyword(r".tar.br"),
]),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Check that you have the correct URL for this package/platform."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "INVALID EXTENSION SUFFIX".to_string(),
severity: Severity::Fatal,
}
}
Problem::InvalidUrl(roc_packaging::https::UrlProblem::MissingTarExt) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.concat([
alloc.reflow(r"However, this file's extension is not "),
alloc.keyword(r".tar"),
alloc.reflow(r"."),
]),
alloc.concat([
alloc.reflow(r"The supported extensions are "),
alloc.keyword(r".tar"),
alloc.reflow(r", "),
alloc.keyword(r".tar.gz"),
alloc.reflow(r" and "),
alloc.keyword(r".tar.br"),
]),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Check that you have the correct URL for this package/platform."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "INVALID EXTENSION".to_string(),
severity: Severity::Fatal,
}
}
Problem::InvalidUrl(roc_packaging::https::UrlProblem::InvalidFragment(
invalid_fragment,
)) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.concat([
alloc.reflow(r"However, this URL's fragment (the part after #) "),
alloc.reflow(r"is not valid. When present, the fragment must point to "),
alloc.reflow(r"an existing "),
alloc.keyword(r".roc"),
alloc.reflow(r" file inside the package. Also, the filename can't be empty, "),
alloc.reflow(r"so a fragment of #.roc would also not be valid. This is the "),
alloc.reflow(r"invalid fragment I encountered: "),
]),
alloc
.string(invalid_fragment)
.annotate(Annotation::Emphasized)
.indent(4),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Check that the fragment points to an existing "),
alloc.keyword(r".roc"),
alloc.reflow(r" file inside the package. You can download this package "),
alloc.reflow(r"and inspect it locally."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "INVALID FRAGMENT".to_string(),
severity: Severity::Fatal,
}
}
Problem::InvalidUrl(roc_packaging::https::UrlProblem::MissingHash) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.concat([
alloc.reflow(r"I use a content hash to detect if the file might "),
alloc.reflow(r"have been tampered with. This could happen if "),
alloc.reflow(r"the server or domain have been compromised."),
]),
alloc.concat([
alloc.reflow(r"The way this works is that the name of the file "),
alloc.reflow(r"is the BLAKE3 hash of the contents of the "),
alloc.reflow(r"file itself. If someone would tamper with the file, "),
alloc.reflow(r"I could notify and protect you. However, I could "),
alloc.reflow(r"not find the expected hash on the URL above, "),
alloc.reflow(r"so I cannot apply this tamper-check."),
]),
alloc.concat([
alloc.tip(),
alloc
.reflow(r"Check that you have the correct URL for this package/platform. "),
alloc.reflow(r"Here is an example of how such a hash looks like: "),
alloc
.string(r"tE4xS_zLdmmxmHwHih9kHWQ7fsXtJr7W7h3425-eZFk".to_string())
.annotate(Annotation::Emphasized),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "MISSING PACKAGE HASH".to_string(),
severity: Severity::Fatal,
}
}
Problem::InvalidUrl(roc_packaging::https::UrlProblem::MissingHttps) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.concat([
alloc.reflow(r"For your security, I will only attempt to download "),
alloc.reflow(r"files from servers which use the "),
alloc.keyword(r"https"),
alloc.reflow(r" protocol."),
]),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Check that you have the correct URL for this package/platform."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "HTTPS MANDATORY".to_string(),
severity: Severity::Fatal,
}
}
Problem::InvalidUrl(roc_packaging::https::UrlProblem::MisleadingCharacter) => {
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.concat([
alloc.reflow(r"I have found one or more potentially misleading "),
alloc.reflow(r"characters in this URL. Misleading characters are "),
alloc.reflow(r"characters that look like others but aren't the same. "),
alloc.reflow(r"The following characters are classified as misleading: "),
alloc.keyword(r"@"),
alloc.reflow(r", "),
alloc.keyword("\u{2044}"),
alloc.reflow(r" (unicode 2044), "),
alloc.keyword("\u{2215}"),
alloc.reflow(r" (unicode 2215), "),
alloc.keyword("\u{FF0F}"),
alloc.reflow(r" (unicode FF0F) and "),
alloc.keyword("\u{29F8}"),
alloc.reflow(r" (unicode 29F8). "),
]),
alloc.concat([
alloc.reflow(r"If you have a use-case for any of these characters we "),
alloc.reflow(r"would like to hear about it. Reach out on "),
alloc
.string(r"https://github.com/roc-lang/roc/issues/5487".to_string())
.annotate(Annotation::Url),
]),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Check that you have the correct URL for this package/platform."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "MISLEADING CHARACTERS".to_string(),
severity: Severity::Fatal,
}
}
Problem::DownloadTooBig(content_len) => {
let nice_bytes = Byte::from_bytes(content_len.into())
.get_appropriate_unit(false)
.format(3);
let doc = alloc.stack([
alloc.reflow(r"I was trying to download this URL:"),
alloc
.string((&url).to_string())
.annotate(Annotation::Url)
.indent(4),
alloc.concat([
alloc.reflow(r"But the server stated this file is "),
alloc.string(nice_bytes).annotate(Annotation::Keyword),
alloc.reflow(r" in size. This is larger that the maximum size I can handle (around 32 GB)."),
]),
alloc.concat([
alloc.tip(),
alloc.reflow(r"Check that you have the correct URL for this package/platform. "),
alloc.reflow(r"If you do, you should contact the package/platform's author and "),
alloc.reflow(r"notify them about this issue."),
]),
]);
Report {
filename: "UNKNOWN.roc".into(),
doc,
title: "FILE TOO LARGE".to_string(),
severity: Severity::Fatal,
}
}
}
}
pub fn to_file_problem_report_string(filename: &Path, error: io::ErrorKind) -> String {
let src_lines: Vec<&str> = Vec::new();