Compare commits

..

2 commits

3 changed files with 127 additions and 15 deletions

57
cli/src/fragment.rs Normal file
View file

@ -0,0 +1,57 @@
use omegaupload_common::secrecy::{ExposeSecret, SecretString};
pub struct Builder {
decryption_key: SecretString,
needs_password: bool,
file_name: Option<String>,
language: Option<String>,
}
impl Builder {
pub fn new(decryption_key: SecretString) -> Self {
Self {
decryption_key,
needs_password: false,
file_name: None,
language: None,
}
}
pub fn needs_password(mut self) -> Self {
self.needs_password = true;
self
}
pub fn file_name(mut self, name: String) -> Self {
self.file_name = Some(name);
self
}
pub fn language(mut self, language: String) -> Self {
self.language = Some(language);
self
}
pub fn build(self) -> SecretString {
if !self.needs_password && self.file_name.is_none() && self.language.is_none() {
return self.decryption_key;
}
let mut args = String::new();
if self.needs_password {
args.push_str("!pw");
}
if let Some(file_name) = self.file_name {
args.push_str("!name:");
args.push_str(&file_name);
}
if let Some(language) = self.language {
args.push_str("!lang:");
args.push_str(&language);
}
SecretString::new(format!(
"key:{}{}",
self.decryption_key.expose_secret(),
args
))
}
}

View file

@ -24,7 +24,7 @@ use anyhow::{anyhow, bail, Context, Result};
use atty::Stream; use atty::Stream;
use clap::Parser; use clap::Parser;
use omegaupload_common::crypto::{open_in_place, seal_in_place}; use omegaupload_common::crypto::{open_in_place, seal_in_place};
use omegaupload_common::secrecy::{ExposeSecret, SecretVec}; use omegaupload_common::secrecy::{ExposeSecret, SecretString, SecretVec};
use omegaupload_common::{ use omegaupload_common::{
base64, Expiration, ParsedUrl, Url, API_ENDPOINT, EXPIRATION_HEADER_NAME, base64, Expiration, ParsedUrl, Url, API_ENDPOINT, EXPIRATION_HEADER_NAME,
}; };
@ -33,6 +33,10 @@ use reqwest::header::EXPIRES;
use reqwest::StatusCode; use reqwest::StatusCode;
use rpassword::prompt_password_stderr; use rpassword::prompt_password_stderr;
use crate::fragment::Builder;
mod fragment;
#[derive(Parser)] #[derive(Parser)]
struct Opts { struct Opts {
#[clap(subcommand)] #[clap(subcommand)]
@ -53,6 +57,13 @@ enum Action {
/// The path to the file to upload. If none is provided, then reads /// The path to the file to upload. If none is provided, then reads
/// stdin instead. /// stdin instead.
path: Option<PathBuf>, path: Option<PathBuf>,
/// Hint that the uploaded file should be syntax highlighted with a
/// specific language.
#[clap(short, long)]
language: Option<String>,
/// Don't provide a file name hint.
#[clap(short = 'F', long)]
no_file_name_hint: bool,
}, },
Download { Download {
/// The paste to download. /// The paste to download.
@ -69,7 +80,9 @@ fn main() -> Result<()> {
password, password,
duration, duration,
path, path,
} => handle_upload(url, password, duration, path), language,
no_file_name_hint,
} => handle_upload(url, password, duration, path, language, no_file_name_hint),
Action::Download { url } => handle_download(url), Action::Download { url } => handle_download(url),
}?; }?;
@ -81,6 +94,8 @@ fn handle_upload(
password: bool, password: bool,
duration: Option<Expiration>, duration: Option<Expiration>,
path: Option<PathBuf>, path: Option<PathBuf>,
language: Option<String>,
no_file_name_hint: bool,
) -> Result<()> { ) -> Result<()> {
url.set_fragment(None); url.set_fragment(None);
@ -89,7 +104,7 @@ fn handle_upload(
} }
let (data, key) = { let (data, key) = {
let mut container = if let Some(path) = path { let mut container = if let Some(ref path) = path {
std::fs::read(path)? std::fs::read(path)?
} else { } else {
let mut container = vec![]; let mut container = vec![];
@ -110,7 +125,7 @@ fn handle_upload(
}; };
let enc_key = seal_in_place(&mut container, password)?; let enc_key = seal_in_place(&mut container, password)?;
let key = base64::encode(&enc_key.expose_secret().as_ref()); let key = SecretString::new(base64::encode(&enc_key.expose_secret().as_ref()));
(container, key) (container, key)
}; };
@ -130,13 +145,22 @@ fn handle_upload(
.map_err(|_| anyhow!("Failed to get base URL"))? .map_err(|_| anyhow!("Failed to get base URL"))?
.extend(std::iter::once(res.text()?)); .extend(std::iter::once(res.text()?));
let fragment = if password { let mut fragment = Builder::new(key);
format!("key:{}!pw", key) if password {
} else { fragment = fragment.needs_password();
key }
};
url.set_fragment(Some(&fragment)); if !no_file_name_hint {
if let Some(path) = path {
fragment = fragment.file_name(path.to_string_lossy().to_string());
}
}
if let Some(language) = language {
fragment = fragment.language(language);
}
url.set_fragment(Some(&fragment.build().expose_secret()));
println!("{}", url); println!("{}", url);

View file

@ -106,13 +106,44 @@ function createStringPasteUi(data, mimeType: string, name?: string, lang?: strin
mainEle.appendChild(preEle); mainEle.appendChild(preEle);
bodyEle.appendChild(mainEle); bodyEle.appendChild(mainEle);
let languages = undefined;
if (!hljs.getLanguage(lang)) { if (!hljs.getLanguage(lang)) {
console.warn(`[js] User provided language (${lang}) is not known. Ignoring.`); console.warn(`[js] User provided language (${lang}) is not known.`);
} else { } else {
console.log(`[js] Selecting user provided language ${lang} for highlighting.`); languages = [lang];
hljs.configure({ }
languages: [lang],
}); // If a language wasn't provided, see if we can use the file extension to give
// us a better hint for hljs
if (!languages) {
if (name) {
console.log("[js] Trying to infer from file name...");
const periodIndex = name.indexOf(".");
if (periodIndex === -1) {
console.warn("[js] Did not find file extension.")
} else {
let extension = name.slice(periodIndex + 1);
console.info(`[js] Found extension ${extension}.`);
if (!hljs.getLanguage(extension)) {
console.warn(`[js] Extension was not recognized by hljs. Giving up.`);
} else {
console.info("[js] Successfully inferred language from file extension.");
languages = [extension];
}
}
} else {
console.log("[js] No file name hint provided.");
}
} else {
console.info(`[js] Selecting user provided language ${languages[0]} for highlighting.`);
}
// If we still haven't set languages here, then we're leaving it up to the
if (!languages) {
console.log("[js] Deferring to hljs inference for syntax highlighting.");
} else {
hljs.configure({ languages });
} }
hljs.highlightAll(); hljs.highlightAll();