clippy lints
This commit is contained in:
parent
de4d4f90b7
commit
3bc4541390
8 changed files with 57 additions and 28 deletions
|
@ -17,7 +17,7 @@ cargo build --release --bin omegaupload-server
|
||||||
# Prepare assets for upload to webserver
|
# Prepare assets for upload to webserver
|
||||||
mkdir -p dist/static
|
mkdir -p dist/static
|
||||||
# Move everything that's not index.html into a `static` subdir
|
# Move everything that's not index.html into a `static` subdir
|
||||||
find dist -type f -exec mv {} dist/static/ ";"
|
find dist -not -name index.html -type f -exec mv {} dist/static/ ";"
|
||||||
|
|
||||||
strip target/release/omegaupload-server
|
strip target/release/omegaupload-server
|
||||||
cp target/release/omegaupload-server dist/omegaupload-server
|
cp target/release/omegaupload-server dist/omegaupload-server
|
||||||
|
|
|
@ -6,6 +6,11 @@ pub fn encode(input: impl AsRef<[u8]>) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// URL-safe Base64 decoding.
|
/// URL-safe Base64 decoding.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if a buffer cannot be decoded, such as if there's an
|
||||||
|
/// incorrect number of bytes.
|
||||||
pub fn decode(input: impl AsRef<[u8]>) -> Result<Vec<u8>, DecodeError> {
|
pub fn decode(input: impl AsRef<[u8]>) -> Result<Vec<u8>, DecodeError> {
|
||||||
base64::decode_config(input, URL_SAFE)
|
base64::decode_config(input, URL_SAFE)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use chacha20poly1305::aead::generic_array::GenericArray;
|
||||||
use chacha20poly1305::aead::{AeadInPlace, NewAead};
|
use chacha20poly1305::aead::{AeadInPlace, NewAead};
|
||||||
use chacha20poly1305::XChaCha20Poly1305;
|
use chacha20poly1305::XChaCha20Poly1305;
|
||||||
use chacha20poly1305::XNonce;
|
use chacha20poly1305::XNonce;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use secrecy::{ExposeSecret, Secret, SecretVec, Zeroize};
|
use secrecy::{ExposeSecret, Secret, SecretVec, Zeroize};
|
||||||
use typenum::Unsigned;
|
use typenum::Unsigned;
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ pub enum Error {
|
||||||
pub struct Key(chacha20poly1305::Key);
|
pub struct Key(chacha20poly1305::Key);
|
||||||
|
|
||||||
impl Key {
|
impl Key {
|
||||||
|
/// Encloses a secret key in a secret `Key` struct.
|
||||||
pub fn new_secret(vec: Vec<u8>) -> Option<Secret<Self>> {
|
pub fn new_secret(vec: Vec<u8>) -> Option<Secret<Self>> {
|
||||||
chacha20poly1305::Key::from_exact_iter(vec.into_iter())
|
chacha20poly1305::Key::from_exact_iter(vec.into_iter())
|
||||||
.map(Self)
|
.map(Self)
|
||||||
|
@ -58,11 +59,14 @@ impl Zeroize for Key {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Seals the provided message with an optional message. The resulting sealed
|
/// Seals the provided message with an optional password, returning the secret
|
||||||
/// message has the nonce used to encrypt the message appended to it as well as
|
/// key used to encrypt the message and mutating the buffer to contain necessary
|
||||||
/// a salt string used to derive the key. In other words, the modified buffer is
|
/// metadata.
|
||||||
/// one of the following to possibilities, depending if there was a password
|
///
|
||||||
/// provided:
|
/// The resulting sealed message has the nonce used to encrypt the message
|
||||||
|
/// appended to it as well as a salt string used to derive the key. In other
|
||||||
|
/// words, the modified buffer is one of the following to possibilities,
|
||||||
|
/// depending if there was a password provided:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// modified = C(message, rng_key, nonce) || nonce
|
/// modified = C(message, rng_key, nonce) || nonce
|
||||||
|
@ -77,6 +81,17 @@ impl Zeroize for Key {
|
||||||
/// `XChaCha20Poly1305`.
|
/// `XChaCha20Poly1305`.
|
||||||
/// - `rng_key` represents a randomly generated key.
|
/// - `rng_key` represents a randomly generated key.
|
||||||
/// - `kdf(pw, salt)` represents a key derived from Argon2.
|
/// - `kdf(pw, salt)` represents a key derived from Argon2.
|
||||||
|
/// - `nonce` represents a randomly generated nonce.
|
||||||
|
///
|
||||||
|
/// Note that the lengths for the nonce, key, and salt follow recommended
|
||||||
|
/// values. As of writing this doc (2021-10-31), the nonce size is 24 bytes, the
|
||||||
|
/// salt size is 16 bytes, and the key size is 32 bytes.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This message will return an error if and only if there was a problem
|
||||||
|
/// encrypting the message or deriving a secret key from the password, if one
|
||||||
|
/// was provided.
|
||||||
pub fn seal_in_place(
|
pub fn seal_in_place(
|
||||||
message: &mut Vec<u8>,
|
message: &mut Vec<u8>,
|
||||||
pw: Option<SecretVec<u8>>,
|
pw: Option<SecretVec<u8>>,
|
||||||
|
@ -104,6 +119,12 @@ pub fn seal_in_place(
|
||||||
Ok(key)
|
Ok(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opens a message that has been sealed with `seal_in_place`.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if there was a decryption failure or if there was a problem
|
||||||
|
/// deriving a secret key from the password.
|
||||||
pub fn open_in_place(
|
pub fn open_in_place(
|
||||||
data: &mut Vec<u8>,
|
data: &mut Vec<u8>,
|
||||||
key: &Secret<Key>,
|
key: &Secret<Key>,
|
||||||
|
@ -140,10 +161,9 @@ pub fn open_in_place(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Securely generates a random key and nonce.
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn gen_key_nonce() -> (Secret<Key>, Nonce) {
|
fn gen_key_nonce() -> (Secret<Key>, Nonce) {
|
||||||
let mut rng = thread_rng();
|
let mut rng = get_csrng();
|
||||||
let mut key = GenericArray::default();
|
let mut key = GenericArray::default();
|
||||||
rng.fill(key.as_mut_slice());
|
rng.fill(key.as_mut_slice());
|
||||||
let mut nonce = Nonce::default();
|
let mut nonce = Nonce::default();
|
||||||
|
@ -154,15 +174,9 @@ fn gen_key_nonce() -> (Secret<Key>, Nonce) {
|
||||||
// Type alias; to ensure that we're consistent on what the inner impl is.
|
// Type alias; to ensure that we're consistent on what the inner impl is.
|
||||||
type NonceImpl = XNonce;
|
type NonceImpl = XNonce;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
|
||||||
struct Nonce(NonceImpl);
|
struct Nonce(NonceImpl);
|
||||||
|
|
||||||
impl Default for Nonce {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(GenericArray::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Nonce {
|
impl Deref for Nonce {
|
||||||
type Target = NonceImpl;
|
type Target = NonceImpl;
|
||||||
|
|
||||||
|
@ -207,7 +221,7 @@ impl Salt {
|
||||||
|
|
||||||
fn random() -> Self {
|
fn random() -> Self {
|
||||||
let mut salt = [0_u8; Self::SIZE];
|
let mut salt = [0_u8; Self::SIZE];
|
||||||
thread_rng().fill(&mut salt);
|
get_csrng().fill(&mut salt);
|
||||||
Self(salt)
|
Self(salt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,3 +241,12 @@ fn kdf(password: &SecretVec<u8>) -> Result<(Secret<Key>, Salt), argon2::Error> {
|
||||||
|
|
||||||
Ok((Secret::new(key), salt))
|
Ok((Secret::new(key), salt))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetches a cryptographically secure random number generator. This indirection
|
||||||
|
/// is used for better auditing the quality of rng. Notably, this function
|
||||||
|
/// returns a `Rng` with the `CryptoRng` marker trait, preventing
|
||||||
|
/// non-cryptographically secure RNGs from being used.
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_csrng() -> impl CryptoRng + Rng {
|
||||||
|
rand::thread_rng()
|
||||||
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ futures = "0.3"
|
||||||
# We just need to pull in whatever axum is pulling in
|
# We just need to pull in whatever axum is pulling in
|
||||||
headers = "*"
|
headers = "*"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
rand = "0.8"
|
# Disable `random()` and `thread_rng()`
|
||||||
|
rand = { version = "0.8", default_features = false }
|
||||||
rocksdb = { version = "0.17", default_features = false, features = ["zstd"] }
|
rocksdb = { version = "0.17", default_features = false, features = ["zstd"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
signal-hook = "0.3"
|
signal-hook = "0.3"
|
||||||
|
|
|
@ -16,8 +16,8 @@ use chrono::Utc;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use headers::HeaderMap;
|
use headers::HeaderMap;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use omegaupload_common::crypto::get_csrng;
|
||||||
use omegaupload_common::{Expiration, API_ENDPOINT};
|
use omegaupload_common::{Expiration, API_ENDPOINT};
|
||||||
use rand::thread_rng;
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rocksdb::{ColumnFamilyDescriptor, IteratorMode};
|
use rocksdb::{ColumnFamilyDescriptor, IteratorMode};
|
||||||
use rocksdb::{Options, DB};
|
use rocksdb::{Options, DB};
|
||||||
|
@ -41,6 +41,7 @@ lazy_static! {
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
const INDEX_PAGE: Html<&'static str> = Html(include_str!("../../dist/index.html"));
|
||||||
const PASTE_DB_PATH: &str = "database";
|
const PASTE_DB_PATH: &str = "database";
|
||||||
const SHORT_CODE_SIZE: usize = 12;
|
const SHORT_CODE_SIZE: usize = 12;
|
||||||
|
|
||||||
|
@ -68,8 +69,6 @@ async fn main() -> Result<()> {
|
||||||
let root_service = service::get(ServeDir::new("static"))
|
let root_service = service::get(ServeDir::new("static"))
|
||||||
.handle_error(|_| Ok::<_, Infallible>(StatusCode::NOT_FOUND));
|
.handle_error(|_| Ok::<_, Infallible>(StatusCode::NOT_FOUND));
|
||||||
|
|
||||||
const INDEX_PAGE: Html<&'static str> = Html(include_str!("../../dist/index.html"));
|
|
||||||
|
|
||||||
axum::Server::bind(&"0.0.0.0:8080".parse()?)
|
axum::Server::bind(&"0.0.0.0:8080".parse()?)
|
||||||
.serve(
|
.serve(
|
||||||
Router::new()
|
Router::new()
|
||||||
|
@ -206,7 +205,7 @@ async fn upload<const N: usize>(
|
||||||
// Try finding a code; give up after 1000 attempts
|
// Try finding a code; give up after 1000 attempts
|
||||||
// Statistics show that this is very unlikely to happen
|
// Statistics show that this is very unlikely to happen
|
||||||
for i in 0..1000 {
|
for i in 0..1000 {
|
||||||
let code: ShortCode<N> = thread_rng().sample(short_code::Generator);
|
let code: ShortCode<N> = get_csrng().sample(short_code::Generator);
|
||||||
let db = Arc::clone(&db);
|
let db = Arc::clone(&db);
|
||||||
let key = code.as_bytes();
|
let key = code.as_bytes();
|
||||||
let query = task::spawn_blocking(move || {
|
let query = task::spawn_blocking(move || {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use rand::prelude::Distribution;
|
use rand::prelude::Distribution;
|
||||||
|
use rand::Rng;
|
||||||
use serde::de::{Unexpected, Visitor};
|
use serde::de::{Unexpected, Visitor};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
@ -109,7 +110,7 @@ pub struct Generator;
|
||||||
const ALPHABET: &[u8; 32] = b"23456789CFGHJMPQRVWXcfghjmpqrvwx";
|
const ALPHABET: &[u8; 32] = b"23456789CFGHJMPQRVWXcfghjmpqrvwx";
|
||||||
|
|
||||||
impl Distribution<ShortCodeChar> for Generator {
|
impl Distribution<ShortCodeChar> for Generator {
|
||||||
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ShortCodeChar {
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ShortCodeChar {
|
||||||
let value = rng.gen_range(0..32);
|
let value = rng.gen_range(0..32);
|
||||||
assert!(value < 32);
|
assert!(value < 32);
|
||||||
ShortCodeChar(ALPHABET[value] as char)
|
ShortCodeChar(ALPHABET[value] as char)
|
||||||
|
@ -117,7 +118,7 @@ impl Distribution<ShortCodeChar> for Generator {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Distribution<ShortCode<N>> for Generator {
|
impl<const N: usize> Distribution<ShortCode<N>> for Generator {
|
||||||
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ShortCode<N> {
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ShortCode<N> {
|
||||||
let mut arr = [ShortCodeChar('\0'); N];
|
let mut arr = [ShortCodeChar('\0'); N];
|
||||||
|
|
||||||
for c in arr.iter_mut() {
|
for c in arr.iter_mut() {
|
||||||
|
|
|
@ -12,7 +12,7 @@ use web_sys::{Blob, BlobPropertyBag};
|
||||||
#[derive(Clone, Serialize)]
|
#[derive(Clone, Serialize)]
|
||||||
pub struct ArchiveMeta {
|
pub struct ArchiveMeta {
|
||||||
name: String,
|
name: String,
|
||||||
file_size: usize,
|
file_size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -86,7 +86,7 @@ pub fn decrypt(
|
||||||
match zip.by_index(i) {
|
match zip.by_index(i) {
|
||||||
Ok(file) => entries.push(ArchiveMeta {
|
Ok(file) => entries.push(ArchiveMeta {
|
||||||
name: file.name().to_string(),
|
name: file.name().to_string(),
|
||||||
file_size: file.size() as usize,
|
file_size: file.size(),
|
||||||
}),
|
}),
|
||||||
Err(err) => match err {
|
Err(err) => match err {
|
||||||
zip::result::ZipError::UnsupportedArchive(s) => {
|
zip::result::ZipError::UnsupportedArchive(s) => {
|
||||||
|
|
|
@ -96,6 +96,8 @@ fn main() {
|
||||||
Ok(Some(password)) if !password.is_empty() => {
|
Ok(Some(password)) if !password.is_empty() => {
|
||||||
break Some(SecretVec::new(password.into_bytes()));
|
break Some(SecretVec::new(password.into_bytes()));
|
||||||
}
|
}
|
||||||
|
// Empty message was entered.
|
||||||
|
Ok(Some(_)) => (),
|
||||||
// Cancel button was entered.
|
// Cancel button was entered.
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
render_message("This paste requires a password.".into());
|
render_message("This paste requires a password.".into());
|
||||||
|
@ -112,8 +114,6 @@ fn main() {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
log!(location().pathname().unwrap());
|
|
||||||
|
|
||||||
spawn_local(async move {
|
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).await {
|
||||||
log!(e.to_string());
|
log!(e.to_string());
|
||||||
|
|
Loading…
Reference in a new issue