Compare commits

...

1 Commits

Author SHA1 Message Date
Edward Shen 43e334ad25
partial webpack 2021-10-25 22:33:11 -07:00
32 changed files with 3476 additions and 382 deletions

8
.swcrc
View File

@ -1,8 +0,0 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "es2021"
}
}

214
Cargo.lock generated
View File

@ -41,8 +41,8 @@ version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
dependencies = [
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
]
@ -118,8 +118,8 @@ dependencies = [
"lazy_static",
"lazycell",
"peeking_take_while",
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"regex",
"rustc-hash",
"shlex",
@ -200,6 +200,12 @@ dependencies = [
"nom 6.1.2",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -212,7 +218,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01b72a433d0cf2aef113ba70f62634c56fddb0f244e6377185c56a7cadbd8f91"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"cipher",
"cpufeatures",
"zeroize",
@ -291,8 +297,8 @@ checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
]
@ -302,7 +308,7 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"wasm-bindgen",
]
@ -330,7 +336,7 @@ version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -361,6 +367,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]]
name = "futures"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
[[package]]
name = "futures"
version = "0.3.17"
@ -417,8 +429,8 @@ checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
dependencies = [
"autocfg",
"proc-macro-hack",
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
]
@ -471,7 +483,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"js-sys",
"libc",
"wasi",
@ -712,7 +724,7 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"winapi",
]
@ -734,7 +746,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -881,6 +893,7 @@ dependencies = [
"sha2",
"thiserror",
"url",
"wasm-bindgen",
"web-sys",
]
@ -903,26 +916,6 @@ dependencies = [
"tracing-subscriber",
]
[[package]]
name = "omegaupload-web"
version = "0.1.0"
dependencies = [
"anyhow",
"byte-unit",
"bytes",
"console_error_panic_hook",
"getrandom",
"gloo-console",
"http",
"js-sys",
"omegaupload-common",
"reqwasm",
"tree_magic_mini",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "once_cell"
version = "1.8.0"
@ -978,8 +971,8 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389"
dependencies = [
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
]
@ -1019,8 +1012,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
"version_check",
]
@ -1031,8 +1024,8 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"version_check",
]
@ -1048,13 +1041,31 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
"unicode-xid 0.1.0",
]
[[package]]
name = "proc-macro2"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70"
dependencies = [
"unicode-xid",
"unicode-xid 0.2.2",
]
[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
"proc-macro2 0.4.30",
]
[[package]]
@ -1063,7 +1074,7 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
"proc-macro2 1.0.30",
]
[[package]]
@ -1145,13 +1156,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34bf31941fb867ae9386a4b443b388e6713574944e6517136ee21a6a93cf996"
dependencies = [
"anyhow",
"futures",
"futures 0.3.17",
"js-sys",
"serde",
"serde_json",
"thiserror",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-futures 0.4.28",
"web-sys",
]
@ -1185,7 +1196,7 @@ dependencies = [
"tokio-rustls",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-futures 0.4.28",
"web-sys",
"webpki-roots",
"winreg",
@ -1216,6 +1227,27 @@ dependencies = [
"librocksdb-sys",
]
[[package]]
name = "rust-webpack-template"
version = "0.1.0"
dependencies = [
"anyhow",
"byte-unit",
"bytes",
"console_error_panic_hook",
"getrandom",
"gloo-console",
"http",
"js-sys",
"omegaupload-common",
"reqwasm",
"tree_magic_mini",
"wasm-bindgen",
"wasm-bindgen-futures 0.4.28",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
@ -1241,6 +1273,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "sct"
version = "0.6.1"
@ -1276,8 +1314,8 @@ version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
]
@ -1311,7 +1349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
dependencies = [
"block-buffer",
"cfg-if",
"cfg-if 1.0.0",
"cpufeatures",
"digest",
"opaque-debug",
@ -1324,7 +1362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [
"block-buffer",
"cfg-if",
"cfg-if 1.0.0",
"cpufeatures",
"digest",
"opaque-debug",
@ -1391,9 +1429,9 @@ version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"proc-macro2 1.0.30",
"quote 1.0.10",
"unicode-xid 0.2.2",
]
[[package]]
@ -1441,8 +1479,8 @@ version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
]
@ -1503,8 +1541,8 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd"
dependencies = [
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
]
@ -1584,7 +1622,7 @@ version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"log",
"pin-project-lite",
"tracing-attributes",
@ -1597,8 +1635,8 @@ version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
dependencies = [
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
]
@ -1714,6 +1752,12 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]]
name = "unicode-xid"
version = "0.2.2"
@ -1788,7 +1832,7 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"serde",
"serde_json",
"wasm-bindgen-macro",
@ -1803,19 +1847,32 @@ dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c"
dependencies = [
"cfg-if 0.1.10",
"futures 0.1.31",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
@ -1827,7 +1884,7 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
dependencies = [
"quote",
"quote 1.0.10",
"wasm-bindgen-macro-support",
]
@ -1837,8 +1894,8 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
dependencies = [
"proc-macro2",
"quote",
"proc-macro2 1.0.30",
"quote 1.0.10",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
@ -1850,6 +1907,31 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "wasm-bindgen-test"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2d9693b63a742d481c7f80587e057920e568317b2806988c59cd71618bc26c1"
dependencies = [
"console_error_panic_hook",
"futures 0.1.31",
"js-sys",
"scoped-tls",
"wasm-bindgen",
"wasm-bindgen-futures 0.3.27",
"wasm-bindgen-test-macro",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.2.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0789dac148a8840bbcf9efe13905463b733fa96543bfbf263790535c11af7ba5"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
]
[[package]]
name = "web-sys"
version = "0.3.55"

View File

@ -1,13 +0,0 @@
[build]
target = "web/index.html"
release = true
[[proxy]]
backend = "http://localhost:8081"
rewrite = "/api/"
[[hooks]]
stage="post_build"
command="npx"
command_arguments=["swc", "$TRUNK_SOURCE_DIR/src/main.ts", "-o", "$TRUNK_STAGING_DIR/main.js"]

View File

@ -18,8 +18,10 @@ sha2 = "0.9"
thiserror = "1"
url = "2"
# Wasm deps
web-sys = { version = "0.3", features = ["Headers"], optional = true }
http = { version = "0.2", optional = true }
wasm-bindgen = { version = "0.2", optional = true }
[features]
wasm = ["web-sys", "http"]
wasm = ["web-sys", "http", "wasm-bindgen"]

View File

@ -1,6 +0,0 @@
{
"devDependencies": {
"@swc/cli": "^0.1.51",
"@swc/core": "^1.2.102"
}
}

6
web/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
node_modules
/dist
/target
/pkg
/wasm-pack.log
yarn-error.log

View File

@ -1,9 +1,15 @@
# You must change these to your own details.
[package]
name = "omegaupload-web"
name = "rust-webpack-template"
description = "My super awesome Rust, WebAssembly, and Webpack project!"
version = "0.1.0"
authors = ["You <you@example.com>"]
categories = ["wasm"]
readme = "README.md"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
[dependencies]
omegaupload-common = { path = "../common", features = ["wasm"] }
@ -40,4 +46,7 @@ features = [
"Window",
"Performance",
"Location",
]
]
[dev-dependencies]
wasm-bindgen-test = "0.2.45"

View File

@ -1,10 +1,48 @@
Contains the codebase used for the frontend
## How to install
Notes on licensing:
```sh
npm install
```
https://www.gnu.org/licenses/gpl-faq.html#AllCompatibility
## How to run in debug mode
Because there is a statically linked in dependency on `shared-mime-types`, this
crate MUST be under a GPLv2 or later license. This has been confirmed as of
2021-10-24.
```sh
# Builds the project and opens it in a new browser tab. Auto-reloads when the project changes.
npm start
```
## How to build in release mode
```sh
# Builds the project and places it into the `dist` folder.
npm run build
```
## How to run unit tests
```sh
# Runs tests in Firefox
npm test -- --firefox
# Runs tests in Chrome
npm test -- --chrome
# Runs tests in Safari
npm test -- --safari
```
## What does each file do?
* `Cargo.toml` contains the standard Rust metadata. You put your Rust dependencies in here. You must change this file with your details (name, description, version, authors, categories)
* `package.json` contains the standard npm metadata. You put your JavaScript dependencies in here. You must change this file with your details (author, name, version)
* `webpack.config.js` contains the Webpack configuration. You shouldn't need to change this, unless you have very special needs.
* The `js` folder contains your JavaScript code (`index.js` is used to hook everything into Webpack, you don't need to change it).
* The `src` folder contains your Rust code.
* The `static` folder contains any files that you want copied as-is into the final build. It contains an `index.html` file which loads the `index.js` file.
* The `tests` folder contains your Rust unit tests.

4
web/js/index.js Normal file
View File

@ -0,0 +1,4 @@
import { renderMessage } from './ui';
import * as index from "../pkg/index.js";
renderMessage("wtf");
console.log(index);

196
web/js/ui.js Normal file
View File

@ -0,0 +1,196 @@
import hljs from 'hljs';
window.addEventListener("hashchange", () => location.reload());
function loadFromDb() {
const dbReq = window.indexedDB.open("omegaupload", 1);
dbReq.onsuccess = (evt) => {
const db = evt.target.result;
const obj_store = db
.transaction("decrypted data")
.objectStore("decrypted data");
let fetchReq = obj_store.get(window.location.pathname);
fetchReq.onsuccess = (evt) => {
const data = evt.target.result;
switch (data.type) {
case "string":
createStringPasteUi(data);
break;
case "blob":
createBlobPasteUi(data);
break;
case "image":
createImagePasteUi(data);
break;
case "audio":
createAudioPasteUi(data);
break;
case "video":
createVideoPasteUi(data);
break;
default:
renderMessage("Something went wrong. Try clearing local data.");
break;
}
// IDB was only used as a temporary medium;
window.onbeforeunload = (e) => {
// See https://link.eddie.sh/NrIIq on why .commit is necessary.
const transaction = db.transaction("decrypted data", "readwrite");
transaction
.objectStore("decrypted data")
.delete(window.location.pathname);
transaction.commit();
transaction.oncomplete = () => {
console.log("Item deleted from cache");
}
};
};
fetchReq.onerror = (evt) => {
console.log("err");
console.log(evt);
};
};
}
function createStringPasteUi(data) {
let bodyEle = document.getElementsByTagName("body")[0];
bodyEle.textContent = '';
let mainEle = document.createElement("main");
let preEle = document.createElement("pre");
preEle.classList.add("paste");
let headerEle = document.createElement("header");
headerEle.classList.add("unselectable");
headerEle.textContent = data.expiration;
preEle.appendChild(headerEle);
preEle.appendChild(document.createElement("hr"));
let codeEle = document.createElement("code");
codeEle.textContent = data.data;
preEle.appendChild(codeEle);
mainEle.appendChild(preEle);
bodyEle.appendChild(mainEle);
hljs.highlightAll();
hljs.initLineNumbersOnLoad();
}
function createBlobPasteUi(data) {
let bodyEle = document.getElementsByTagName("body")[0];
bodyEle.textContent = '';
let mainEle = document.createElement("main");
mainEle.classList.add("hljs");
mainEle.classList.add("centered");
mainEle.classList.add("fullscreen");
let divEle = document.createElement("div");
divEle.classList.add("centered");
let 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;
downloadEle.classList.add("hljs-meta");
downloadEle.textContent = "Download binary file.";
divEle.appendChild(downloadEle);
mainEle.appendChild(divEle);
let displayAnywayEle = document.createElement("p");
displayAnywayEle.classList.add("display-anyways");
displayAnywayEle.classList.add("hljs-comment");
displayAnywayEle.textContent = "Display anyways?";
displayAnywayEle.onclick = () => {
data.data.text().then(text => {
data.data = text;
createStringPasteUi(data);
})
};
mainEle.appendChild(displayAnywayEle);
bodyEle.appendChild(mainEle);
}
function createImagePasteUi({ expiration, data, file_size }) {
createMultiMediaPasteUi("img", expiration, data, (downloadEle, imgEle) => {
imgEle.onload = () => {
downloadEle.textContent = "Download " + file_size + " \u2014 " + imgEle.naturalWidth + " by " + imgEle.naturalHeight;
}
});
}
function createAudioPasteUi({ expiration, data }) {
createMultiMediaPasteUi("audio", expiration, data, "Download");
}
function createVideoPasteUi({ expiration, data }) {
createMultiMediaPasteUi("video", expiration, data, "Download");
}
function createMultiMediaPasteUi(tag, expiration, data, on_create) {
let bodyEle = document.getElementsByTagName("body")[0];
bodyEle.textContent = '';
let mainEle = document.createElement("main");
mainEle.classList.add("hljs");
mainEle.classList.add("centered");
mainEle.classList.add("fullscreen");
const downloadLink = URL.createObjectURL(data);
let expirationEle = document.createElement("p");
expirationEle.textContent = expiration;
mainEle.appendChild(expirationEle);
let mediaEle = document.createElement(tag);
mediaEle.src = downloadLink;
mediaEle.controls = true;
mainEle.appendChild(mediaEle);
let downloadEle = document.createElement("a");
downloadEle.href = downloadLink;
downloadEle.download = window.location.pathname;
downloadEle.classList.add("hljs-meta");
mainEle.appendChild(downloadEle);
bodyEle.appendChild(mainEle);
if (on_create instanceof Function) {
on_create(downloadEle, mediaEle);
} else {
downloadEle.textContent = on_create;
}
}
function renderMessage(message) {
let body = document.getElementsByTagName("body")[0];
body.textContent = '';
let mainEle = document.createElement("main");
mainEle.classList.add("hljs");
mainEle.classList.add("centered");
mainEle.classList.add("fullscreen");
mainEle.textContent = message;
body.appendChild(mainEle);
}
function renderIndex() {
console.log("index");
// TODO: find a way to not hard code this.
// https://docs.rs/chacha20poly1305/0.9.0/chacha20poly1305/type.Key.html
// https://docs.rs/chacha20poly1305/0.9.0/chacha20poly1305/type.XNonce.html
const key = crypto.getRandomValues(new Uint8Array(32));
const nonce = crypto.getRandomValues(new Uint8Array(24));
console.log(key, nonce);
}
export { renderIndex, renderMessage, loadFromDb };

23
web/package.json Normal file
View File

@ -0,0 +1,23 @@
{
"author": "Edward Shen <code@eddie.sh>",
"name": "omegaupload-web",
"version": "0.1.0",
"scripts": {
"build": "rimraf dist pkg && webpack",
"start": "rimraf dist pkg && webpack-dev-server --open",
"test": "cargo test && wasm-pack test --headless"
},
"devDependencies": {
"@wasm-tool/wasm-pack-plugin": "^1.1.0",
"copy-webpack-plugin": "^9.0.1",
"rimraf": "^3.0.0",
"ts-loader": "^9.2.6",
"webpack": "^5.60.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.3.1"
},
"dependencies": {
"hljs": "^6.2.3",
"typescript": "^4.4.4"
}
}

253
web/src/lib.rs Normal file
View File

@ -0,0 +1,253 @@
#![warn(clippy::nursery, clippy::pedantic)]
use std::str::FromStr;
use anyhow::{anyhow, bail, Context, Result};
use byte_unit::{n_mib_bytes, Byte};
use decrypt::DecryptedData;
use gloo_console::{error, log};
use http::uri::PathAndQuery;
use http::{StatusCode, Uri};
use js_sys::{JsString, Object, Uint8Array};
use omegaupload_common::crypto::{Key, Nonce};
use omegaupload_common::{hash, Expiration, PartialParsedUrl};
use reqwasm::http::Request;
use wasm_bindgen::prelude::{wasm_bindgen, Closure};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen_futures::{spawn_local, JsFuture};
use web_sys::{Event, IdbObjectStore, IdbOpenDbRequest, IdbTransactionMode, Location, Window};
use crate::decrypt::decrypt;
use crate::idb_object::IdbObject;
use crate::util::as_idb_db;
mod decrypt;
mod idb_object;
mod util;
const DOWNLOAD_SIZE_LIMIT: u128 = n_mib_bytes!(500);
#[wasm_bindgen(raw_module = "../js/ui.js")]
extern "C" {
#[wasm_bindgen(js_name = renderIndex)]
pub fn render_index();
#[wasm_bindgen(js_name = loadFromDb)]
pub fn load_from_db();
#[wasm_bindgen(js_name = renderMessage)]
pub fn render_message(message: JsString);
}
fn window() -> Window {
web_sys::window().expect("Failed to get a reference of the window")
}
fn location() -> Location {
window().location()
}
fn open_idb() -> Result<IdbOpenDbRequest> {
window()
.indexed_db()
.unwrap()
.context("Missing browser idb impl")?
.open("omegaupload")
.map_err(|_| anyhow!("Failed to open idb"))
}
// This is like the `main` function, except for JavaScript.
#[wasm_bindgen(start)]
pub fn js_main() {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
if location().pathname().unwrap() == "/" {
render_index();
} else {
render_message("Loading paste...".into());
let url = String::from(location().to_string());
let request_uri = {
let mut uri_parts = url.parse::<Uri>().unwrap().into_parts();
if let Some(parts) = uri_parts.path_and_query.as_mut() {
*parts = PathAndQuery::from_str(&format!("/api{}", parts.path())).unwrap();
}
Uri::from_parts(uri_parts).unwrap()
};
log!(&url);
log!(&request_uri.to_string());
log!(&location().pathname().unwrap());
let (key, nonce, needs_pw) = {
let partial_parsed_url = url
.split_once('#')
.map(|(_, fragment)| PartialParsedUrl::from(fragment))
.unwrap_or_default();
let key = if let Some(key) = partial_parsed_url.decryption_key {
key
} else {
error!("Key is missing in url; bailing.");
render_message("Invalid paste link: Missing decryption key.".into());
return;
};
let nonce = if let Some(nonce) = partial_parsed_url.nonce {
nonce
} else {
error!("Nonce is missing in url; bailing.");
render_message("Invalid paste link: Missing nonce.".into());
return;
};
(key, nonce, partial_parsed_url.needs_password)
};
let password = if needs_pw {
loop {
let pw =
window().prompt_with_message("A password is required to decrypt this paste:");
if let Ok(Some(password)) = pw {
if !password.is_empty() {
break Some(hash(password));
}
}
}
} else {
None
};
spawn_local(async move {
if let Err(e) = fetch_resources(request_uri, key, nonce, password).await {
log!(e.to_string());
}
});
}
}
#[allow(clippy::future_not_send)]
async fn fetch_resources(
request_uri: Uri,
key: Key,
nonce: Nonce,
password: Option<Key>,
) -> Result<()> {
match Request::get(&request_uri.to_string()).send().await {
Ok(resp) if resp.status() == StatusCode::OK => {
let expires = Expiration::try_from(resp.headers()).map_or_else(
|_| "This item does not expire.".to_string(),
|expires| expires.to_string(),
);
let data = {
let data_fut = resp
.as_raw()
.array_buffer()
.expect("to get raw bytes from a response");
let data = match JsFuture::from(data_fut).await {
Ok(data) => data,
Err(e) => {
render_message(
"Network failure: Failed to completely read encryption paste.".into(),
);
bail!(format!(
"JsFuture returned an error while fetching resp buffer: {:?}",
e
));
}
};
Uint8Array::new(&data).to_vec()
};
if data.len() as u128 > DOWNLOAD_SIZE_LIMIT {
render_message("The paste is too large to decrypt from the web browser. You must use the CLI tool to download this paste.".into());
return Ok(());
}
let decrypted = decrypt(data, key, nonce, password)?;
let db_open_req = open_idb()?;
// On success callback
let on_success = Closure::once(Box::new(move |event: Event| {
let transaction: IdbObjectStore = as_idb_db(&event)
.transaction_with_str_and_mode("decrypted data", IdbTransactionMode::Readwrite)
.unwrap()
.object_store("decrypted data")
.unwrap();
let decrypted_object = match &decrypted {
DecryptedData::String(s) => IdbObject::new()
.string()
.expiration_text(&expires)
.data(&JsValue::from_str(s)),
DecryptedData::Blob(blob) => {
IdbObject::new().blob().expiration_text(&expires).data(blob)
}
DecryptedData::Image(blob, size) => IdbObject::new()
.image()
.expiration_text(&expires)
.data(blob)
.extra(
"file_size",
Byte::from_bytes(*size as u128)
.get_appropriate_unit(true)
.to_string(),
),
DecryptedData::Audio(blob) => IdbObject::new()
.audio()
.expiration_text(&expires)
.data(blob),
DecryptedData::Video(blob) => IdbObject::new()
.video()
.expiration_text(&expires)
.data(blob),
};
let put_action = transaction
.put_with_key(
&Object::from(decrypted_object),
&JsString::from(location().pathname().unwrap()),
)
.unwrap();
put_action.set_onsuccess(Some(
Closure::wrap(Box::new(|| {
log!("success");
load_from_db();
}) as Box<dyn Fn()>)
.into_js_value()
.unchecked_ref(),
));
put_action.set_onerror(Some(
Closure::wrap(Box::new(|e| {
log!(e);
}) as Box<dyn Fn(Event)>)
.into_js_value()
.unchecked_ref(),
));
}) as Box<dyn FnOnce(Event)>);
db_open_req.set_onsuccess(Some(on_success.into_js_value().unchecked_ref()));
db_open_req.set_onerror(Some(
Closure::wrap(Box::new(|e| {
log!(e);
}) as Box<dyn Fn(Event)>)
.into_js_value()
.unchecked_ref(),
));
let on_upgrade = Closure::wrap(Box::new(move |event: Event| {
let db = as_idb_db(&event);
let _obj_store = db.create_object_store("decrypted data").unwrap();
}) as Box<dyn FnMut(Event)>);
db_open_req.set_onupgradeneeded(Some(on_upgrade.into_js_value().unchecked_ref()));
}
Ok(resp) if resp.status() == StatusCode::NOT_FOUND => {
render_message("Either the paste was burned or it never existed.".into());
}
Ok(resp) if resp.status() == StatusCode::BAD_REQUEST => {
render_message("Invalid paste URL.".into());
}
Ok(err) => {
render_message(err.status_text().into());
}
Err(err) => {
render_message(format!("{}", err).into());
}
}
Ok(())
}

15
web/static/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Omegaupload</title>
<!-- <script src="highlightjs-line-numbers.min.js" defer></script> -->
</head>
<body>
<script src="index.js"></script>
</body>
</html>

30
web/tests/app.rs Normal file
View File

@ -0,0 +1,30 @@
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::JsFuture;
use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
wasm_bindgen_test_configure!(run_in_browser);
// This runs a unit test in native Rust, so it can only use Rust APIs.
#[test]
fn rust_test() {
assert_eq!(1, 1);
}
// This runs a unit test in the browser, so it can use browser APIs.
#[wasm_bindgen_test]
fn web_test() {
assert_eq!(1, 1);
}
// This runs a unit test in the browser, and in addition it supports asynchronous Future APIs.
#[wasm_bindgen_test(async)]
async fn async_test() -> Result<(), JsValue> {
// Creates a JavaScript Promise which will asynchronously resolve with the value 42.
let promise = js_sys::Promise::resolve(&JsValue::from(42));
// Converts that Promise into a Future.
// The unit test will wait for the Future to resolve.
JsFuture::from(promise).map(|x| {
assert_eq!(x, 42);
})
}

11
web/tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": false,
"module": "esnext",
"target": "es5",
"allowJs": true,
"moduleResolution": "node",
"sourceMap": true,
}
}

51
web/webpack.config.js Normal file
View File

@ -0,0 +1,51 @@
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
const dist = path.resolve(__dirname, "dist");
module.exports = {
mode: "development",
entry: {
index: "./js/index.js"
},
devtool: 'inline-source-map',
output: {
path: dist,
filename: "[name].js"
},
devServer: {
static: {
directory: dist,
},
proxy: {
'/api': {
target: 'http://localhost:8081',
pathRewrite: { '^/api': '' }
}
},
watchFiles: ['src/**', 'js/**'],
},
plugins: [
new CopyPlugin({
patterns: [
path.resolve(__dirname, "static")
]
}),
new WasmPackPlugin({
crateDirectory: __dirname,
}),
],
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
}
]
},
experiments: {
asyncWebAssembly: true,
},
};

2356
web/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

43
web_old/Cargo.toml Normal file
View File

@ -0,0 +1,43 @@
[package]
name = "omegaupload-web"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
omegaupload-common = { path = "../common", features = ["wasm"] }
# Enables wasm support
getrandom = { version = "*", features = ["js"] }
anyhow = "1"
bytes = "1"
byte-unit = "4"
console_error_panic_hook = "0.1"
gloo-console = "0.1"
http = "0.2"
js-sys = "0.3"
reqwasm = "0.2"
tree_magic_mini = { version = "3", features = ["with-gpl-data"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
[dependencies.web-sys]
version = "0.3"
features = [
"TextDecoder",
"IdbFactory",
"IdbOpenDbRequest",
"IdbRequest",
"IdbDatabase",
"IdbObjectStore",
"IdbTransaction",
"IdbTransactionMode",
"IdbIndex",
"IdbIndexParameters",
"Event",
"EventTarget",
"Window",
"Performance",
"Location",
]

10
web_old/README.md Normal file
View File

@ -0,0 +1,10 @@
Contains the codebase used for the frontend
Notes on licensing:
https://www.gnu.org/licenses/gpl-faq.html#AllCompatibility
Because there is a statically linked in dependency on `shared-mime-types`, this
crate MUST be under a GPLv2 or later license. This has been confirmed as of
2021-10-24.

105
web_old/src/decrypt.rs Normal file
View File

@ -0,0 +1,105 @@
use std::fmt::{Display, Formatter};
use std::sync::Arc;
use gloo_console::log;
use js_sys::{Array, Uint8Array};
use omegaupload_common::crypto::{open_in_place, Key, Nonce};
use wasm_bindgen::JsCast;
use web_sys::Blob;
#[derive(Clone)]
pub enum DecryptedData {
String(Arc<String>),
Blob(Arc<Blob>),
Image(Arc<Blob>, usize),
Audio(Arc<Blob>),
Video(Arc<Blob>),
}
fn now() -> f64 {
web_sys::window()
.expect("should have a Window")
.performance()
.expect("should have a Performance")
.now()
}
pub fn decrypt(
mut container: Vec<u8>,
key: Key,
nonce: Nonce,
maybe_password: Option<Key>,
) -> Result<DecryptedData, PasteCompleteConstructionError> {
let container = &mut container;
log!("Stage 1 decryption started.");
let start = now();
if let Some(password) = maybe_password {
crate::render_message("Decrypting Stage 1...".into());
open_in_place(container, &nonce.increment(), &password).map_err(|_| {
crate::render_message("Unable to decrypt paste with the provided password.".into());
PasteCompleteConstructionError::StageOneFailure
})?;
}
log!(format!("Stage 1 completed in {}ms", now() - start));
log!("Stage 2 decryption started.");
let start = now();
crate::render_message("Decrypting Stage 2...".into());
open_in_place(container, &nonce, &key).map_err(|_| {
crate::render_message(
"Unable to decrypt paste with the provided encryption key and nonce.".into(),
);
PasteCompleteConstructionError::StageTwoFailure
})?;
log!(format!("Stage 2 completed in {}ms", now() - start));
if let Ok(decrypted) = std::str::from_utf8(container) {
Ok(DecryptedData::String(Arc::new(decrypted.to_owned())))
} else {
log!("Blob conversion started.");
let start = now();
let blob_chunks = Array::new_with_length(container.chunks(65536).len().try_into().unwrap());
for (i, chunk) in container.chunks(65536).enumerate() {
let array = Uint8Array::new_with_length(chunk.len().try_into().unwrap());
array.copy_from(chunk);
blob_chunks.set(i.try_into().unwrap(), array.dyn_into().unwrap());
}
let blob =
Arc::new(Blob::new_with_u8_array_sequence(blob_chunks.dyn_ref().unwrap()).unwrap());
log!(format!("Blob conversion completed in {}ms", now() - start));
let mime_type = tree_magic_mini::from_u8(container);
if mime_type.starts_with("image/") || mime_type == "application/x-riff" {
Ok(DecryptedData::Image(blob, container.len()))
} else if mime_type.starts_with("audio/") {
Ok(DecryptedData::Audio(blob))
} else if mime_type.starts_with("video/") || mime_type == "application/x-matroska" {
Ok(DecryptedData::Video(blob))
} else {
Ok(DecryptedData::Blob(blob))
}
}
}
#[derive(Debug)]
pub enum PasteCompleteConstructionError {
StageOneFailure,
StageTwoFailure,
}
impl std::error::Error for PasteCompleteConstructionError {}
impl Display for PasteCompleteConstructionError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
PasteCompleteConstructionError::StageOneFailure => {
write!(f, "Failed to decrypt stage one.")
}
PasteCompleteConstructionError::StageTwoFailure => {
write!(f, "Failed to decrypt stage two.")
}
}
}
}

95
web_old/src/idb_object.rs Normal file
View File

@ -0,0 +1,95 @@
use std::{hint::unreachable_unchecked, marker::PhantomData};
use js_sys::{Array, JsString, Object};
use wasm_bindgen::JsValue;
pub struct IdbObject<State>(Array, PhantomData<State>);
impl<State: IdbObjectState> IdbObject<State> {
fn add_tuple<NextState>(self, key: &str, value: &JsValue) -> IdbObject<NextState> {
let array = Array::new();
array.push(&JsString::from(key));
array.push(value);
self.0.push(&array);
IdbObject(self.0, PhantomData)
}
}
impl From<IdbObject<Ready>> for Object {
fn from(db_object: IdbObject<Ready>) -> Self {
match Self::from_entries(db_object.as_ref()) {
Ok(o) => o,
// SAFETY: IdbObject maintains the invariant that it can eventually
// be constructed into a JS object.
_ => unsafe { unreachable_unchecked() },
}
}
}
impl IdbObject<NeedsType> {
pub fn new() -> Self {
Self(Array::new(), PhantomData)
}
pub fn video(self) -> IdbObject<NeedsExpiration> {
self.add_tuple("type", &JsString::from("video"))
}
pub fn audio(self) -> IdbObject<NeedsExpiration> {
self.add_tuple("type", &JsString::from("audio"))
}
pub fn image(self) -> IdbObject<NeedsExpiration> {
self.add_tuple("type", &JsString::from("image"))
}
pub fn blob(self) -> IdbObject<NeedsExpiration> {
self.add_tuple("type", &JsString::from("blob"))
}
pub fn string(self) -> IdbObject<NeedsExpiration> {
self.add_tuple("type", &JsString::from("string"))
}
}
impl Default for IdbObject<NeedsType> {
fn default() -> Self {
Self::new()
}
}
impl IdbObject<NeedsExpiration> {
pub fn expiration_text(self, expires: &str) -> IdbObject<NeedsData> {
self.add_tuple("expiration", &JsString::from(expires))
}
}
impl IdbObject<NeedsData> {
pub fn data(self, value: &JsValue) -> IdbObject<Ready> {
self.add_tuple("data", value)
}
}
impl IdbObject<Ready> {
pub fn extra(self, key: &str, value: impl Into<JsValue>) -> Self {
self.add_tuple(key, &value.into())
}
}
impl AsRef<JsValue> for IdbObject<Ready> {
fn as_ref(&self) -> &JsValue {
self.0.as_ref()
}
}
macro_rules! impl_idb_object_state {
($($ident:ident),*) => {
pub trait IdbObjectState {}
$(
pub enum $ident {}
impl IdbObjectState for $ident {}
)*
};
}
impl_idb_object_state!(NeedsType, NeedsExpiration, NeedsData, Ready);

View File

@ -29,6 +29,8 @@ const DOWNLOAD_SIZE_LIMIT: u128 = n_mib_bytes!(500);
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_name = renderIndex)]
pub fn render_index();
#[wasm_bindgen(js_name = loadFromDb)]
pub fn load_from_db();
#[wasm_bindgen(js_name = renderMessage)]
@ -55,58 +57,59 @@ fn open_idb() -> Result<IdbOpenDbRequest> {
fn main() {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
render_message("Loading paste...".into());
if location().pathname().unwrap() == "/" {
render_index();
} else {
render_message("Loading paste...".into());
let url = String::from(location().to_string());
let request_uri = {
let mut uri_parts = url.parse::<Uri>().unwrap().into_parts();
if let Some(parts) = uri_parts.path_and_query.as_mut() {
*parts = PathAndQuery::from_str(&format!("/api{}", parts.path())).unwrap();
}
Uri::from_parts(uri_parts).unwrap()
};
log!(&url);
log!(&request_uri.to_string());
log!(&location().pathname().unwrap());
let (key, nonce, needs_pw) = {
let partial_parsed_url = url
.split_once('#')
.map(|(_, fragment)| PartialParsedUrl::from(fragment))
.unwrap_or_default();
let key = if let Some(key) = partial_parsed_url.decryption_key {
key
} else {
error!("Key is missing in url; bailing.");
render_message("Invalid paste link: Missing decryption key.".into());
return;
let url = String::from(location().to_string());
let request_uri = {
let mut uri_parts = url.parse::<Uri>().unwrap().into_parts();
if let Some(parts) = uri_parts.path_and_query.as_mut() {
*parts = PathAndQuery::from_str(&format!("/api{}", parts.path())).unwrap();
}
Uri::from_parts(uri_parts).unwrap()
};
let nonce = if let Some(nonce) = partial_parsed_url.nonce {
nonce
} else {
error!("Nonce is missing in url; bailing.");
render_message("Invalid paste link: Missing nonce.".into());
return;
log!(&url);
log!(&request_uri.to_string());
log!(&location().pathname().unwrap());
let (key, nonce, needs_pw) = {
let partial_parsed_url = url
.split_once('#')
.map(|(_, fragment)| PartialParsedUrl::from(fragment))
.unwrap_or_default();
let key = if let Some(key) = partial_parsed_url.decryption_key {
key
} else {
error!("Key is missing in url; bailing.");
render_message("Invalid paste link: Missing decryption key.".into());
return;
};
let nonce = if let Some(nonce) = partial_parsed_url.nonce {
nonce
} else {
error!("Nonce is missing in url; bailing.");
render_message("Invalid paste link: Missing nonce.".into());
return;
};
(key, nonce, partial_parsed_url.needs_password)
};
(key, nonce, partial_parsed_url.needs_password)
};
let password = if needs_pw {
loop {
let pw = window().prompt_with_message("A password is required to decrypt this paste:");
let password = if needs_pw {
loop {
let pw =
window().prompt_with_message("A password is required to decrypt this paste:");
if let Ok(Some(password)) = pw {
if !password.is_empty() {
break Some(hash(password));
if let Ok(Some(password)) = pw {
if !password.is_empty() {
break Some(hash(password));
}
}
}
}
} else {
None
};
if location().pathname().unwrap() == "/" {
} else {
} else {
None
};
spawn_local(async move {
if let Err(e) = fetch_resources(request_uri, key, nonce, password).await {
log!(e.to_string());

View File

@ -1,3 +1,6 @@
window.addEventListener("hashchange", () => location.reload());
// Exported to main.rs
function loadFromDb() {
const dbReq = window.indexedDB.open("omegaupload", 1);
@ -179,4 +182,13 @@ function renderMessage(message) {
body.appendChild(mainEle);
}
window.addEventListener("hashchange", () => location.reload());
// Export to main.rs
function renderIndex() {
console.log("index");
// TODO: find a way to not hard code this.
// https://docs.rs/chacha20poly1305/0.9.0/chacha20poly1305/type.Key.html
// https://docs.rs/chacha20poly1305/0.9.0/chacha20poly1305/type.XNonce.html
const key = crypto.getRandomValues(new Uint8Array(32));
const nonce = crypto.getRandomValues(new Uint8Array(24));
console.log(key, nonce);
}

10
web_old/src/util.rs Normal file
View File

@ -0,0 +1,10 @@
use wasm_bindgen::JsCast;
use web_sys::{Event, IdbDatabase, IdbOpenDbRequest};
/// # Panics
///
/// This will panic if event is not an event from the IDB API.
pub fn as_idb_db(event: &Event) -> IdbDatabase {
let target: IdbOpenDbRequest = event.target().map(JsCast::unchecked_into).unwrap();
target.result().map(JsCast::unchecked_into).unwrap()
}

233
yarn.lock
View File

@ -1,233 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@napi-rs/triples@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@napi-rs/triples/-/triples-1.0.3.tgz#76d6d0c3f4d16013c61e45dfca5ff1e6c31ae53c"
integrity sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA==
"@node-rs/helper@^1.0.0":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@node-rs/helper/-/helper-1.2.1.tgz#e079b05f21ff4329d82c4e1f71c0290e4ecdc70c"
integrity sha512-R5wEmm8nbuQU0YGGmYVjEc0OHtYsuXdpRG+Ut/3wZ9XAvQWyThN08bTh2cBJgoZxHQUPtvRfeQuxcAgLuiBISg==
dependencies:
"@napi-rs/triples" "^1.0.3"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@swc/cli@^0.1.51":
version "0.1.51"
resolved "https://registry.yarnpkg.com/@swc/cli/-/cli-0.1.51.tgz#720f2d966446558011085c2a40a65fd9079d06a1"
integrity sha512-7eqZGpkI4QOYfF+9FV4xpT/V/LSRDs5OMJcm4Z46JnPMvv+sxumAFdCe1hHRzHgnzwis9OtjI8Tt3Srf9JudQw==
dependencies:
commander "^7.1.0"
fast-glob "^3.2.5"
slash "3.0.0"
source-map "^0.7.3"
"@swc/core-android-arm64@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-android-arm64/-/core-android-arm64-1.2.102.tgz#972a47217053cc759f0bc0308a508279de1247ba"
integrity sha512-03wXXSyzm3I/7E3HihYRwvR/v5Xq8Z6j+oXYAouNoQo0/ODTMH9ATFv30csrK3mRtVEcJUk8VpVvfyh1N4hqkw==
"@swc/core-darwin-arm64@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.2.102.tgz#1795a4080d1060ca8ac52f218cc4c64b73a7ef06"
integrity sha512-DlC9+qt6gq6gGbmr9MCuMZmdHD/RyfZlf7YfkbQOlRlxaanUWz0lq0TZDWGI6MIofVOgaTle0FImPXby6dI/RA==
"@swc/core-darwin-x64@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.2.102.tgz#f48ab5b8b56798d36acd38838c62eb0be4af3c4b"
integrity sha512-JQhxbDnb8RYZ4m7B1f5J05HlUfmjiniQDnpSrvo5rDhlAZWXxuAKjEJQw8Qas/vqLdmgqrZ9POZmFaMBwIgKwg==
"@swc/core-linux-arm-gnueabihf@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.2.102.tgz#a617cea4f5a2ff1aac9f668da12dd7a6a0a6700d"
integrity sha512-XWr6Cm3lBOcSGjTjPDLWHBh+lOSkKFMS2gCpLmIC3StAvtcN0oQY59T4cqDfe7VcBgJcdeo/H4dEnrXvnJyCaw==
"@swc/core-linux-arm64-gnu@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.2.102.tgz#0abccb26af51783be141dea8b7af0baa0dcc55b4"
integrity sha512-HVtLVBpyqpSIkXmonW75nDzpdrRtZXwEYLYG+y6Sw/8AQFQ9WntwnR+xoJ8q9o3Bby2DGpWetjR0V8rr1m+lmg==
"@swc/core-linux-arm64-musl@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.2.102.tgz#ab079233626a355995b8e25e3666a759edffe1c5"
integrity sha512-XDgnkd90alnkBB+JcXaYIG5lXrv/ppLb9Z5fZ4BIsi8uNsVZgo+H/eAj/BTcYff4mpyGdCdqd7P1lC/WRR8uEg==
"@swc/core-linux-x64-gnu@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.2.102.tgz#6336698ffae22a491e782cb9ab7478130ceb2240"
integrity sha512-O3XZpJ0GMghNcO5uxfhAvDTJ4FgDOcq8DBPpa4f4Mz7hU6fcGY4Koy4rUeff4BuOKlIzI/O+REszxk7Fiivh2w==
"@swc/core-linux-x64-musl@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.2.102.tgz#b9f557dd53647318ac6dd832f174efe8e7386e1a"
integrity sha512-bGqatsVX3yc56YoOLGcHMUG23I2PKMe638vCBfuKVWN6UKcGJGMzqZV/efyPiHJDFcWzN/1jYW3GccGQq97G3Q==
"@swc/core-win32-arm64-msvc@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.2.102.tgz#e7c7958f0c2adb1e83a375e0d8d6af673e53150d"
integrity sha512-A15tUAEDS72a2ixNQl3mKCgMD6RVzntMdWl9pDG71/xRd/U/NVIKx0x12FT5fUQH8PTJ7cgcp2Y0VqKeeEuF5w==
"@swc/core-win32-ia32-msvc@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.2.102.tgz#f14c93ac0c8b2ec03a8d5438b86551d962da4b0c"
integrity sha512-uePvr9+C1Z0KVElU/Y6ZyXw7vqzRIxl+KSYfn9mCFpgYy/1BRSmxpxqTzR0rkfClXMBi2W9a0JosmWbUvRC8ZQ==
"@swc/core-win32-x64-msvc@1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.2.102.tgz#e3cbbb58d99174b7b7d9c1c58467491d31dca269"
integrity sha512-VsUducGCqKm0ucFrZiKQZ95Y4EcCSivg/zYBdTXM20eu/7mG9ynBXHCoKW0B+69D6J3IZsrc9Hvcu7gKkT9QfQ==
"@swc/core@^1.2.102":
version "1.2.102"
resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.2.102.tgz#c71fd22941fa9b7b3c52c778d494ab57beef2c17"
integrity sha512-KQEsDWb8HTSQ/I8N6qVHNSl6al/qcXxsRAjpEP8ZPnnpgThbnP9MeKpT2KeU+Qd4VD0qXM72dMm2QOPzdSlxHQ==
dependencies:
"@node-rs/helper" "^1.0.0"
optionalDependencies:
"@swc/core-android-arm64" "1.2.102"
"@swc/core-darwin-arm64" "1.2.102"
"@swc/core-darwin-x64" "1.2.102"
"@swc/core-linux-arm-gnueabihf" "1.2.102"
"@swc/core-linux-arm64-gnu" "1.2.102"
"@swc/core-linux-arm64-musl" "1.2.102"
"@swc/core-linux-x64-gnu" "1.2.102"
"@swc/core-linux-x64-musl" "1.2.102"
"@swc/core-win32-arm64-msvc" "1.2.102"
"@swc/core-win32-ia32-msvc" "1.2.102"
"@swc/core-win32-x64-msvc" "1.2.102"
braces@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
commander@^7.1.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
fast-glob@^3.2.5:
version "3.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.4"
fastq@^1.6.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
dependencies:
reusify "^1.0.4"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
glob-parent@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-glob@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
merge2@^1.3.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
micromatch@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
dependencies:
braces "^3.0.1"
picomatch "^2.2.3"
picomatch@^2.2.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
reusify@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
dependencies:
queue-microtask "^1.2.2"
slash@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
source-map@^0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"