add support for encrypting text files from web
This commit is contained in:
parent
b793139a99
commit
774b13e46c
11 changed files with 438 additions and 321 deletions
53
Cargo.lock
generated
53
Cargo.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -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"] }
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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,
|
|
@ -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";
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue