mirror of
https://github.com/typst/typst
synced 2025-05-15 01:25:28 +08:00
Support proxy and custom certificate configuration. (#2006)
This commit is contained in:
parent
d056280165
commit
6483d3035b
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -660,6 +660,16 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_proxy"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a5019be18538406a43b5419a5501461f0c8b49ea7dfda0cfc32f4e51fc44be1"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -2172,6 +2182,15 @@ dependencies = [
|
|||||||
"sct",
|
"sct",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pemfile"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.100.2"
|
version = "0.100.2"
|
||||||
@ -2906,6 +2925,7 @@ dependencies = [
|
|||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"comemo",
|
"comemo",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
"env_proxy",
|
||||||
"flate2",
|
"flate2",
|
||||||
"inferno",
|
"inferno",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
@ -2913,6 +2933,8 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"open",
|
"open",
|
||||||
"pathdiff 0.1.0",
|
"pathdiff 0.1.0",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pemfile",
|
||||||
"same-file",
|
"same-file",
|
||||||
"self-replace",
|
"self-replace",
|
||||||
"semver",
|
"semver",
|
||||||
|
@ -49,6 +49,9 @@ tracing-error = "0.2"
|
|||||||
tracing-flame = "0.2.0"
|
tracing-flame = "0.2.0"
|
||||||
tracing-subscriber = "0.3.17"
|
tracing-subscriber = "0.3.17"
|
||||||
ureq = "2"
|
ureq = "2"
|
||||||
|
rustls = "0.21"
|
||||||
|
rustls-pemfile = "1"
|
||||||
|
env_proxy = "0.4"
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
xz2 = { version = "0.1", optional = true }
|
xz2 = { version = "0.1", optional = true }
|
||||||
zip = { version = "0.6", optional = true }
|
zip = { version = "0.6", optional = true }
|
||||||
|
@ -17,6 +17,10 @@ pub struct CliArguments {
|
|||||||
/// -v = warning & error, -vv = info, -vvv = debug, -vvvv = trace
|
/// -v = warning & error, -vv = info, -vvv = debug, -vvvv = trace
|
||||||
#[clap(short, long, action = ArgAction::Count)]
|
#[clap(short, long, action = ArgAction::Count)]
|
||||||
pub verbosity: u8,
|
pub verbosity: u8,
|
||||||
|
|
||||||
|
/// Path to a custom CA certificate to use when making network requests.
|
||||||
|
#[clap(long = "cert", env = "TYPST_CERT")]
|
||||||
|
pub cert: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// What to do.
|
/// What to do.
|
||||||
|
@ -1,20 +1,60 @@
|
|||||||
use std::collections::VecDeque;
|
|
||||||
use std::io::{self, ErrorKind, Read, Stderr, Write};
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
use ureq::Response;
|
|
||||||
|
|
||||||
// Acknowledgement:
|
// Acknowledgement:
|
||||||
// Closely modelled after rustup's [`DownloadTracker`].
|
// Closely modelled after rustup's [`DownloadTracker`].
|
||||||
// https://github.com/rust-lang/rustup/blob/master/src/cli/download_tracker.rs
|
// https://github.com/rust-lang/rustup/blob/master/src/cli/download_tracker.rs
|
||||||
|
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::io::{self, ErrorKind, Read, Stderr, Write};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use ureq::Response;
|
||||||
|
|
||||||
/// Keep track of this many download speed samples.
|
/// Keep track of this many download speed samples.
|
||||||
const SPEED_SAMPLES: usize = 5;
|
const SPEED_SAMPLES: usize = 5;
|
||||||
|
|
||||||
|
/// Lazily loads a custom CA certificate if present, but if there's an error
|
||||||
|
/// loading certificate, it just uses the default configuration.
|
||||||
|
static TLS_CONFIG: Lazy<Option<Arc<rustls::ClientConfig>>> = Lazy::new(|| {
|
||||||
|
crate::ARGS
|
||||||
|
.cert
|
||||||
|
.as_ref()
|
||||||
|
.map(|path| {
|
||||||
|
let file = std::fs::OpenOptions::new().read(true).open(path)?;
|
||||||
|
let mut buffer = std::io::BufReader::new(file);
|
||||||
|
let certs = rustls_pemfile::certs(&mut buffer)?;
|
||||||
|
let mut store = rustls::RootCertStore::empty();
|
||||||
|
store.add_parsable_certificates(&certs);
|
||||||
|
let config = rustls::ClientConfig::builder()
|
||||||
|
.with_safe_defaults()
|
||||||
|
.with_root_certificates(store)
|
||||||
|
.with_no_client_auth();
|
||||||
|
Ok::<_, std::io::Error>(Arc::new(config))
|
||||||
|
})
|
||||||
|
.and_then(|x| x.ok())
|
||||||
|
});
|
||||||
|
|
||||||
/// Download binary data and display its progress.
|
/// Download binary data and display its progress.
|
||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub fn download_with_progress(url: &str) -> Result<Vec<u8>, ureq::Error> {
|
pub fn download_with_progress(url: &str) -> Result<Vec<u8>, ureq::Error> {
|
||||||
let response = ureq::get(url).call()?;
|
let mut builder = ureq::AgentBuilder::new()
|
||||||
|
.user_agent(concat!("typst/{}", env!("CARGO_PKG_VERSION")));
|
||||||
|
|
||||||
|
// Get the network proxy config from the environment.
|
||||||
|
if let Some(proxy) = env_proxy::for_url_str(url)
|
||||||
|
.to_url()
|
||||||
|
.and_then(|url| ureq::Proxy::new(url).ok())
|
||||||
|
{
|
||||||
|
builder = builder.proxy(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply a custom CA certificate if present.
|
||||||
|
if let Some(config) = &*TLS_CONFIG {
|
||||||
|
builder = builder.tls_config(config.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let agent = builder.build();
|
||||||
|
let response = agent.get(url).call()?;
|
||||||
Ok(RemoteReader::from_response(response).download()?)
|
Ok(RemoteReader::from_response(response).download()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use walkdir::WalkDir;
|
|||||||
use crate::args::FontsCommand;
|
use crate::args::FontsCommand;
|
||||||
|
|
||||||
/// Execute a font listing command.
|
/// Execute a font listing command.
|
||||||
pub fn fonts(command: FontsCommand) -> StrResult<()> {
|
pub fn fonts(command: &FontsCommand) -> StrResult<()> {
|
||||||
let mut searcher = FontSearcher::new();
|
let mut searcher = FontSearcher::new();
|
||||||
searcher.search(&command.font_paths);
|
searcher.search(&command.font_paths);
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ use std::process::ExitCode;
|
|||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use codespan_reporting::term::{self, termcolor};
|
use codespan_reporting::term::{self, termcolor};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
use termcolor::{ColorChoice, WriteColor};
|
use termcolor::{ColorChoice, WriteColor};
|
||||||
|
|
||||||
use crate::args::{CliArguments, Command};
|
use crate::args::{CliArguments, Command};
|
||||||
@ -26,10 +27,12 @@ thread_local! {
|
|||||||
static EXIT: Cell<ExitCode> = Cell::new(ExitCode::SUCCESS);
|
static EXIT: Cell<ExitCode> = Cell::new(ExitCode::SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The parsed commandline arguments.
|
||||||
|
static ARGS: Lazy<CliArguments> = Lazy::new(CliArguments::parse);
|
||||||
|
|
||||||
/// Entry point.
|
/// Entry point.
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let arguments = CliArguments::parse();
|
let _guard = match crate::tracing::setup_tracing(&ARGS) {
|
||||||
let _guard = match crate::tracing::setup_tracing(&arguments) {
|
|
||||||
Ok(guard) => guard,
|
Ok(guard) => guard,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("failed to initialize tracing {}", err);
|
eprintln!("failed to initialize tracing {}", err);
|
||||||
@ -37,9 +40,9 @@ fn main() -> ExitCode {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = match arguments.command {
|
let res = match &ARGS.command {
|
||||||
Command::Compile(command) => crate::compile::compile(command),
|
Command::Compile(command) => crate::compile::compile(command.clone()),
|
||||||
Command::Watch(command) => crate::watch::watch(command),
|
Command::Watch(command) => crate::watch::watch(command.clone()),
|
||||||
Command::Query(command) => crate::query::query(command),
|
Command::Query(command) => crate::query::query(command),
|
||||||
Command::Fonts(command) => crate::fonts::fonts(command),
|
Command::Fonts(command) => crate::fonts::fonts(command),
|
||||||
Command::Update(command) => crate::update::update(command),
|
Command::Update(command) => crate::update::update(command),
|
||||||
@ -89,7 +92,7 @@ mod update {
|
|||||||
use crate::args::UpdateCommand;
|
use crate::args::UpdateCommand;
|
||||||
use typst::diag::{bail, StrResult};
|
use typst::diag::{bail, StrResult};
|
||||||
|
|
||||||
pub fn update(_: UpdateCommand) -> StrResult<()> {
|
pub fn update(_: &UpdateCommand) -> StrResult<()> {
|
||||||
bail!(
|
bail!(
|
||||||
"self-updating is not enabled for this executable, \
|
"self-updating is not enabled for this executable, \
|
||||||
please update with the package manager or mechanism \
|
please update with the package manager or mechanism \
|
||||||
|
@ -12,7 +12,7 @@ use crate::set_failed;
|
|||||||
use crate::world::SystemWorld;
|
use crate::world::SystemWorld;
|
||||||
|
|
||||||
/// Execute a query command.
|
/// Execute a query command.
|
||||||
pub fn query(command: QueryCommand) -> StrResult<()> {
|
pub fn query(command: &QueryCommand) -> StrResult<()> {
|
||||||
let mut world = SystemWorld::new(&command.common)?;
|
let mut world = SystemWorld::new(&command.common)?;
|
||||||
tracing::info!("Starting querying");
|
tracing::info!("Starting querying");
|
||||||
|
|
||||||
@ -27,8 +27,8 @@ pub fn query(command: QueryCommand) -> StrResult<()> {
|
|||||||
match result {
|
match result {
|
||||||
// Retrieve and print query results.
|
// Retrieve and print query results.
|
||||||
Ok(document) => {
|
Ok(document) => {
|
||||||
let data = retrieve(&world, &command, &document)?;
|
let data = retrieve(&world, command, &document)?;
|
||||||
let serialized = format(data, &command)?;
|
let serialized = format(data, command)?;
|
||||||
println!("{serialized}");
|
println!("{serialized}");
|
||||||
print_diagnostics(&world, &[], &warnings, command.common.diagnostic_format)
|
print_diagnostics(&world, &[], &warnings, command.common.diagnostic_format)
|
||||||
.map_err(|_| "failed to print diagnostics")?;
|
.map_err(|_| "failed to print diagnostics")?;
|
||||||
|
@ -21,7 +21,7 @@ const TYPST_REPO: &str = "typst";
|
|||||||
/// Fetches a target release or the latest release (if no version was specified)
|
/// Fetches a target release or the latest release (if no version was specified)
|
||||||
/// from GitHub, unpacks it and self replaces the current binary with the
|
/// from GitHub, unpacks it and self replaces the current binary with the
|
||||||
/// pre-compiled asset from the downloaded release.
|
/// pre-compiled asset from the downloaded release.
|
||||||
pub fn update(command: UpdateCommand) -> StrResult<()> {
|
pub fn update(command: &UpdateCommand) -> StrResult<()> {
|
||||||
if let Some(ref version) = command.version {
|
if let Some(ref version) = command.version {
|
||||||
let current_tag = env!("CARGO_PKG_VERSION").parse().unwrap();
|
let current_tag = env!("CARGO_PKG_VERSION").parse().unwrap();
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ pub fn update(command: UpdateCommand) -> StrResult<()> {
|
|||||||
fs::copy(current_exe, &backup_path)
|
fs::copy(current_exe, &backup_path)
|
||||||
.map_err(|err| eco_format!("failed to create backup: {err}"))?;
|
.map_err(|err| eco_format!("failed to create backup: {err}"))?;
|
||||||
|
|
||||||
let release = Release::from_tag(command.version)?;
|
let release = Release::from_tag(command.version.as_ref())?;
|
||||||
if !update_needed(&release)? && !command.force {
|
if !update_needed(&release)? && !command.force {
|
||||||
eprintln!("Already up-to-date.");
|
eprintln!("Already up-to-date.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -99,7 +99,7 @@ struct Release {
|
|||||||
impl Release {
|
impl Release {
|
||||||
/// Download the target release, or latest if version is `None`, from the
|
/// Download the target release, or latest if version is `None`, from the
|
||||||
/// Typst repository.
|
/// Typst repository.
|
||||||
pub fn from_tag(tag: Option<Version>) -> StrResult<Release> {
|
pub fn from_tag(tag: Option<&Version>) -> StrResult<Release> {
|
||||||
let url = match tag {
|
let url = match tag {
|
||||||
Some(tag) => format!(
|
Some(tag) => format!(
|
||||||
"https://api.github.com/repos/{}/{}/releases/tags/v{}",
|
"https://api.github.com/repos/{}/{}/releases/tags/v{}",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user