This commit is contained in:
Aaron Global 2025-11-17 17:21:49 -05:00
commit 6f49740c39
18 changed files with 3185 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

1117
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

7
Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[workspace]
members = [
"crates/cli",
"crates/message-tools",
"crates/server"
]
resolver = "3"

2
README.md Normal file
View file

@ -0,0 +1,2 @@
# zachery-lol
Code and assets for my website.

8
crates/cli/Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "cli"
version = "0.1.0"
edition = "2024"
default-run = "cli"
[dependencies]
clap = { version = "4.5.52", features = ["derive"] }

92
crates/cli/src/main.rs Normal file
View file

@ -0,0 +1,92 @@
use std::process::Command;
use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Builds the website and server, including wasm files
Build,
/// Starts the server
Run,
/// Generates new encryption keys
GenKeys {
/// How many keypairs to generate
#[arg(short, long, default_value = "100")]
number: Option<usize>,
},
/// Reads fetched messages
ReadMessages {
/// Optional source file path
#[arg(short, long)]
source: Option<String>,
/// Optional output file path
#[arg(short, long)]
out_dir: Option<String>,
},
}
fn main() {
let cli = Cli::parse();
match &cli.command {
Commands::Build => {
println!("Executing build command...");
build();
}
Commands::Run => {
println!("Executing run command...");
// Add your run logic here
}
Commands::GenKeys { .. } => {
println!("Executing gen-keys command...");
// Add your key generation logic here
}
Commands::ReadMessages { source, .. } => {
println!("Executing read-messages command...");
match source {
Some(s) => println!("Reading from source: {}", s),
None => println!("Reading from default source."),
}
// Add your message reading logic here
}
}
}
fn build() {
let status = Command::new("wasm-pack")
.arg("build")
.arg("--out-dir")
.arg("../../routes/contact/pkg")
.arg("crates/message-tools")
.arg("--target")
.arg("no-modules")
.status();
match status {
Ok(exit_status) => {
if exit_status.success() {
println!("\nBuild successful!");
} else {
// Print the exit code if the build failed
eprintln!("\nBuild failed with exit code: {:?}", exit_status.code());
std::process::exit(exit_status.code().unwrap_or(1));
}
}
Err(e) => {
eprintln!("\nFailed to execute cargo build command: {}", e);
std::process::exit(1); // Exit with an error code
}
}
}

1
crates/message-tools/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
target/*

462
crates/message-tools/Cargo.lock generated Normal file
View file

@ -0,0 +1,462 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aead"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
"crypto-common",
"generic-array",
]
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chacha20"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "chacha20poly1305"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
dependencies = [
"aead",
"chacha20",
"cipher",
"poly1305",
"zeroize",
]
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
"zeroize",
]
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"rand_core",
"typenum",
]
[[package]]
name = "curve25519-dalek"
version = "4.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"fiat-crypto",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek-derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "fiat-crypto"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi",
"wasm-bindgen",
]
[[package]]
name = "inout"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [
"generic-array",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "message-box"
version = "0.1.0"
dependencies = [
"blake2",
"chacha20poly1305",
"getrandom",
"serde",
"serde_json",
"wasm-bindgen",
"x25519-dalek",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "opaque-debug"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "poly1305"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "semver"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
"serde_core",
]
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "typenum"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "universal-hash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
"crypto-common",
"subtle",
]
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasm-bindgen"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
dependencies = [
"unicode-ident",
]
[[package]]
name = "x25519-dalek"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
dependencies = [
"curve25519-dalek",
"rand_core",
"serde",
"zeroize",
]
[[package]]
name = "zeroize"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -0,0 +1,18 @@
[package]
name = "message-tools"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
chacha20poly1305 = "0.10.1"
x25519-dalek = { version = "2.0.1", features = ["getrandom", "static_secrets"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"
blake2 = "0.10.6"
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
wasm-bindgen = "0.2.105"
getrandom = { version = "0.2", features = ["js"] }

View file

@ -0,0 +1,227 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Input Form</title>
<style>
body {
display: flex;
flex-direction: column; /* Ensure vertical stacking */
align-items: center; /* Center horizontally */
padding-top: 50px;
min-height: 120vh;
margin: 0;
font-family: Arial, sans-serif;
background-color: Cornsilk;
}
.form-container {
background-color: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
width: 90%;
max-width: 800px;
min-height: 400px;
max-height: 1000px;
margin-bottom: 20px; /* Add space below the form container */
}
nav.directory {
width: 90%;
max-width: 800px;
margin: 0 auto; /* Center horizontally */
text-align: center;
}
nav.directory dt a {
text-decoration: none;
color: #333;
padding: 0.5rem 1rem;
display: inline-block;
width: auto; /* Prevent stretching */
}
.input-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
textarea {
width: 100%;
height: 120px;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
resize: vertical;
box-sizing: border-box;
}
.expandable-section {
margin-top: 20px;
}
.expandable-header {
cursor: pointer;
padding: 10px;
background-color: #f0f0f0;
border-radius: 4px;
}
.expandable-content {
display: none;
padding: 10px;
background-color: #f9f9f9;
border-radius: 0 0 4px 4px;
}
</style>
<script src="pkg/message_box.js"></script>
<script>
const { make_salt, make_key_bytes, box_message } = wasm_bindgen;
var serverPublicKey;
async function run() {
await wasm_bindgen();
await fetchPublicKey();
console.log(`Server pk: ${serverPublicKey}`)
const form = document.getElementById("message-form");
form.addEventListener("submit", (event) => {
event.preventDefault();
submit();
});
}
async function fetchPublicKey() {
try {
const response = await fetch("http://127.0.0.1:3001/pubkey");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const pubkeyJSON = await response.text();
serverPublicKey = JSON.parse(pubkeyJSON)
} catch (error) {
console.error("Error fetching public key:", error);
document.getElementById("status").textContent =
"Failed to load public key.";
}
}
function submit() {
console.log("begin");
const user = document.getElementById("name").value;
const password = document.getElementById("password").value;
const message = document.getElementById("message").value;
const salt = make_salt();
const makeKeyBytesArgs = {
name: String(user),
password: String(password),
salt: [...salt],
};
const keyBytes = make_key_bytes(JSON.stringify(makeKeyBytesArgs));
console.log(keyBytes);
const boxMessageArgs = {
user: String(user),
salt: [...salt],
user_sk: [...keyBytes],
remote_pk: [...serverPublicKey],
plaintext: String(message),
};
console.log("Boxed preflight: ", JSON.stringify(boxMessageArgs))
const boxed = box_message(JSON.stringify(boxMessageArgs));
console.log(JSON.parse(boxed));
console.log("End");
alert("Sent!");
location.reload();
}
run();
</script>
<script>
function toggleSection() {
const content = document.getElementById("expandableContent");
const header = document.querySelector(".expandable-header");
if (content.style.display === "block") {
content.style.display = "none";
header.innerHTML = "How to use ▼";
} else {
content.style.display = "block";
header.innerHTML = "How to use ▲";
}
}
</script>
</head>
<body>
<div class="form-container">
<form id="message-form">
<div class="input-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" />
</div>
<div class="input-group">
<label for="password">Password (optional)</label>
<input type="password" id="password" name="password" />
</div>
<div class="input-group">
<label for="message">Message</label>
<textarea id="message" name="message"></textarea>
</div>
<div class="input-group">
<button
type="submit"
style="
width: 100%;
padding: 10px;
background-color: #dbdbdb;
border: none;
border-radius: 4px;
cursor: pointer;
"
>
Submit
</button>
</div>
</form>
<div class="expandable-section">
<div class="expandable-header" onclick="toggleSection()">
How to use ▼
</div>
<div class="expandable-content" id="expandableContent">
<p>
Tell me who you are, and add an optional password. If I do not
otherwise have your contact information, please tell me the best way
to reach you back.
</p>
</div>
</div>
</div>
<nav class="directory">
<dt><a href="/">back to home</a></dt>
</nav>
</body>
</html>

View file

@ -0,0 +1,196 @@
use blake2::{Blake2s256, Digest};
use chacha20poly1305::{
AeadCore, KeyInit, XChaCha20Poly1305,
aead::{Aead, OsRng},
};
use serde::{Deserialize, Serialize};
use x25519_dalek::{PublicKey, StaticSecret};
#[cfg(target_arch = "wasm32")]
pub mod wasm;
// Syntactic sugar
type Error = Box<dyn std::error::Error>;
type Result<T> = std::result::Result<T, Error>;
fn to_error<E: std::fmt::Debug>(e: E) -> Error {
format!("{e:?}").into()
}
/// An encrypted message packed with metadata ready to be sent off from the client
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct BoxedMessage {
/// Name given by the user
user: String,
/// salt generated randomly, used to make the password hash
salt: Vec<u8>,
/// user public key, generated from their password and a salt using a cryptographic password hash
user_pk: Vec<u8>,
/// pubkey given by the server, used for symmetric AEAD
remote_pk: Vec<u8>,
/// nonce for XChaCha20poly1305
nonce: Vec<u8>,
/// encrypted message using the user's generated secret key (from password hash) and the public key given by the server
ciphertext: Vec<u8>,
}
#[derive(Deserialize, Serialize, Debug, Default)]
pub struct MakeKeyBytesArgs {
pub name: String,
pub password: String,
pub salt: Vec<u8>,
}
/// As a way of enabling shared keys, we make a quick and dirty secret key from the user-given
/// name and "password" and a cryptographic hash, in this case blake2s.
pub fn make_key_bytes(args: MakeKeyBytesArgs) -> Result<Vec<u8>> {
let MakeKeyBytesArgs {
name,
password,
salt,
} = args;
let pw = format!("{name}{password}");
let mut hasher = Blake2s256::new();
hasher.update(pw.as_bytes());
hasher.update(salt);
let key_bytes = hasher.finalize();
Ok(key_bytes.to_vec())
}
#[derive(Deserialize, Serialize, Debug, Default)]
pub struct BoxMessageArgs {
pub user: String,
pub salt: Vec<u8>,
pub user_sk: Vec<u8>,
pub remote_pk: Vec<u8>,
pub plaintext: String,
}
/// Encrypt plaintext and pack all the data needed for the server to later decrypt
pub fn box_message(args: BoxMessageArgs) -> Result<BoxedMessage> {
let BoxMessageArgs {
user,
salt,
user_sk,
remote_pk,
plaintext,
} = args;
let sk = {
let bytes: [u8; 32] = user_sk.try_into().map_err(to_error)?;
StaticSecret::from(bytes)
};
let user_pk = PublicKey::from(&sk);
let remote_pubkey = {
let bytes: [u8; 32] = remote_pk.try_into().map_err(to_error)?;
PublicKey::from(bytes)
};
let shared_key = sk.diffie_hellman(&remote_pubkey);
let cipher = XChaCha20Poly1305::new(shared_key.as_bytes().into());
let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
let ciphertext = cipher
.encrypt(&nonce, plaintext.as_bytes())
.map_err(to_error)?;
Ok(BoxedMessage {
user,
salt,
user_pk: user_pk.to_bytes().to_vec(),
remote_pk: remote_pubkey.to_bytes().to_vec(),
nonce: nonce.to_vec(),
ciphertext,
})
}
/// Takes an encrypted message and the secret of the corresponding public key of the [BoxedMessage] and returns the plaintext
pub fn unbox_message<K: Into<StaticSecret>>(msg: BoxedMessage, sk: K) -> Result<String> {
let user_pk: [u8; 32] = msg.user_pk.try_into().map_err(to_error)?;
let shared_key = (sk.into() as StaticSecret).diffie_hellman(&PublicKey::from(user_pk));
let cipher = XChaCha20Poly1305::new(shared_key.as_bytes().into());
let plaintext: String = cipher
.decrypt(msg.nonce.as_slice().into(), msg.ciphertext.as_slice())
.map_err(to_error)?
.try_into()?;
Ok(plaintext)
}
#[cfg(test)]
mod test {
use crate::*;
use x25519_dalek::{EphemeralSecret, PublicKey, StaticSecret};
#[test]
fn makes_key() {
let name = "alice";
let password = "safe_password";
let salt = 42u64.to_le_bytes();
let _key = make_key_bytes(MakeKeyBytesArgs {
name: name.to_string(),
password: password.to_string(),
salt: salt.to_vec(),
})
.unwrap();
}
#[test]
fn boxes_message() {
let message = "Hello, world!";
let user = "me".to_string();
let salt = 42u64.to_le_bytes().to_vec();
let user_sk: [u8; 32] = make_key_bytes(MakeKeyBytesArgs {
name: user.clone(),
password: "hunter2".into(),
salt,
})
.expect("failed to make user key")
.try_into()
.expect("wrong vector size");
let args = BoxMessageArgs {
user,
salt: 42u64.to_le_bytes().to_vec(),
user_sk: user_sk.to_vec(),
remote_pk: PublicKey::from(&EphemeralSecret::random())
.to_bytes()
.to_vec(),
plaintext: message.to_string(),
};
let _boxed = box_message(args).expect("failed to box");
}
#[test]
fn boxes_unboxes() {
let remote_sk = StaticSecret::random();
let message = "Hello, world!";
let user = "me".to_string();
let salt = 42u64.to_le_bytes().to_vec();
let user_sk: [u8; 32] = make_key_bytes(MakeKeyBytesArgs {
name: user.clone(),
password: "hunter2".into(),
salt,
})
.expect("failed to make user key")
.try_into()
.expect("wrong vector size");
let args = BoxMessageArgs {
user,
salt: 42u64.to_le_bytes().to_vec(),
user_sk: user_sk.to_vec(),
remote_pk: PublicKey::from(&remote_sk).to_bytes().to_vec(),
plaintext: message.to_string(),
};
let boxed = box_message(args).expect("failed to box");
let unboxed = unbox_message(boxed, remote_sk.to_bytes()).expect("failed to unbox");
assert_eq!(&unboxed, message);
}
}

View file

@ -0,0 +1,32 @@
use chacha20poly1305::aead::{OsRng, rand_core::CryptoRngCore};
use wasm_bindgen::prelude::*;
use crate::{BoxMessageArgs, MakeKeyBytesArgs};
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[wasm_bindgen]
pub fn make_salt() -> Vec<u8> {
let mut s = vec![0u8; 16];
let rng = &mut OsRng;
rng.as_rngcore().fill_bytes(&mut s);
s
}
#[wasm_bindgen]
pub fn make_key_bytes(args: String) -> Vec<u8> {
let args: MakeKeyBytesArgs = serde_json::from_str(&args).unwrap();
crate::make_key_bytes(args).unwrap()
}
#[wasm_bindgen]
pub fn box_message(args: String) -> String {
let args: BoxMessageArgs = serde_json::from_str(&args).unwrap();
let res = crate::box_message(args).unwrap();
serde_json::to_string(&res).unwrap()
}

644
crates/server/Cargo.lock generated Normal file
View file

@ -0,0 +1,644 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "axum"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
dependencies = [
"axum-core",
"bytes",
"form_urlencoded",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"serde_core",
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-core"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
"sync_wrapper",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bytes"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
dependencies = [
"percent-encoding",
]
[[package]]
name = "futures-channel"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-task"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"pin-utils",
]
[[package]]
name = "http"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http",
]
[[package]]
name = "http-body-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hyper"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
dependencies = [
"atomic-waker",
"bytes",
"futures-channel",
"futures-core",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"pin-utils",
"smallvec",
"tokio",
]
[[package]]
name = "hyper-util"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"hyper",
"pin-project-lite",
"tokio",
"tower-service",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "libc"
version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "matchit"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mio"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
dependencies = [
"libc",
"wasi",
"windows-sys 0.61.2",
]
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
"serde_core",
]
[[package]]
name = "serde_path_to_error"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
dependencies = [
"itoa",
"serde",
"serde_core",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]]
name = "syn"
version = "2.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]]
name = "tokio"
version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [
"bytes",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tower"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"log",
"pin-project-lite",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
dependencies = [
"once_cell",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "zachery-lol"
version = "0.1.0"
dependencies = [
"axum",
"tokio",
]

12
crates/server/Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "server"
version = "0.1.0"
edition = "2024"
[[bin]]
name = "server"
path = "bin/main.rs"
[dependencies]
axum = "0.8.7"
tokio = { version = "1.48.0", features = ["full"] }

33
crates/server/bin/main.rs Normal file
View file

@ -0,0 +1,33 @@
use axum::{Router, response::Html, routing::get};
use std::{fs::OpenOptions, io::Read};
type Error = Box<dyn std::error::Error>;
type Result<T> = std::result::Result<T, Error>;
#[tokio::main]
async fn main() -> Result<()> {
// build our application with a single route
let app = Router::new()
.route("/", get(serve_path("./routes/root/index.html")?))
.route("/who", get(serve_path("./routes/who/index.html")?))
.route("/contact", get(serve_path("./routes/contact/index.html")?))
// .route("/api/pubkey", get(todo!()));
;
// run our app with hyper, listening globally on port 3000
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
Ok(())
}
fn serve_path(path: impl AsRef<std::path::Path>) -> Result<Html<String>> {
let mut s = String::new();
OpenOptions::new()
.read(true)
.write(false)
.open(path)?
.read_to_string(&mut s)?;
Ok(Html(s))
}

227
routes/contact/index.html Normal file
View file

@ -0,0 +1,227 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Input Form</title>
<style>
body {
display: flex;
flex-direction: column; /* Ensure vertical stacking */
align-items: center; /* Center horizontally */
padding-top: 50px;
min-height: 120vh;
margin: 0;
font-family: Arial, sans-serif;
background-color: Cornsilk;
}
.form-container {
background-color: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
width: 90%;
max-width: 800px;
min-height: 400px;
max-height: 1000px;
margin-bottom: 20px; /* Add space below the form container */
}
nav.directory {
width: 90%;
max-width: 800px;
margin: 0 auto; /* Center horizontally */
text-align: center;
}
nav.directory dt a {
text-decoration: none;
color: #333;
padding: 0.5rem 1rem;
display: inline-block;
width: auto; /* Prevent stretching */
}
.input-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
textarea {
width: 100%;
height: 120px;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
resize: vertical;
box-sizing: border-box;
}
.expandable-section {
margin-top: 20px;
}
.expandable-header {
cursor: pointer;
padding: 10px;
background-color: #f0f0f0;
border-radius: 4px;
}
.expandable-content {
display: none;
padding: 10px;
background-color: #f9f9f9;
border-radius: 0 0 4px 4px;
}
</style>
<script src="pkg/message_tools.js"></script>
<script>
const { make_salt, make_key_bytes, box_message } = wasm_bindgen;
var serverPublicKey;
async function run() {
await wasm_bindgen();
await fetchPublicKey();
console.log(`Server pk: ${serverPublicKey}`)
const form = document.getElementById("message-form");
form.addEventListener("submit", (event) => {
event.preventDefault();
submit();
});
}
async function fetchPublicKey() {
try {
const response = await fetch("./api/pubkey");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const pubkeyJSON = await response.text();
serverPublicKey = JSON.parse(pubkeyJSON)
} catch (error) {
console.error("Error fetching public key:", error);
document.getElementById("status").textContent =
"Failed to load public key.";
}
}
function submit() {
console.log("begin");
const user = document.getElementById("name").value;
const password = document.getElementById("password").value;
const message = document.getElementById("message").value;
const salt = make_salt();
const makeKeyBytesArgs = {
name: String(user),
password: String(password),
salt: [...salt],
};
const keyBytes = make_key_bytes(JSON.stringify(makeKeyBytesArgs));
console.log(keyBytes);
const boxMessageArgs = {
user: String(user),
salt: [...salt],
user_sk: [...keyBytes],
remote_pk: [...serverPublicKey],
plaintext: String(message),
};
console.log("Boxed preflight: ", JSON.stringify(boxMessageArgs))
const boxed = box_message(JSON.stringify(boxMessageArgs));
console.log(JSON.parse(boxed));
console.log("End");
alert("Sent!");
location.reload();
}
run();
</script>
<script>
function toggleSection() {
const content = document.getElementById("expandableContent");
const header = document.querySelector(".expandable-header");
if (content.style.display === "block") {
content.style.display = "none";
header.innerHTML = "How to use ▼";
} else {
content.style.display = "block";
header.innerHTML = "How to use ▲";
}
}
</script>
</head>
<body>
<div class="form-container">
<form id="message-form">
<div class="input-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" />
</div>
<div class="input-group">
<label for="password">Password (optional)</label>
<input type="password" id="password" name="password" />
</div>
<div class="input-group">
<label for="message">Message</label>
<textarea id="message" name="message"></textarea>
</div>
<div class="input-group">
<button
type="submit"
style="
width: 100%;
padding: 10px;
background-color: #dbdbdb;
border: none;
border-radius: 4px;
cursor: pointer;
"
>
Submit
</button>
</div>
</form>
<div class="expandable-section">
<div class="expandable-header" onclick="toggleSection()">
How to use ▼
</div>
<div class="expandable-content" id="expandableContent">
<p>
Tell me who you are, and add an optional password. If I do not
otherwise have your contact information, please tell me the best way
to reach you back.
</p>
</div>
</div>
</div>
<nav class="directory">
<dt><a href="/">back to home</a></dt>
</nav>
</body>
</html>

55
routes/root/index.html Executable file
View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Zach's page</title>
<style>
body {
font-family: system-ui, sans-serif;
background-color: Cornsilk;
}
header h2 {
font-weight: normal;
font-family: "Gill Sans", sans-serif;
text-align: center;
}
body {
margin: 0;
padding: 0;
}
nav.directory {
text-align: center;
padding: 1rem 0;
}
nav.directory dt {
margin: 1.2rem 0;
font-size: 1.1rem;
}
nav.directory dt a {
text-decoration: none;
color: #333;
padding: 0.5rem 1rem;
display: inline-block;
}
</style>
</head>
<body>
<header>
<h2>Zachery Aaron Shores-Chmielewski</h2>
</header>
<nav class="directory">
<nav>
<dl>
<dt><a href="./who">Who</a></dt>
<!-- <dt><a href="#">Writing</a></dt> -->
<dt><a href="./contact">Send me a message</a></dt>
</dl>
</nav>
</nav>
</body>
</html>

51
routes/who/index.html Executable file
View file

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Zach's page</title>
<style>
body {
font-family: system-ui, sans-serif;
background-color: Cornsilk;
}
header h2 {
font-weight: normal;
font-family: "Gill Sans", sans-serif;
text-align: center;
}
body {
margin: 0;
padding: 0;
text-align: center;
}
nav.directory {
text-align: center;
padding: 1rem 0;
}
nav.directory dt {
margin: 1.2rem 0;
font-size: 1.1rem;
}
nav.directory dt a {
text-decoration: none;
color: #333;
padding: 0.5rem 1rem;
display: inline-block;
}
</style>
</head>
<body>
<div>
<p>No one in particular :)</p>
<p>I'll write more later...</p>
</div>
<nav class="directory">
<dt><a href="/">back to home</a></dt>
</nav>
</body>
</html>