diff --git a/src/database/gree.rs b/src/database/gree.rs index 6fc400c..afda622 100644 --- a/src/database/gree.rs +++ b/src/database/gree.rs @@ -60,13 +60,28 @@ fn vacuum_database() { DATABASE.lock_and_exec("VACUUM", params!()); } +pub fn get_user_cert(uuid: &str) -> Option<(i64, String)> { + let user_id = DATABASE.lock_and_select("SELECT user_id FROM users WHERE uuid=?1;", params!(uuid)).ok()?.parse::().ok()?; + let cert = DATABASE.lock_and_select("SELECT cert FROM users WHERE uuid=?1;", params!(uuid)).ok()?; + + Some((user_id, cert)) +} + pub fn is_registered(uuid: &str) -> bool { - match DATABASE.lock_and_select("SELECT cert FROM users WHERE uuid=?1;", params!(uuid)) { - Ok(cert) => cert != "none", - Err(_) => false + match get_user_cert(uuid) { + Some((_, cert)) => pem::parse(&cert).is_ok(), + None => false } } +pub fn verify_fingerprint(uuid: &str, fingerprint: &str, cert: &str) -> bool { + let Ok(signature) = general_purpose::STANDARD.decode(fingerprint) else { + return false; + }; + + verify_signature(&signature, uuid.as_bytes(), cert) +} + fn verify_signature(signature: &[u8], message: &[u8], public_key: &str) -> bool { let Ok(pem) = pem::parse(public_key) else { return false; diff --git a/src/router/gree.rs b/src/router/gree.rs index 41f5482..ef3ab5f 100644 --- a/src/router/gree.rs +++ b/src/router/gree.rs @@ -16,6 +16,7 @@ use crate::database::gree::*; const APP_ID: &str = "232610769078541"; const SRC_APP_ID: &str = "100900301"; const HMAC_SECRET_HEX: &str = "6438663638653238346566646636306262616563326432323563306366643432"; +const ERROR_INVALID_SIGNATURE: i32 = 4; const ERROR_MIGRATED_DEVICE: i32 = 20; struct RequireGreeAuth; @@ -52,6 +53,8 @@ pub fn routes(cfg: &mut web::ServiceConfig) { .service( web::scope("/migration") .route("", web::post().to(migration)) + .route("/auth/initialize", web::post().to(initialize)) + .route("/user/token", web::post().to(migration_user_token)) .route("/code", web::get().to(migration_code)) .route("/code/verify", web::post().to(migration_verify)) .route("/password/register", web::post().to(migration_password_register)) @@ -234,6 +237,36 @@ async fn migration(req: HttpRequest, body: String) -> impl Responder { send(req, resp) } +async fn migration_user_token(req: HttpRequest, body: String) -> impl Responder { + let body = jzon::parse(&body).unwrap_or(object!{}); + let uuid = body["uuid"].to_string(); + + let resp = if let Some((user_id, cert)) = get_user_cert(&uuid) { + if verify_fingerprint(&uuid, &body["fingerprint"].to_string(), &cert) { + update_cert(user_id, &body["token"].to_string()); + object!{ + result: "OK" + } + } else { + println!("Rejecting device token update for {}: bad fingerprint", uuid); + object!{ + result: "NG", + code: ERROR_INVALID_SIGNATURE, + message: "Invalid fingerprint" + } + } + } else { + println!("Rejecting device token update for unregistered device {}", uuid); + object!{ + result: "NG", + code: ERROR_MIGRATED_DEVICE, + message: "Device is not registered" + } + }; + + send(req, resp) +} + async fn balance(req: HttpRequest) -> impl Responder { let uid = get_uid(&req);