Add support for language and name hints
This commit is contained in:
parent
9b2f53bddf
commit
b7d5425a73
5 changed files with 147 additions and 72 deletions
|
@ -52,6 +52,8 @@ pub struct ParsedUrl {
|
|||
pub struct PartialParsedUrl {
|
||||
pub decryption_key: Option<Secret<Key>>,
|
||||
pub needs_password: bool,
|
||||
pub name: Option<String>,
|
||||
pub language: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -91,7 +93,7 @@ impl TryFrom<&str> for PartialParsedUrl {
|
|||
|
||||
return Ok(Self {
|
||||
decryption_key,
|
||||
needs_password: false,
|
||||
..Self::default()
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,6 +108,8 @@ impl TryFrom<&str> for PartialParsedUrl {
|
|||
|
||||
let mut decryption_key = None;
|
||||
let mut needs_password = false;
|
||||
let mut name = None;
|
||||
let mut language = None;
|
||||
|
||||
for (key, value) in args {
|
||||
match (key, value) {
|
||||
|
@ -117,6 +121,8 @@ impl TryFrom<&str> for PartialParsedUrl {
|
|||
("pw", _) => {
|
||||
needs_password = true;
|
||||
}
|
||||
("name", Some(provided_name)) => name = Some(provided_name.to_owned()),
|
||||
("lang", Some(provided_lang)) => language = Some(provided_lang.to_owned()),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +130,8 @@ impl TryFrom<&str> for PartialParsedUrl {
|
|||
Ok(Self {
|
||||
decryption_key,
|
||||
needs_password,
|
||||
name,
|
||||
language,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -159,6 +167,7 @@ impl FromStr for ParsedUrl {
|
|||
let PartialParsedUrl {
|
||||
mut decryption_key,
|
||||
needs_password,
|
||||
..
|
||||
} = PartialParsedUrl::try_from(fragment)?;
|
||||
|
||||
url.set_fragment(None);
|
||||
|
@ -338,7 +347,7 @@ mod partial_parsed_url_parsing {
|
|||
DECRYPTION_KEY_STRING.parse(),
|
||||
Ok(PartialParsedUrl {
|
||||
decryption_key: decryption_key(),
|
||||
needs_password: false
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -350,7 +359,7 @@ mod partial_parsed_url_parsing {
|
|||
input.parse(),
|
||||
Ok(PartialParsedUrl {
|
||||
decryption_key: decryption_key(),
|
||||
needs_password: false
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -362,7 +371,34 @@ mod partial_parsed_url_parsing {
|
|||
input.parse(),
|
||||
Ok(PartialParsedUrl {
|
||||
decryption_key: decryption_key(),
|
||||
needs_password: true
|
||||
needs_password: true,
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_name() {
|
||||
let input = "key:ddLod7sGy_EjFDjWqZoH4i5n_XU8bIpEuEo3-pjfAIE=!name:test_file.rs";
|
||||
assert_eq!(
|
||||
input.parse(),
|
||||
Ok(PartialParsedUrl {
|
||||
decryption_key: decryption_key(),
|
||||
name: Some("test_file.rs".to_owned()),
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_lang() {
|
||||
let input = "key:ddLod7sGy_EjFDjWqZoH4i5n_XU8bIpEuEo3-pjfAIE=!lang:rust";
|
||||
assert_eq!(
|
||||
input.parse(),
|
||||
Ok(PartialParsedUrl {
|
||||
decryption_key: decryption_key(),
|
||||
language: Some("rust".to_owned()),
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -374,7 +410,8 @@ mod partial_parsed_url_parsing {
|
|||
input.parse(),
|
||||
Ok(PartialParsedUrl {
|
||||
decryption_key: decryption_key(),
|
||||
needs_password: true
|
||||
needs_password: true,
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -386,7 +423,7 @@ mod partial_parsed_url_parsing {
|
|||
input.parse(),
|
||||
Ok(PartialParsedUrl {
|
||||
decryption_key: decryption_key(),
|
||||
needs_password: false
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<script src="static/highlightjs-line-numbers.min.js" defer></script>
|
||||
|
||||
<link data-trunk rel="rust" data-wasm-opt="0" data-keep-debug="true" data-no-mangle="true" />
|
||||
<link data-trunk rel="copy-file" href="vendor/MPLUS_FONTS/fonts/ttf/MplusCodeLatin[wdth,wght].ttf" dest="/" />
|
||||
<link data-trunk rel="copy-file" href="vendor/MPLUS_FONTS/fonts/ttf/MPLUSCodeLatin[wdth,wght].ttf" dest="/" />
|
||||
<link data-trunk rel="copy-file" href="vendor/highlight.min.js" dest="/" />
|
||||
<link data-trunk rel="copy-file" href="vendor/highlightjs-line-numbers.js/dist/highlightjs-line-numbers.min.js"
|
||||
dest="/" />
|
||||
|
|
|
@ -47,7 +47,7 @@ const DOWNLOAD_SIZE_LIMIT: u128 = n_mib_bytes!(500);
|
|||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_name = loadFromDb)]
|
||||
pub fn load_from_db(mimetype: JsString);
|
||||
pub fn load_from_db(mime_type: JsString, name: Option<JsString>, language: Option<JsString>);
|
||||
#[wasm_bindgen(js_name = renderMessage)]
|
||||
pub fn render_message(message: JsString);
|
||||
}
|
||||
|
@ -88,7 +88,15 @@ fn main() {
|
|||
Uri::from_parts(uri_parts).unwrap()
|
||||
};
|
||||
|
||||
let (key, needs_pw) = {
|
||||
let (
|
||||
key,
|
||||
PartialParsedUrl {
|
||||
needs_password,
|
||||
name,
|
||||
language,
|
||||
..
|
||||
},
|
||||
) = {
|
||||
let fragment = if let Some(fragment) = url.split_once('#').map(|(_, fragment)| fragment) {
|
||||
if fragment.is_empty() {
|
||||
error!("Key is missing in url; bailing.");
|
||||
|
@ -102,7 +110,7 @@ fn main() {
|
|||
return;
|
||||
};
|
||||
|
||||
let partial_parsed_url = match PartialParsedUrl::try_from(fragment) {
|
||||
let mut partial_parsed_url = match PartialParsedUrl::try_from(fragment) {
|
||||
Ok(partial_parsed_url) => partial_parsed_url,
|
||||
Err(e) => {
|
||||
error!("Failed to parse text fragment; bailing.");
|
||||
|
@ -111,7 +119,7 @@ fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
let key = if let Some(key) = partial_parsed_url.decryption_key {
|
||||
let key = if let Some(key) = partial_parsed_url.decryption_key.take() {
|
||||
key
|
||||
} else {
|
||||
error!("Key is missing in url; bailing.");
|
||||
|
@ -119,10 +127,10 @@ fn main() {
|
|||
return;
|
||||
};
|
||||
|
||||
(key, partial_parsed_url.needs_password)
|
||||
(key, partial_parsed_url)
|
||||
};
|
||||
|
||||
let password = if needs_pw {
|
||||
let password = if needs_password {
|
||||
loop {
|
||||
let pw = window().prompt_with_message("A password is required to decrypt this paste:");
|
||||
|
||||
|
@ -150,7 +158,7 @@ fn main() {
|
|||
};
|
||||
|
||||
spawn_local(async move {
|
||||
if let Err(e) = fetch_resources(request_uri, key, password).await {
|
||||
if let Err(e) = fetch_resources(request_uri, key, password, name, language).await {
|
||||
log!(e.to_string());
|
||||
}
|
||||
});
|
||||
|
@ -161,6 +169,8 @@ async fn fetch_resources(
|
|||
request_uri: Uri,
|
||||
key: Secret<Key>,
|
||||
password: Option<SecretVec<u8>>,
|
||||
name: Option<String>,
|
||||
language: Option<String>,
|
||||
) -> Result<()> {
|
||||
match Request::get(&request_uri.to_string()).send().await {
|
||||
Ok(resp) if resp.status() == StatusCode::OK => {
|
||||
|
@ -213,7 +223,7 @@ async fn fetch_resources(
|
|||
let db_open_req = open_idb()?;
|
||||
|
||||
let on_success = Closure::once(Box::new(move |event| {
|
||||
on_success(&event, &decrypted, mimetype, &expires);
|
||||
on_success(&event, &decrypted, mimetype, &expires, name, language);
|
||||
}));
|
||||
|
||||
db_open_req.set_onsuccess(Some(on_success.into_js_value().unchecked_ref()));
|
||||
|
@ -245,7 +255,14 @@ async fn fetch_resources(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn on_success(event: &Event, decrypted: &DecryptedData, mimetype: MimeType, expires: &str) {
|
||||
fn on_success(
|
||||
event: &Event,
|
||||
decrypted: &DecryptedData,
|
||||
mimetype: MimeType,
|
||||
expires: &str,
|
||||
name: Option<String>,
|
||||
language: Option<String>,
|
||||
) {
|
||||
let transaction: IdbObjectStore = as_idb_db(event)
|
||||
.transaction_with_str_and_mode("decrypted data", IdbTransactionMode::Readwrite)
|
||||
.unwrap()
|
||||
|
@ -294,7 +311,9 @@ fn on_success(event: &Event, decrypted: &DecryptedData, mimetype: MimeType, expi
|
|||
put_action.set_onsuccess(Some(
|
||||
Closure::once(Box::new(|| {
|
||||
log!("success");
|
||||
load_from_db(JsString::from(mimetype.0));
|
||||
let name = name.map(JsString::from);
|
||||
let language = language.map(JsString::from);
|
||||
load_from_db(JsString::from(mimetype.0), name, language);
|
||||
}))
|
||||
.into_js_value()
|
||||
.unchecked_ref(),
|
||||
|
|
|
@ -20,7 +20,7 @@ $padding: 1em;
|
|||
|
||||
@font-face {
|
||||
font-family: "Mplus Code";
|
||||
src: url("./MplusCodeLatin[wdth,wght].ttf") format("truetype");
|
||||
src: url("./MPLUSCodeLatin[wdth,wght].ttf") format("truetype");
|
||||
}
|
||||
|
||||
body {
|
||||
|
|
127
web/src/main.ts
127
web/src/main.ts
|
@ -15,35 +15,38 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// Exported to main.rs
|
||||
function loadFromDb(mimetype: string) {
|
||||
console.log("Got mime type:", mimetype);
|
||||
function loadFromDb(mimeType: string, name?: string, language?: string) {
|
||||
console.log("[js] Got name:", name);
|
||||
console.log("[js] Got language:", language);
|
||||
console.log("[js] Got mime type:", mimeType);
|
||||
|
||||
const dbReq = window.indexedDB.open("omegaupload", 1);
|
||||
dbReq.onsuccess = (evt) => {
|
||||
const db = (evt.target as IDBRequest).result;
|
||||
const obj_store = db
|
||||
.transaction("decrypted data")
|
||||
.objectStore("decrypted data");
|
||||
let fetchReq = obj_store.get(window.location.pathname);
|
||||
const fetchReq = obj_store.get(window.location.pathname);
|
||||
fetchReq.onsuccess = (evt) => {
|
||||
const data = (evt.target as IDBRequest).result;
|
||||
switch (data.type) {
|
||||
case "string":
|
||||
createStringPasteUi(data, mimetype);
|
||||
createStringPasteUi(data, mimeType, name, language);
|
||||
break;
|
||||
case "blob":
|
||||
createBlobPasteUi(data);
|
||||
createBlobPasteUi(data, name);
|
||||
break;
|
||||
case "image":
|
||||
createImagePasteUi(data);
|
||||
createImagePasteUi(data, name);
|
||||
break;
|
||||
case "audio":
|
||||
createAudioPasteUi(data);
|
||||
createAudioPasteUi(data, name);
|
||||
break;
|
||||
case "video":
|
||||
createVideoPasteUi(data);
|
||||
createVideoPasteUi(data, name);
|
||||
break;
|
||||
case "archive":
|
||||
createArchivePasteUi(data);
|
||||
createArchivePasteUi(data, name);
|
||||
break;
|
||||
default:
|
||||
renderMessage("Something went wrong. Try clearing local data.");
|
||||
|
@ -71,23 +74,24 @@ function loadFromDb(mimetype: string) {
|
|||
};
|
||||
}
|
||||
|
||||
function createStringPasteUi(data, type: string) {
|
||||
let bodyEle = document.getElementsByTagName("body")[0];
|
||||
function createStringPasteUi(data, mimeType: string, name?: string, lang?: string) {
|
||||
const bodyEle = document.getElementsByTagName("body")[0];
|
||||
bodyEle.textContent = '';
|
||||
|
||||
let mainEle = document.createElement("main");
|
||||
let preEle = document.createElement("pre");
|
||||
const mainEle = document.createElement("main");
|
||||
const preEle = document.createElement("pre");
|
||||
preEle.classList.add("paste");
|
||||
|
||||
let headerEle = document.createElement("p");
|
||||
const headerEle = document.createElement("p");
|
||||
headerEle.classList.add("unselectable");
|
||||
headerEle.classList.add("centered");
|
||||
headerEle.textContent = data.expiration;
|
||||
preEle.appendChild(headerEle);
|
||||
|
||||
let downloadEle = document.createElement("a");
|
||||
downloadEle.href = URL.createObjectURL(new Blob([data.data], { type }));
|
||||
downloadEle.download = window.location.pathname;
|
||||
const downloadEle = document.createElement("a");
|
||||
downloadEle.href = getObjectUrl([data.data], mimeType);
|
||||
downloadEle.download = name;
|
||||
|
||||
downloadEle.classList.add("hljs-meta");
|
||||
downloadEle.classList.add("centered");
|
||||
downloadEle.textContent = "Download file.";
|
||||
|
@ -95,43 +99,52 @@ function createStringPasteUi(data, type: string) {
|
|||
|
||||
preEle.appendChild(document.createElement("hr"));
|
||||
|
||||
let codeEle = document.createElement("code");
|
||||
const codeEle = document.createElement("code");
|
||||
codeEle.textContent = data.data;
|
||||
preEle.appendChild(codeEle);
|
||||
|
||||
mainEle.appendChild(preEle);
|
||||
bodyEle.appendChild(mainEle);
|
||||
|
||||
if (!hljs.getLanguage(lang)) {
|
||||
console.warn(`[js] User provided language (${lang}) is not known. Ignoring.`);
|
||||
} else {
|
||||
console.log(`[js] Selecting user provided language ${lang} for highlighting.`);
|
||||
hljs.configure({
|
||||
languages: [lang],
|
||||
});
|
||||
}
|
||||
|
||||
hljs.highlightAll();
|
||||
hljs.initLineNumbersOnLoad();
|
||||
}
|
||||
|
||||
function createBlobPasteUi(data) {
|
||||
let bodyEle = document.getElementsByTagName("body")[0];
|
||||
function createBlobPasteUi(data, name?: string) {
|
||||
const bodyEle = document.getElementsByTagName("body")[0];
|
||||
bodyEle.textContent = '';
|
||||
|
||||
let mainEle = document.createElement("main");
|
||||
const mainEle = document.createElement("main");
|
||||
mainEle.classList.add("hljs");
|
||||
mainEle.classList.add("centered");
|
||||
mainEle.classList.add("fullscreen");
|
||||
|
||||
let divEle = document.createElement("div");
|
||||
const divEle = document.createElement("div");
|
||||
divEle.classList.add("centered");
|
||||
|
||||
let expirationEle = document.createElement("p");
|
||||
const expirationEle = document.createElement("p");
|
||||
expirationEle.textContent = data.expiration;
|
||||
divEle.appendChild(expirationEle);
|
||||
|
||||
let downloadEle = document.createElement("a");
|
||||
downloadEle.href = URL.createObjectURL(data.data);
|
||||
downloadEle.download = window.location.pathname;
|
||||
const downloadEle = document.createElement("a");
|
||||
downloadEle.href = getObjectUrl(data.data, name);
|
||||
downloadEle.download = name;
|
||||
downloadEle.classList.add("hljs-meta");
|
||||
downloadEle.textContent = "Download binary file.";
|
||||
divEle.appendChild(downloadEle);
|
||||
|
||||
mainEle.appendChild(divEle);
|
||||
|
||||
let displayAnywayEle = document.createElement("p");
|
||||
const displayAnywayEle = document.createElement("p");
|
||||
displayAnywayEle.classList.add("display-anyways");
|
||||
displayAnywayEle.classList.add("hljs-comment");
|
||||
displayAnywayEle.textContent = "Display anyways?";
|
||||
|
@ -145,41 +158,41 @@ function createBlobPasteUi(data) {
|
|||
bodyEle.appendChild(mainEle);
|
||||
}
|
||||
|
||||
function createImagePasteUi({ expiration, data, file_size }) {
|
||||
createMultiMediaPasteUi("img", expiration, data, (downloadEle, imgEle) => {
|
||||
function createImagePasteUi({ expiration, data, file_size }, name?: string) {
|
||||
createMultiMediaPasteUi("img", expiration, data, name, (downloadEle, imgEle) => {
|
||||
imgEle.onload = () => {
|
||||
let width = imgEle.naturalWidth || imgEle.width;
|
||||
let height = imgEle.naturalHeight || imgEle.height;
|
||||
const width = imgEle.naturalWidth || imgEle.width;
|
||||
const height = imgEle.naturalHeight || imgEle.height;
|
||||
downloadEle.textContent = "Download " + file_size + " \u2014 " + width + " by " + height;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createAudioPasteUi({ expiration, data }) {
|
||||
createMultiMediaPasteUi("audio", expiration, data, "Download");
|
||||
function createAudioPasteUi({ expiration, data }, name?: string) {
|
||||
createMultiMediaPasteUi("audio", expiration, data, name, "Download");
|
||||
}
|
||||
|
||||
function createVideoPasteUi({ expiration, data }) {
|
||||
createMultiMediaPasteUi("video", expiration, data, "Download");
|
||||
function createVideoPasteUi({ expiration, data }, name?: string) {
|
||||
createMultiMediaPasteUi("video", expiration, data, name, "Download");
|
||||
}
|
||||
|
||||
function createArchivePasteUi({ expiration, data, entries }) {
|
||||
let bodyEle = document.getElementsByTagName("body")[0];
|
||||
function createArchivePasteUi({ expiration, data, entries }, name?: string) {
|
||||
const bodyEle = document.getElementsByTagName("body")[0];
|
||||
bodyEle.textContent = '';
|
||||
|
||||
let mainEle = document.createElement("main");
|
||||
const mainEle = document.createElement("main");
|
||||
|
||||
let sectionEle = document.createElement("section");
|
||||
const sectionEle = document.createElement("section");
|
||||
sectionEle.classList.add("paste");
|
||||
|
||||
let expirationEle = document.createElement("p");
|
||||
const expirationEle = document.createElement("p");
|
||||
expirationEle.textContent = expiration;
|
||||
expirationEle.classList.add("centered");
|
||||
sectionEle.appendChild(expirationEle);
|
||||
|
||||
let downloadEle = document.createElement("a");
|
||||
downloadEle.href = URL.createObjectURL(data);
|
||||
downloadEle.download = window.location.pathname;
|
||||
const downloadEle = document.createElement("a");
|
||||
downloadEle.href = getObjectUrl(data);
|
||||
downloadEle.download = name;
|
||||
downloadEle.textContent = "Download";
|
||||
downloadEle.classList.add("hljs-meta");
|
||||
downloadEle.classList.add("centered");
|
||||
|
@ -187,7 +200,7 @@ function createArchivePasteUi({ expiration, data, entries }) {
|
|||
|
||||
sectionEle.appendChild(document.createElement("hr"));
|
||||
|
||||
let mediaEle = document.createElement("table");
|
||||
const mediaEle = document.createElement("table");
|
||||
mediaEle.classList.add("archive-table");
|
||||
const tr = mediaEle.insertRow();
|
||||
tr.classList.add("hljs-title");
|
||||
|
@ -224,30 +237,30 @@ function createArchivePasteUi({ expiration, data, entries }) {
|
|||
bodyEle.appendChild(mainEle);
|
||||
}
|
||||
|
||||
function createMultiMediaPasteUi(tag, expiration, data, on_create?) {
|
||||
let bodyEle = document.getElementsByTagName("body")[0];
|
||||
function createMultiMediaPasteUi(tag, expiration, data, name?: string, on_create?) {
|
||||
const bodyEle = document.getElementsByTagName("body")[0];
|
||||
bodyEle.textContent = '';
|
||||
|
||||
let mainEle = document.createElement("main");
|
||||
const mainEle = document.createElement("main");
|
||||
mainEle.classList.add("hljs");
|
||||
mainEle.classList.add("centered");
|
||||
mainEle.classList.add("fullscreen");
|
||||
|
||||
const downloadLink = URL.createObjectURL(data);
|
||||
const downloadLink = getObjectUrl(data, name);
|
||||
|
||||
let expirationEle = document.createElement("p");
|
||||
const expirationEle = document.createElement("p");
|
||||
expirationEle.textContent = expiration;
|
||||
mainEle.appendChild(expirationEle);
|
||||
|
||||
let mediaEle = document.createElement(tag);
|
||||
const mediaEle = document.createElement(tag);
|
||||
mediaEle.src = downloadLink;
|
||||
mediaEle.controls = true;
|
||||
mainEle.appendChild(mediaEle);
|
||||
|
||||
|
||||
let downloadEle = document.createElement("a");
|
||||
const downloadEle = document.createElement("a");
|
||||
downloadEle.href = downloadLink;
|
||||
downloadEle.download = window.location.pathname;
|
||||
downloadEle.download = name;
|
||||
downloadEle.classList.add("hljs-meta");
|
||||
mainEle.appendChild(downloadEle);
|
||||
|
||||
|
@ -261,9 +274,9 @@ function createMultiMediaPasteUi(tag, expiration, data, on_create?) {
|
|||
}
|
||||
|
||||
function renderMessage(message) {
|
||||
let body = document.getElementsByTagName("body")[0];
|
||||
const body = document.getElementsByTagName("body")[0];
|
||||
body.textContent = '';
|
||||
let mainEle = document.createElement("main");
|
||||
const mainEle = document.createElement("main");
|
||||
mainEle.classList.add("hljs");
|
||||
mainEle.classList.add("centered");
|
||||
mainEle.classList.add("fullscreen");
|
||||
|
@ -271,4 +284,10 @@ function renderMessage(message) {
|
|||
body.appendChild(mainEle);
|
||||
}
|
||||
|
||||
function getObjectUrl(data, mimeType?: string) {
|
||||
return URL.createObjectURL(new Blob(data, {
|
||||
type: mimeType,
|
||||
}));
|
||||
}
|
||||
|
||||
window.addEventListener("hashchange", () => location.reload());
|
||||
|
|
Loading…
Reference in a new issue