add support for encrypting text files from web

This commit is contained in:
Ninja3047 2022-07-26 22:03:50 -04:00
parent b793139a99
commit 774b13e46c
No known key found for this signature in database
11 changed files with 438 additions and 321 deletions

53
Cargo.lock generated
View file

@ -33,17 +33,6 @@ version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]]
name = "argon2"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25df3c03f1040d0069fcd3907e24e36d59f9b6fa07ba49be0eb25a794f036ba7"
dependencies = [
"base64ct",
"blake2",
"password-hash 0.3.2",
]
[[package]] [[package]]
name = "argon2" name = "argon2"
version = "0.4.1" version = "0.4.1"
@ -52,7 +41,7 @@ checksum = "db4ce4441f99dbd377ca8a8f57b698c44d0d6e712d8329b5040da5a64aa1ce73"
dependencies = [ dependencies = [
"base64ct", "base64ct",
"blake2", "blake2",
"password-hash 0.4.2", "password-hash",
] ]
[[package]] [[package]]
@ -998,7 +987,7 @@ dependencies = [
"anyhow", "anyhow",
"atty", "atty",
"clap", "clap",
"omegaupload-common 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "omegaupload-common",
"reqwest", "reqwest",
"rpassword", "rpassword",
] ]
@ -1007,7 +996,7 @@ dependencies = [
name = "omegaupload-common" name = "omegaupload-common"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"argon2 0.4.1", "argon2",
"base64", "base64",
"bytes", "bytes",
"chacha20poly1305", "chacha20poly1305",
@ -1025,27 +1014,6 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "omegaupload-common"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0e6112dcb442b5d280f65cf14b9d6749f3585709d1ed2f1b8821f12c3b6c16"
dependencies = [
"argon2 0.3.4",
"base64",
"bytes",
"chacha20poly1305",
"chrono",
"headers",
"lazy_static",
"rand",
"secrecy",
"serde",
"thiserror",
"typenum",
"url",
]
[[package]] [[package]]
name = "omegaupload-server" name = "omegaupload-server"
version = "0.1.0" version = "0.1.0"
@ -1058,7 +1026,7 @@ dependencies = [
"futures", "futures",
"headers", "headers",
"lazy_static", "lazy_static",
"omegaupload-common 0.2.0", "omegaupload-common",
"rand", "rand",
"rocksdb", "rocksdb",
"serde", "serde",
@ -1084,7 +1052,7 @@ dependencies = [
"http", "http",
"js-sys", "js-sys",
"mime_guess", "mime_guess",
"omegaupload-common 0.2.0", "omegaupload-common",
"reqwasm", "reqwasm",
"serde", "serde",
"tar", "tar",
@ -1113,17 +1081,6 @@ version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
[[package]]
name = "password-hash"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8"
dependencies = [
"base64ct",
"rand_core",
"subtle",
]
[[package]] [[package]]
name = "password-hash" name = "password-hash"
version = "0.4.2" version = "0.4.2"

View file

@ -9,8 +9,7 @@ license = "GPL-3.0-or-later"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
omegaupload-common = "0.2.0" omegaupload-common = { path = "../common" }
anyhow = "1.0.58" anyhow = "1.0.58"
atty = "0.2.14" atty = "0.2.14"
clap = { version = "3.2.8", features = ["derive"] } clap = { version = "3.2.8", features = ["derive"] }

View file

@ -25,6 +25,7 @@ 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, SecretString, SecretVec}; use omegaupload_common::secrecy::{ExposeSecret, SecretString, SecretVec};
use omegaupload_common::fragment::Builder;
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,10 +34,6 @@ use reqwest::header::EXPIRES;
use reqwest::StatusCode; use reqwest::StatusCode;
use rpassword::prompt_password; use rpassword::prompt_password;
use crate::fragment::Builder;
mod fragment;
#[derive(Parser)] #[derive(Parser)]
struct Opts { struct Opts {
#[clap(subcommand)] #[clap(subcommand)]

View file

@ -1,4 +1,4 @@
use omegaupload_common::secrecy::{ExposeSecret, SecretString}; use crate::secrecy::{ExposeSecret, SecretString};
pub struct Builder { pub struct Builder {
decryption_key: SecretString, decryption_key: SecretString,

View file

@ -41,6 +41,7 @@ use crate::crypto::Key;
pub mod base64; pub mod base64;
pub mod crypto; pub mod crypto;
pub mod fragment;
pub const API_ENDPOINT: &str = "/api"; pub const API_ENDPOINT: &str = "/api";

View file

@ -17,7 +17,8 @@
"highlight.js": "^11.4.0", "highlight.js": "^11.4.0",
"highlightjs-line-numbers.js": "^2.8.0", "highlightjs-line-numbers.js": "^2.8.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2" "react-dom": "^17.0.2",
"source-map-loader": "^4.0.0"
}, },
"scripts": { "scripts": {
"build": "webpack --mode production", "build": "webpack --mode production",

View file

@ -26,8 +26,11 @@ use http::uri::PathAndQuery;
use http::{StatusCode, Uri}; use http::{StatusCode, Uri};
use js_sys::{Array, JsString, Object, Uint8Array}; use js_sys::{Array, JsString, Object, Uint8Array};
use omegaupload_common::crypto::{Error as CryptoError, Key}; use omegaupload_common::crypto::{Error as CryptoError, Key};
use omegaupload_common::secrecy::{Secret, SecretVec}; use omegaupload_common::fragment::Builder;
use omegaupload_common::{Expiration, PartialParsedUrl}; use omegaupload_common::base64;
use omegaupload_common::crypto::seal_in_place;
use omegaupload_common::secrecy::{Secret, SecretVec, SecretString, ExposeSecret};
use omegaupload_common::{Expiration, PartialParsedUrl, Url};
use reqwasm::http::Request; use reqwasm::http::Request;
use wasm_bindgen::prelude::{wasm_bindgen, Closure}; use wasm_bindgen::prelude::{wasm_bindgen, Closure};
use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen::{JsCast, JsValue};
@ -50,6 +53,8 @@ extern "C" {
pub fn load_from_db(mime_type: JsString, name: Option<JsString>, language: Option<JsString>); pub fn load_from_db(mime_type: JsString, name: Option<JsString>, language: Option<JsString>);
#[wasm_bindgen(js_name = renderMessage)] #[wasm_bindgen(js_name = renderMessage)]
pub fn render_message(message: JsString); pub fn render_message(message: JsString);
#[wasm_bindgen(js_name = createUploadUi)]
pub fn create_upload_ui();
} }
fn window() -> Window { fn window() -> Window {
@ -75,7 +80,7 @@ pub fn start() {
std::panic::set_hook(Box::new(console_error_panic_hook::hook)); std::panic::set_hook(Box::new(console_error_panic_hook::hook));
if location().pathname().unwrap() == "/" { if location().pathname().unwrap() == "/" {
render_message("Go away".into()); create_upload_ui();
return; return;
} }
@ -166,6 +171,39 @@ pub fn start() {
}); });
} }
#[wasm_bindgen]
#[allow(clippy::future_not_send)]
#[allow(clippy::missing_panics_doc)]
pub fn encrypt_string(data: String) {
spawn_local(async move {
if let Err(e) = do_encrypt(data.into_bytes()).await {
log!(e.to_string());
}
});
}
#[allow(clippy::future_not_send)]
async fn do_encrypt(mut data: Vec<u8>) -> Result<()> {
let (data, key) = {
let enc_key = seal_in_place(&mut data, None)?;
let key = SecretString::new(base64::encode(&enc_key.expose_secret().as_ref()));
(data, key)
};
let s: String = location().to_string().into();
let mut url = Url::from_str(&s)?;
let fragment = Builder::new(key);
let js_data = Uint8Array::new_with_length(data.len() as u32);
js_data.copy_from(&data);
let short_code = Request::post(url.as_ref()).body(js_data).send().await?.text().await?;
url.set_path(&short_code);
url.set_fragment(Some(fragment.build().expose_secret()));
location().set_href(url.as_ref()).expect("Unable to navigate to encrypted upload");
Ok(())
}
#[allow(clippy::future_not_send)] #[allow(clippy::future_not_send)]
async fn fetch_resources( async fn fetch_resources(
request_uri: Uri, request_uri: Uri,

View file

@ -95,6 +95,14 @@ img, audio, video {
max-width: 75vw; max-width: 75vw;
} }
textarea {
width: 100%;
height: 100%;
min-width: 75vw;
min-height: 75vh;
box-sizing: border-box;
}
.primary { .primary {
@extend .hljs; @extend .hljs;
} }
@ -108,4 +116,4 @@ img, audio, video {
@extend .align-right; @extend .align-right;
padding-left: $padding; padding-left: $padding;
} }
} }

View file

@ -17,11 +17,56 @@
import './main.scss'; import './main.scss';
import ReactDom from 'react-dom'; import ReactDom from 'react-dom';
import React from 'react'; import React from 'react';
import { encrypt_string } from '../pkg';
const hljs = require('highlight.js'); const hljs = require('highlight.js');
(window as any).hljs = hljs; (window as any).hljs = hljs;
require('highlightjs-line-numbers.js'); require('highlightjs-line-numbers.js');
class PasteForm extends React.Component {
constructor(props) {
super(props)
this.state = {
value: "Sample text"
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
try {
encrypt_string(this.state.value);
} catch (e) {
console.error(e);
}
event.preventDefault();
}
render() {
return (
<pre className='paste'>
<form class="hljs centered" onSubmit={this.handleSubmit}>
<textarea value={this.state.value} onChange={this.handleChange} />
<input type="submit" value="submit" />
</form>
</pre>
);
}
}
function createUploadUi() {
const html = <main className='hljs centered fullscreen'>
<PasteForm />
</main>;
ReactDom.render(html, document.body);
}
function loadFromDb(mimeType: string, name?: string, language?: string) { function loadFromDb(mimeType: string, name?: string, language?: string) {
let resolvedName; let resolvedName;
if (name) { if (name) {
@ -287,4 +332,4 @@ function getObjectUrl(data, mimeType?: string) {
window.addEventListener("hashchange", () => location.reload()); window.addEventListener("hashchange", () => location.reload());
export { renderMessage, loadFromDb }; export { renderMessage, createUploadUi, loadFromDb };

View file

@ -2,6 +2,7 @@ const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); const webpack = require('webpack');
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin"); const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
const { SourceMapDevToolPlugin } = require('webpack');
module.exports = { module.exports = {
entry: './web/src/index.js', entry: './web/src/index.js',
@ -21,6 +22,8 @@ module.exports = {
"css-loader", "css-loader",
// Compiles Sass to CSS // Compiles Sass to CSS
"sass-loader", "sass-loader",
// source map for debugging
"source-map-loader"
], ],
}, },
], ],
@ -41,6 +44,7 @@ module.exports = {
crateDirectory: path.resolve(__dirname, "web"), crateDirectory: path.resolve(__dirname, "web"),
outDir: path.resolve(__dirname, "web/pkg"), outDir: path.resolve(__dirname, "web/pkg"),
}), }),
new SourceMapDevToolPlugin({}),
], ],
experiments: { experiments: {
asyncWebAssembly: true, asyncWebAssembly: true,

587
yarn.lock

File diff suppressed because it is too large Load diff