mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Actually verify user credentials
This commit is contained in:
@@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[features]
|
||||
steam = ["steamworks"]
|
||||
robocraft = []
|
||||
robocraft = ["rc_core"]
|
||||
cardlife = []
|
||||
default = ["robocraft", "cardlife"]
|
||||
|
||||
@@ -18,3 +18,5 @@ uuid = { version = "1.12", features = [ "v4", "fast-rng" ] }
|
||||
steamworks = { version = "0.11", optional = true }
|
||||
hex = "0.4"
|
||||
jsonwebtoken = "9"
|
||||
clap.workspace = true
|
||||
rc_core = { version = "*", optional = true, path = "../rc_core" }
|
||||
|
||||
28
auth/src/common/cli.rs
Normal file
28
auth/src/common/cli.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
pub struct CliArgs {
|
||||
#[cfg(feature = "robocraft")]
|
||||
/// Robocraft user data root
|
||||
#[arg(long, default_value_t = {"../data/robocraft".to_string()})]
|
||||
pub data_robocraft: String,
|
||||
}
|
||||
|
||||
impl CliArgs {
|
||||
pub fn get() -> Self {
|
||||
Self::parse()
|
||||
}
|
||||
|
||||
pub fn preloaded(self) -> Config {
|
||||
Config {
|
||||
#[cfg(feature = "robocraft")]
|
||||
robocraft: crate::robocraft::RcConfig::from_args(&self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
#[cfg(feature = "robocraft")]
|
||||
pub robocraft: crate::robocraft::RcConfig,
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub(crate) mod steam_utils;
|
||||
pub(crate) mod cli;
|
||||
|
||||
@@ -13,8 +13,10 @@ fn index() -> &'static str {
|
||||
#[rocket::launch]
|
||||
fn rocket() -> _ {
|
||||
env_logger::init();
|
||||
let args = common::cli::CliArgs::get();
|
||||
#[allow(unused_mut)]
|
||||
let mut builder = rocket::build().mount("/", rocket::routes![index]);
|
||||
let mut builder = rocket::build().mount("/", rocket::routes![index])
|
||||
.manage(args.preloaded());
|
||||
|
||||
#[cfg(feature = "cardlife")]
|
||||
{builder = builder.attach(cardlife::stage());}
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
use rocket::{post, routes, serde::json::Json, http::Status};
|
||||
use rc_core::UserAuthenticator;
|
||||
use rocket::{post, routes, serde::json::Json, http::Status, State};
|
||||
|
||||
fn generate_token(user_auth: &libfj::robocraft::EmailUserAuthenticationPayload) -> String {
|
||||
let header = jsonwebtoken::Header {
|
||||
typ: Some("JWT".to_string()),
|
||||
alg: jsonwebtoken::Algorithm::HS256,
|
||||
..Default::default()
|
||||
};
|
||||
#[post("/authenticate/robocraft/game", data = "<body>")]
|
||||
pub fn email_password_auth(body: Json<libfj::robocraft::EmailUserAuthenticationPayload>, config: &State<crate::common::cli::Config>) -> Result<Json<libfj::robocraft::AuthenticationResponseInfo>, Status> {
|
||||
log::info!("Authenticating {} user {}", body.target, body.display_name);
|
||||
let payload = libfj::robocraft::TokenPayload {
|
||||
public_id: user_auth.display_name.to_owned(),
|
||||
display_name: user_auth.display_name.to_owned(),
|
||||
robocraft_name: user_auth.display_name.to_owned(),
|
||||
email_address: user_auth.email_address.to_owned(),
|
||||
public_id: body.display_name.clone(),
|
||||
display_name: body.display_name.clone(),
|
||||
robocraft_name: body.display_name.clone(),
|
||||
email_address: body.email_address.clone(),
|
||||
email_verified: true,
|
||||
flags: Vec::new(),
|
||||
};
|
||||
let secret = jsonwebtoken::EncodingKey::from_secret(user_auth.password.as_bytes()); // FIXME use an actually secret secret
|
||||
jsonwebtoken::encode(&header, &payload, &secret)
|
||||
.unwrap_or_else(|e| {
|
||||
log::error!("Failed to encode JWT: {}", e);
|
||||
libfj::robocraft::DEFAULT_TOKEN.to_owned()
|
||||
})
|
||||
}
|
||||
|
||||
#[post("/authenticate/robocraft/game", data = "<body>")]
|
||||
pub fn email_password_auth(body: Json<libfj::robocraft::EmailUserAuthenticationPayload>) -> Result<Json<libfj::robocraft::AuthenticationResponseInfo>, Status> {
|
||||
log::info!("Authenticating {} user {}", body.target, body.display_name);
|
||||
Ok(Json(libfj::robocraft::AuthenticationResponseInfo {
|
||||
token: generate_token(&body),
|
||||
refresh_token: "qwertyuiop".to_string(), // TODO
|
||||
refresh_token_expiry: "0".to_string(), // TODO (seems like this isn't actually considered by the client)
|
||||
}))
|
||||
let user_info = rc_core::persist::user::UserInfo {
|
||||
payload,
|
||||
extra: rc_core::persist::user::ExtraUserInfo::Standalone { password: body.password.clone() },
|
||||
};
|
||||
let response = config.robocraft.account_provider.login(user_info)
|
||||
.map_err(|e| {
|
||||
log::error!("Failed to authenticate {} user {}: {}", body.target, body.display_name, e);
|
||||
Status { code: 401 }
|
||||
})?;
|
||||
Ok(Json(response.response))
|
||||
}
|
||||
|
||||
pub fn stage() -> rocket::fairing::AdHoc {
|
||||
|
||||
@@ -7,5 +7,31 @@ pub fn stage() -> rocket::fairing::AdHoc {
|
||||
rocket.attach(email::stage())
|
||||
.attach(steam::stage())
|
||||
.attach(debug::stage())
|
||||
.register("/", rocket::catchers![unauthorized])
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct RcConfig {
|
||||
pub root: std::path::PathBuf,
|
||||
pub account_provider: rc_core::UserImpl,
|
||||
}
|
||||
|
||||
impl RcConfig {
|
||||
pub fn from_args(args: &crate::common::cli::CliArgs) -> Self {
|
||||
Self {
|
||||
account_provider: rc_core::UserImpl::load_for_auth(&args.data_robocraft).expect("Invalid Robocraft user data"),
|
||||
root: args.data_robocraft.clone().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use rocket::{catch, serde::json::Json};
|
||||
|
||||
#[catch(401)]
|
||||
fn unauthorized() -> Json<libfj::robocraft::ErrorInfo> {
|
||||
Json(libfj::robocraft::ErrorInfo {
|
||||
error_code: "204".to_owned(),
|
||||
error_message: "Invalid username, password, or SteamID".to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,37 +1,29 @@
|
||||
use rocket::{post, routes, serde::json::Json, http::Status};
|
||||
use rc_core::UserAuthenticator;
|
||||
use rocket::{http::Status, post, routes, serde::json::Json, State};
|
||||
|
||||
fn generate_token(user_auth: &libfj::robocraft::SteamAuthenticationPayload, steam_id: u64) -> String {
|
||||
let header = jsonwebtoken::Header {
|
||||
typ: Some("JWT".to_string()),
|
||||
alg: jsonwebtoken::Algorithm::HS256,
|
||||
..Default::default()
|
||||
};
|
||||
#[post("/authenticate/steam/game", data = "<body>")]
|
||||
pub fn steam_auth(body: Json<libfj::robocraft::SteamAuthenticationPayload>, config: &State<crate::common::cli::Config>) -> Result<Json<libfj::robocraft::AuthenticationResponseInfo>, Status> {
|
||||
let steam_id = crate::common::steam_utils::authenticate_steam_ticket(&body.steam_ticket)
|
||||
.map_err(|_| Status { code: 401 })?;
|
||||
log::info!("Authenticating {} steam user {}", body.target, steam_id);
|
||||
let payload = libfj::robocraft::TokenPayload {
|
||||
public_id: steam_id.to_string(),
|
||||
display_name: steam_id.to_string(),
|
||||
robocraft_name: steam_id.to_string(),
|
||||
email_address: format!("{}.rc.steam@ngni.us", steam_id),
|
||||
email_address: format!("{}.rc.steam@ngram.ca", steam_id),
|
||||
email_verified: true,
|
||||
flags: Vec::new(),
|
||||
};
|
||||
let secret = jsonwebtoken::EncodingKey::from_secret(user_auth.steam_ticket.as_ref()); // FIXME use an actually secret secret
|
||||
jsonwebtoken::encode(&header, &payload, &secret)
|
||||
.unwrap_or_else(|e| {
|
||||
log::error!("Failed to encode JWT: {}", e);
|
||||
libfj::robocraft::DEFAULT_TOKEN.to_owned()
|
||||
})
|
||||
}
|
||||
|
||||
#[post("/authenticate/steam/game", data = "<body>")]
|
||||
pub fn steam_auth(body: Json<libfj::robocraft::SteamAuthenticationPayload>) -> Result<Json<libfj::robocraft::AuthenticationResponseInfo>, Status> {
|
||||
let steam_id = crate::common::steam_utils::authenticate_steam_ticket(&body.steam_ticket)
|
||||
.map_err(|_| Status { code: 401 })?;
|
||||
log::info!("Authenticating {} steam user {}", body.target, steam_id);
|
||||
Ok(Json(libfj::robocraft::AuthenticationResponseInfo {
|
||||
token: generate_token(&body, steam_id),
|
||||
refresh_token: "qwertyuiop".to_string(), // TODO
|
||||
refresh_token_expiry: "0".to_string(), // TODO (seems like this isn't actually considered by the client)
|
||||
}))
|
||||
let user_info = rc_core::persist::user::UserInfo {
|
||||
payload,
|
||||
extra: rc_core::persist::user::ExtraUserInfo::Steam { id: steam_id },
|
||||
};
|
||||
let response = config.robocraft.account_provider.login(user_info)
|
||||
.map_err(|e| {
|
||||
log::error!("Failed to authenticate {} steam user {}: {}", body.target, steam_id, e);
|
||||
Status { code: 401 }
|
||||
})?;
|
||||
Ok(Json(response.response))
|
||||
}
|
||||
|
||||
pub fn stage() -> rocket::fairing::AdHoc {
|
||||
|
||||
Reference in New Issue
Block a user