added proper email function, actix endpoints etc
Diff
Cargo.lock | 307 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Cargo.toml | 7 ++++---
src/email.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/endpoints.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/main.rs | 46 +++++++++++++++++++---------------------------
src/verification.rs | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
src/whitelist.rs | 23 +++++++++++++++++++++++
7 files changed, 587 insertions(+), 92 deletions(-)
@@ -253,6 +253,131 @@
checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
[[package]]
name = "async-channel"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
dependencies = [
"concurrent-queue",
"event-listener",
"futures-core",
]
[[package]]
name = "async-executor"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb"
dependencies = [
"async-lock",
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"slab",
]
[[package]]
name = "async-global-executor"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776"
dependencies = [
"async-channel",
"async-executor",
"async-io",
"async-lock",
"blocking",
"futures-lite",
"once_cell",
]
[[package]]
name = "async-io"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
dependencies = [
"async-lock",
"autocfg 1.1.0",
"cfg-if",
"concurrent-queue",
"futures-lite",
"log",
"parking",
"polling",
"rustix",
"slab",
"socket2",
"waker-fn",
]
[[package]]
name = "async-lock"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7"
dependencies = [
"event-listener",
]
[[package]]
name = "async-process"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9"
dependencies = [
"async-io",
"async-lock",
"autocfg 1.1.0",
"blocking",
"cfg-if",
"event-listener",
"futures-lite",
"rustix",
"signal-hook",
"windows-sys 0.48.0",
]
[[package]]
name = "async-std"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
dependencies = [
"async-channel",
"async-global-executor",
"async-io",
"async-lock",
"crossbeam-utils",
"futures-channel",
"futures-core",
"futures-io",
"futures-lite",
"gloo-timers",
"kv-log-macro",
"log",
"memchr",
"once_cell",
"pin-project-lite",
"pin-utils",
"slab",
"wasm-bindgen-futures",
]
[[package]]
name = "async-task"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae"
[[package]]
name = "atomic-waker"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -305,6 +430,21 @@
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "blocking"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65"
dependencies = [
"async-channel",
"async-lock",
"async-task",
"atomic-waker",
"fastrand",
"futures-lite",
"log",
]
[[package]]
@@ -402,6 +542,15 @@
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "concurrent-queue"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
dependencies = [
"crossbeam-utils",
]
[[package]]
@@ -451,6 +600,15 @@
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
dependencies = [
"cfg-if",
]
@@ -463,6 +621,16 @@
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "ctor"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [
"quote",
"syn 1.0.109",
]
[[package]]
@@ -656,6 +824,12 @@
"cc",
"libc",
]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "fast_chemail"
@@ -720,6 +894,15 @@
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "futures-channel"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
@@ -732,6 +915,21 @@
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
[[package]]
name = "futures-lite"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"memchr",
"parking",
"pin-project-lite",
"waker-fn",
]
[[package]]
name = "futures-sink"
@@ -779,6 +977,18 @@
"cfg-if",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "gloo-timers"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
dependencies = [
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
]
[[package]]
@@ -941,6 +1151,15 @@
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kv-log-macro"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
dependencies = [
"log",
]
[[package]]
@@ -1058,6 +1277,7 @@
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
"value-bag",
]
[[package]]
@@ -1072,11 +1292,14 @@
dependencies = [
"actix-rt",
"actix-web",
"async-process",
"async-std",
"base64 0.21.0",
"chrono",
"lettre 0.10.4",
"lettre_email",
"openssl",
"rand 0.8.5",
"serde",
"serde_qs",
]
@@ -1226,6 +1449,12 @@
"pkg-config",
"vcpkg",
]
[[package]]
name = "parking"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
[[package]]
name = "parking_lot"
@@ -1279,6 +1508,22 @@
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "polling"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
dependencies = [
"autocfg 1.1.0",
"bitflags",
"cfg-if",
"concurrent-queue",
"libc",
"log",
"pin-project-lite",
"windows-sys 0.48.0",
]
[[package]]
name = "ppv-lite86"
@@ -1593,6 +1838,20 @@
version = "1.0.162"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.162"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
]
[[package]]
name = "serde_json"
@@ -1637,6 +1896,16 @@
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "signal-hook"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
@@ -1893,6 +2162,16 @@
checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
dependencies = [
"rand 0.6.5",
]
[[package]]
name = "value-bag"
version = "1.0.0-alpha.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55"
dependencies = [
"ctor",
"version_check 0.9.4",
]
[[package]]
@@ -1912,6 +2191,12 @@
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "waker-fn"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
[[package]]
name = "wasi"
@@ -1948,6 +2233,18 @@
"quote",
"syn 1.0.109",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
@@ -1978,6 +2275,16 @@
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "web-sys"
version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
@@ -1,17 +1,18 @@
[package]
name = "mc-mailer"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-rt = "2.8.0"
actix-web = "4.3.1"
async-process = "1.7.0"
async-std = "1.12.0"
base64 = "0.21.0"
chrono = "0.4.24"
lettre = "0.10.4"
lettre_email = "0.9.4"
openssl = "0.10.52"
serde = "1.0.162"
rand = "0.8.5"
serde = { version = "1.0.162", features = ["derive"] }
serde_qs = "0.12.0"
@@ -1,0 +1,83 @@
use actix_web::Responder;
use lettre::message::Mailbox;
use lettre::*;
use lettre::address::Address;
use lettre::transport::smtp::authentication::Credentials;
use lettre_email::EmailBuilder;
use crate::verification::*;
use crate::secrets::*;
pub async fn send_verification_email(request: VerificationRequest) -> Result<(), String> {
let creds = Credentials::new(
format!("{}@{}", EMAIL_USERNAME, EMAIL_DOMAIN),
EMAIL_PASSWORD.to_string()
);
let mailer = SmtpTransport::starttls_relay("mail.cock.li")
.unwrap()
.credentials(creds)
.build();
let email = Message::builder()
.from(
Mailbox::new(
Some(VERIFY_EMAIL_NICKNAME.to_string()),
Address::new(EMAIL_USERNAME.to_string(), EMAIL_DOMAIN.to_string()).unwrap()
)
)
.to(
Mailbox::new(
Some(request.minecraft_username.clone()),
Address::new(request.email.clone(), "st-andrews.ac.uk").unwrap()
)
)
.subject(VERIFY_EMAIL_SUBJECT)
.body(
VERIFY_EMAIL_BODY_1.to_string() + &request.as_code() + VERIFY_EMAIL_BODY_2
)
.unwrap();
println!("Sending email...");
match mailer.send(&email) {
Ok(_) => Ok(()),
Err(e) => Err(format!("Failed to send email: {}", e))
}
}
pub async fn send_written_reason_email(request: WrittenReasonRequest) -> Result<(), String> {
let creds = Credentials::new(
format!("{}@{}", EMAIL_USERNAME, EMAIL_DOMAIN),
EMAIL_PASSWORD.to_string()
);
let mailer = SmtpTransport::starttls_relay("mail.cock.li")
.unwrap()
.credentials(creds)
.build();
let email = Message::builder()
.from(
Mailbox::new(
Some(VERIFY_EMAIL_NICKNAME.to_string()),
Address::new(EMAIL_USERNAME.to_string(), EMAIL_DOMAIN.to_string()).unwrap()
)
)
.to(
Mailbox::new(
Some(request.minecraft_username.clone()),
Address::new("walchuk2018", "icloud.com").unwrap()
)
)
.subject("Request from ".to_string() + &request.minecraft_username)
.body(
format!("{:?}", request)
)
.unwrap();
println!("Sending email...");
match mailer.send(&email) {
Ok(_) => Ok(()),
Err(e) => Err(format!("Failed to send email: {}", e))
}
}
@@ -1,0 +1,56 @@
use chrono::Utc;
use crate::secrets::*;
use crate::verification::*;
use crate::email::*;
use actix_web::{web, Responder, HttpResponse};
pub async fn index() -> impl Responder {
let request_proto = VerificationRequestProto {
email: String::from("jpw24"),
minecraft_username: String::from("jacobroly")
};
let request = request_proto.hydrate();
let response = HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(
HTML_ON_EMAIL_SENT_1.to_string() + &request.minecraft_username + HTML_ON_EMAIL_SENT_2 + &request.email + HTML_ON_EMAIL_SENT_3
);
println!("{}", request.as_code());
return response;
}
pub async fn send_sta(form: web::Form<VerificationRequestProto>) -> impl Responder {
let request = form.into_inner().hydrate();
let response = HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(
HTML_ON_EMAIL_SENT_1.to_string() + &request.minecraft_username + HTML_ON_EMAIL_SENT_2 + &request.email + HTML_ON_EMAIL_SENT_3
);
actix_rt::spawn(send_verification_email(request));
return response;
}
pub async fn send_written(form: web::Form<WrittenReasonRequest>) -> impl Responder {
let response = HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(HTML_ON_WRITTEN_REQUEST_SENT.to_string());
actix_rt::spawn(send_written_reason_email(form.into_inner()));
return response;
}
pub async fn verify(path: web::Path<String>) -> impl Responder {
let code = path.into_inner();
let receipt = VerificationReceipt::from_code(code);
if (receipt.valid) {
return HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(HTML_ON_EMAIL_VERIFIED_1.to_string() + &receipt.minecraft_username + HTML_ON_EMAIL_VERIFIED_2);
} else {
return HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(HTML_ON_EMAIL_VERIFICATION_FAILED.to_string());
}
}
@@ -1,30 +1,20 @@
use chrono::Utc;
use lettre_email::EmailBuilder;
use secrets::secrets::EMAIL_USERNAME;
use crate::verification::verification::*;
use crate::secrets::secrets::SPECIAL_SALT_CODE;
mod endpoints;
mod secrets;
mod verification;
mod email;
pub mod verification;
pub mod secrets;
use actix_web::{web, App, HttpServer};
async fn send_verification_email(verificationRequest: VerificationRequest, ) -> impl Responder {
let email = EmailBuilder::new()
.to(format("{}@st-andrews.ac.uk", verificationRequest.email))
.from(EMAIL_USERNAME)
.subject("Minecraft Verification")
.text(format!("Here's your whitelist verification link: https://mc.7800.io/verify/{}", verificationRequest.as_code()))
.build();
}
fn main() {
let verification_request = VerificationRequest {
minecraft_username: String::from("jacobroly"),
date: Utc::now(),
seed: 45343,
};
println!("Generated verification request: {:?}", verification_request);
let verification_code = verification_request.as_code();
println!("Generated verification code: {}", verification_code);
let verification_receipt = VerificationReceipt::from_code(verification_code);
println!("Generated verification receipt: {:?}", verification_receipt);
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/", web::get().to(endpoints::index))
.route("/send-sta", web::post().to(endpoints::send_sta))
.route("/send-written", web::post().to(endpoints::send_written))
.route("/verify/{code}", web::get().to(endpoints::verify))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
@@ -1,66 +1,101 @@
pub mod verification {
use openssl::hash::*;
use base64::engine::Engine as _;
use base64::engine::general_purpose::URL_SAFE_NO_PAD as BASE64;
use chrono::prelude::*;
use crate::SPECIAL_SALT_CODE;
#[derive(Debug)]
pub struct VerificationRequest {
pub(crate) minecraft_username: String,
pub(crate) date: DateTime<Utc>,
pub(crate) seed: u32,
}
#[derive(Debug)]
pub struct VerificationReceipt {
valid: bool,
minecraft_username: String,
}
pub trait VerificationCodeGenerator {
fn as_code(&self) -> String;
}
pub trait VerificationCodeValidator {
fn from_code(code: String) -> VerificationReceipt;
use openssl::{hash::*};
use rand::{thread_rng, Rng};
use base64::engine::Engine as _;
use base64::engine::general_purpose::URL_SAFE_NO_PAD as BASE64;
use chrono::prelude::*;
use serde::{Serialize, Deserialize};
use crate::secrets::SPECIAL_SALT_CODE;
#[derive(Debug, Serialize, Deserialize)]
pub struct VerificationRequestProto {
pub(crate) email: String,
pub(crate) minecraft_username: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WrittenReasonRequest {
pub(crate) email: String,
pub(crate) minecraft_username: String,
pub(crate) reason: String,
}
#[derive(Debug)]
pub struct VerificationRequest {
pub(crate) email: String,
pub(crate) minecraft_username: String,
pub(crate) date: DateTime<Utc>,
pub(crate) seed: u32,
}
#[derive(Debug)]
pub struct VerificationReceipt {
pub(crate) valid: bool,
pub(crate) minecraft_username: String,
}
pub trait VerificationCodeGenerator {
fn as_code(&self) -> String;
}
pub trait VerificationCodeValidator {
fn from_code(code: String) -> VerificationReceipt;
}
pub trait VerificationCodeHydrator {
fn hydrate(&self) -> VerificationRequest;
}
impl VerificationCodeGenerator for VerificationRequest {
fn as_code(&self) -> String {
println!("generating verification code from request: {:?}", self.clone());
return format!(
"{}{}{}",
BASE64.encode(
&self.seed.to_be_bytes()
),
BASE64.encode(
hash(MessageDigest::sha256(),
format!(
"{}{}{}{}",
self.seed,
self.date.format("%Y%m%d").to_string(),
SPECIAL_SALT_CODE,
self.minecraft_username
).as_bytes()).unwrap().as_ref()
),
BASE64.encode(
&self.minecraft_username.as_bytes()
)
);
}
}
impl VerificationCodeGenerator for VerificationRequest {
fn as_code(&self) -> String {
return format!(
"{}{}{}",
BASE64.encode(
&self.seed.to_be_bytes()
),
BASE64.encode(
hash(MessageDigest::sha256(),
format!(
"{}{}{}{}",
self.seed,
self.date.timestamp(),
SPECIAL_SALT_CODE,
self.minecraft_username
).as_bytes()).unwrap().as_ref()
),
BASE64.encode(
&self.minecraft_username.as_bytes()
)
);
}
impl VerificationCodeValidator for VerificationReceipt {
fn from_code(code: String) -> VerificationReceipt {
println!("code: {}", code);
println!("reconstructed username: {}", String::from_utf8(BASE64.decode(&code[49..]).unwrap()).unwrap());
println!("reconstructed seed: {}", u32::from_be_bytes(BASE64.decode(&code[0..6]).unwrap().try_into().unwrap()));
let username = String::from_utf8(BASE64.decode(&code[49..]).unwrap()).unwrap();
return VerificationReceipt {
minecraft_username: username.clone(),
valid: code == VerificationRequest {
email: String::from(""),
minecraft_username: username,
date: Utc::now(),
seed: u32::from_be_bytes(BASE64.decode(&code[0..6]).unwrap().try_into().unwrap()),
}.as_code()
};
}
impl VerificationCodeValidator for VerificationReceipt {
fn from_code(code: String) -> VerificationReceipt {
let username = String::from_utf8(BASE64.decode(&code[49..]).unwrap()).unwrap();
return VerificationReceipt {
minecraft_username: username.clone(),
valid: code == VerificationRequest {
minecraft_username: username,
date: Utc::now(),
seed: u32::from_be_bytes(BASE64.decode(&code[0..6]).unwrap().try_into().unwrap()),
}.as_code()
};
}
}
impl VerificationCodeHydrator for VerificationRequestProto {
fn hydrate(&self) -> VerificationRequest {
return VerificationRequest {
email: self.email.clone(),
minecraft_username: self.minecraft_username.clone(),
date: Utc::now(),
seed: rand::thread_rng().gen::<u32>(),
};
}
}
@@ -1,0 +1,23 @@
use std::io::Error;
use std::process::Stdio;
use async_process::Command;
use async_std::prelude::*;
use actix_rt::System;
use crate::secrets::WHITELIST_SCRIPT_PATH;
async fn add_to_whitelist(args: &str) -> Result<String, Error> {
let mut child = Command::new("sh")
.arg(WHITELIST_SCRIPT_PATH)
.arg(args)
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()?;
let output = child.output().await?;
let success = output.status.success();
let output_text = String::from_utf8_lossy(&output.stdout).to_string();
let error_text = String::from_utf8_lossy(&output.stderr).to_string();
Ok(format!("=== STDOUT ===\n{}\n\n== STDERR ==\n{}", output_text, error_text))
}