Compare commits
2 commits
b7d5425a73
...
6337642b3c
Author | SHA1 | Date | |
---|---|---|---|
6337642b3c | |||
ca71815d22 |
3 changed files with 127 additions and 15 deletions
57
cli/src/fragment.rs
Normal file
57
cli/src/fragment.rs
Normal 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
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue