Implement proper jp authentication (gree)

This commit is contained in:
Ethan O'Brien
2024-04-08 11:55:04 -05:00
parent f33e211dab
commit b5138bfaaa
13 changed files with 381 additions and 42 deletions

View File

@ -5,8 +5,8 @@ use crate::router::global;
use actix_web::{HttpResponse, HttpRequest};
use crate::router::userdata;
pub fn home(req: HttpRequest, _body: String) -> HttpResponse {
let key = global::get_login(req.headers());
pub fn home(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let user = userdata::get_acc(&key);
let id = user["user"]["favorite_master_card_id"].as_i64().unwrap() / 10000;

View File

@ -4,6 +4,7 @@ use actix_web::{
HttpResponse,
http::header::{HeaderValue, HeaderMap}
};
use crate::router::gree;
use std::time::{SystemTime, UNIX_EPOCH};
use base64::{Engine as _, engine::general_purpose};
@ -15,20 +16,23 @@ pub const ASSET_VERSION_JP: &str = "4c921d2443335e574a82e04ec9ea243c";
pub const ASSET_HASH_ANDROID_JP: &str = "67f8f261c16b3cca63e520a25aad6c1c";
pub const ASSET_HASH_IOS_JP: &str = "b8975be8300013a168d061d3fdcd4a16";
pub fn get_login(headers: &HeaderMap) -> String {
pub fn get_login(headers: &HeaderMap, body: &str) -> String {
let blank_header = HeaderValue::from_static("");
let login = headers.get("a6573cbe").unwrap_or(&blank_header).to_str().unwrap_or("");
let decoded = general_purpose::STANDARD.decode(login).unwrap_or(vec![]);
let a6573cbe = String::from_utf8_lossy(&decoded);
if a6573cbe.contains("-") {
let parts: Vec<&str> = a6573cbe.split('-').collect();
let token = parts[1..parts.len() - 1].join("-");
return token.to_string();
}
//only jp should error?
let key = headers.get("aoharu-user-id").unwrap_or(&blank_header).to_str().unwrap_or("");
key.to_string()
match String::from_utf8(decoded) {
Ok(a6573cbe) => {
let parts: Vec<&str> = a6573cbe.split('-').collect();
let token = parts[1..parts.len() - 1].join("-");
return token.to_string();
},
Err(_) => {
let rv = gree::get_uuid(headers, body);
assert!(rv != String::new());
return rv;
},
};
}
pub fn timestamp() -> u64 {

View File

@ -1,5 +1,5 @@
use crate::router::global;
use actix_web::{HttpResponse, HttpRequest, http::header::HeaderValue, http::header::ContentType};
use actix_web::{HttpResponse, HttpRequest, http::header::HeaderValue, http::header::ContentType, http::header::HeaderMap};
use base64::{Engine as _, engine::general_purpose};
use std::collections::HashMap;
use sha1::Sha1;
@ -7,16 +7,180 @@ use substring::Substring;
use json::object;
use hmac::{Hmac, Mac};
use crate::router::userdata;
use crate::encryption;
pub fn initialize(req: HttpRequest, _body: String) -> HttpResponse {
//println!("{}", body);
use rusqlite::{Connection, params, ToSql};
use std::sync::{Mutex, MutexGuard};
use lazy_static::lazy_static;
use uuid::Uuid;
use openssl::pkey::PKey;
use openssl::rsa::Rsa;
use openssl::hash::MessageDigest;
use openssl::sign::Verifier;
lazy_static! {
pub static ref ENGINE: Mutex<Option<Connection>> = Mutex::new(None);
}
fn init(engine: &mut MutexGuard<'_, Option<Connection>>) {
let conn = Connection::open("gree.db").unwrap();
conn.execute("PRAGMA foreign_keys = ON;", ()).unwrap();
engine.replace(conn);
}
fn lock_and_exec(command: &str, args: &[&dyn ToSql]) {
loop {
match ENGINE.lock() {
Ok(mut result) => {
if result.is_none() {
init(&mut result);
}
let conn = result.as_ref().unwrap();
conn.execute(command, args).unwrap();
return;
}
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(15));
}
}
}
}
fn lock_and_select(command: &str) -> Result<String, rusqlite::Error> {
loop {
match ENGINE.lock() {
Ok(mut result) => {
if result.is_none() {
init(&mut result);
}
let conn = result.as_ref().unwrap();
let mut stmt = conn.prepare(command).unwrap();
return stmt.query_row([], |row| row.get(0));
}
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(15));
}
}
}
}
fn create_store(test_cmd: &str, table: &str, init_cmd: &str, init_args: &[&dyn ToSql]) {
loop {
match ENGINE.lock() {
Ok(mut result) => {
if result.is_none() {
init(&mut result);
}
let conn = result.as_ref().unwrap();
match conn.prepare(test_cmd) {
Ok(_) => {}
Err(_) => {
conn.execute(
table,
(),
).unwrap();
conn.execute(
init_cmd,
init_args
).unwrap();
}
}
return;
}
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(15));
}
}
}
}
fn get_new_uuid() -> String {
create_store("SELECT jsondata FROM uuids", "CREATE TABLE uuids (
jsondata TEXT NOT NULL
)", "INSERT INTO uuids (jsondata) VALUES (?1)", params!("[]"));
let id = format!("{}", Uuid::new_v4());
let mut existing_ids = json::parse(&lock_and_select("SELECT jsondata FROM uuids").unwrap()).unwrap();
if existing_ids.contains(id.clone()) {
return get_new_uuid();
}
existing_ids.push(id.clone()).unwrap();
lock_and_exec(
"UPDATE uuids SET jsondata=?1",
params!(json::stringify(existing_ids))
);
id
}
fn create_acc(cert: &str) -> String {
let uuid = get_new_uuid();
let user = userdata::get_acc(&uuid);
let user_id = user["user"]["id"].to_string();
lock_and_exec(
&format!("CREATE TABLE _{}_ (
cert TEXT NOT NULL,
uuid TEXT NOT NULL
)", user_id),
params!(),
);
lock_and_exec(
&format!("INSERT INTO _{}_ (cert, uuid) VALUES (?1, ?2)", user_id),
params!(cert, uuid)
);
uuid
}
fn verify_signature(signature: &[u8], message: &[u8], public_key: &[u8]) -> bool {
let rsa_public_key = match Rsa::public_key_from_pem(public_key) {
Ok(key) => key,
Err(_) => return false,
};
let pkey = match PKey::from_rsa(rsa_public_key) {
Ok(pkey) => pkey,
Err(_) => return false,
};
let mut verifier = Verifier::new(MessageDigest::sha1(), &pkey).unwrap();
verifier.update(message).unwrap();
match verifier.verify(signature) {
Ok(_) => true,
Err(_) => false,
}
}
pub fn get_uuid(headers: &HeaderMap, body: &str) -> String {
let body = encryption::decrypt_packet(&body).unwrap();
let blank_header = HeaderValue::from_static("");
let login = headers.get("a6573cbe").unwrap_or(&blank_header).to_str().unwrap_or("");
let uid = headers.get("aoharu-user-id").unwrap_or(&blank_header).to_str().unwrap_or("");
let version = headers.get("aoharu-client-version").unwrap_or(&blank_header).to_str().unwrap_or("");
let timestamp = headers.get("aoharu-timestamp").unwrap_or(&blank_header).to_str().unwrap_or("");
if uid == "" || login == "" || version == "" || timestamp == "" {
return String::new();
}
let cert = lock_and_select(&format!("SELECT cert FROM _{}_", uid)).unwrap();
let data = format!("{}{}{}{}{}", uid, "sk1bdzb310n0s9tl", version, timestamp, body);
let encoded = general_purpose::STANDARD.encode(data.as_bytes());
let decoded = general_purpose::STANDARD.decode(login).unwrap_or(vec![]);
if verify_signature(&decoded, &encoded.as_bytes(), &cert.as_bytes()) {
return lock_and_select(&format!("SELECT uuid FROM _{}_", uid)).unwrap();
} else {
return String::new();
}
}
pub fn initialize(req: HttpRequest, body: String) -> HttpResponse {
let body = json::parse(&body).unwrap();
let token = create_acc(&body["token"].to_string());
let app_id = "232610769078541";
let resp = object!{
result: "OK",
app_id: app_id,
uuid: format!("{}{:x}", app_id, md5::compute((global::timestamp() * 1000).to_string()))
uuid: token
};
println!("{}", resp["uuid"].to_string());
HttpResponse::Ok()
.insert_header(ContentType::json())
@ -29,7 +193,6 @@ pub fn initialize(req: HttpRequest, _body: String) -> HttpResponse {
}
pub fn authorize(req: HttpRequest, _body: String) -> HttpResponse {
let resp = object!{
result: "OK"
};
@ -44,7 +207,6 @@ pub fn authorize(req: HttpRequest, _body: String) -> HttpResponse {
}
pub fn moderate_keyword(req: HttpRequest) -> HttpResponse {
let resp = object!{
result: "OK",
entry: {
@ -63,7 +225,6 @@ pub fn moderate_keyword(req: HttpRequest) -> HttpResponse {
}
pub fn uid(req: HttpRequest) -> HttpResponse {
let app_id = "232610769078541";
let mut uid = String::new();
let blank_header = HeaderValue::from_static("");
@ -75,10 +236,10 @@ pub fn uid(req: HttpRequest) -> HttpResponse {
uid = uid_str.to_string();
}
}
//println!("{}", auth_header);
//println!("{}", uid);
let key = uid.substring(app_id.len(), uid.len());
let user = userdata::get_acc(&key);
let user = userdata::get_acc(&uid);
//println!("{}", user["user"]["id"].to_string());
let resp = object!{
result: "OK",

View File

@ -6,8 +6,8 @@ use actix_web::{HttpResponse, HttpRequest};
use crate::router::userdata;
pub fn preset(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let mut user = userdata::get_acc_home(&key);
for (_i, data) in user["home"]["preset_setting"].members_mut().enumerate() {
@ -26,7 +26,7 @@ pub fn preset(req: HttpRequest, body: String) -> HttpResponse {
}
pub fn preset_get(req: HttpRequest) -> HttpResponse {
let key = global::get_login(req.headers());
let key = global::get_login(req.headers(), "");
let user = userdata::get_acc(&key);
let resp = object!{
@ -42,7 +42,10 @@ pub fn preset_get(req: HttpRequest) -> HttpResponse {
}
pub fn home(req: HttpRequest) -> HttpResponse {
let key = global::get_login(req.headers());
for (name, value) in req.headers().iter() {
println!("{}: {}", name, value.to_str().unwrap());
}
let key = global::get_login(req.headers(), "");
let user = userdata::get_acc_home(&key);
let resp = object!{

View File

@ -83,8 +83,8 @@ pub fn update_live_data(user: &mut JsonValue, data: &JsonValue) -> JsonValue {
}
pub fn end(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let user2 = userdata::get_acc_home(&key);
let mut user = userdata::get_acc(&key);

View File

@ -6,9 +6,9 @@ use actix_web::{HttpResponse, HttpRequest};
use crate::router::userdata;
//First time login handler
pub fn dummy(req: HttpRequest, _body: String) -> HttpResponse {
pub fn dummy(req: HttpRequest, body: String) -> HttpResponse {
//let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let key = global::get_login(req.headers(), &body);
let mut user = userdata::get_acc(&key);
user["user"]["last_login_time"] = global::timestamp().into();
@ -25,9 +25,9 @@ pub fn dummy(req: HttpRequest, _body: String) -> HttpResponse {
global::send(resp)
}
pub fn bonus(req: HttpRequest, _body: String) -> HttpResponse {
pub fn bonus(req: HttpRequest, body: String) -> HttpResponse {
//let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let key = global::get_login(req.headers(), &body);
let user = userdata::get_acc_home(&key);
let resp = object!{

View File

@ -100,9 +100,9 @@ pub fn lottery(_req: HttpRequest) -> HttpResponse {
}
pub fn lottery_post(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
println!("lottery: {}", body);
let key = global::get_login(req.headers());
let mut user = userdata::get_acc(&key);
let user2 = userdata::get_acc(&key);

View File

@ -2,7 +2,7 @@ use json;
use json::object;
use crate::router::global;
use actix_web::{HttpResponse, HttpRequest};
use crate::router::userdata;
//use crate::router::userdata;
pub fn mission(_req: HttpRequest) -> HttpResponse {
//let key = global::get_login(req.headers());

View File

@ -40,12 +40,13 @@ pub fn asset_hash(req: HttpRequest, body: String) -> HttpResponse {
}
pub fn start(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
if body["asset_version"].to_string() != global::ASSET_VERSION && body["asset_version"].to_string() != global::ASSET_VERSION_JP {
println!("Warning! Asset version is not what was expected. (Did the app update?)");
}
let key = global::get_login(req.headers());
let mut user = userdata::get_acc(&key);
//println!("{} - {}", key, user["user"]["id"].to_string());
user["user"]["last_login_time"] = global::timestamp().into();
user["stamina"]["last_updated_time"] = global::timestamp().into();

View File

@ -6,8 +6,8 @@ use actix_web::{HttpResponse, HttpRequest};
use crate::router::userdata;
pub fn tutorial(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let mut user = userdata::get_acc(&key);
user["tutorial_step"] = body["step"].clone();

View File

@ -6,9 +6,8 @@ use actix_web::{HttpResponse, HttpRequest};
use crate::router::userdata;
pub fn deck(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let mut user = userdata::get_acc(&key);
for (i, data) in user["deck_list"].members().enumerate() {
@ -35,8 +34,7 @@ pub fn deck(req: HttpRequest, body: String) -> HttpResponse {
}
pub fn user(req: HttpRequest) -> HttpResponse {
let key = global::get_login(req.headers());
let key = global::get_login(req.headers(), "");
let user = userdata::get_acc(&key);
let resp = object!{
@ -48,9 +46,9 @@ pub fn user(req: HttpRequest) -> HttpResponse {
}
pub fn user_post(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let mut user = userdata::get_acc(&key);
let user_2 = userdata::get_acc_home(&key);
@ -125,8 +123,8 @@ pub fn get_migration_code(_req: HttpRequest, body: String) -> HttpResponse {
}
pub fn register_password(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let user = userdata::get_acc(&key);
let code = uid_to_code(user["user"]["id"].to_string());
@ -212,9 +210,9 @@ pub fn migration(_req: HttpRequest, body: String) -> HttpResponse {
pub fn initialize(req: HttpRequest, body: String) -> HttpResponse {
let key = global::get_login(req.headers(), &body);
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let key = global::get_login(req.headers());
let mut user = userdata::get_acc(&key);
let mut user2 = userdata::get_acc_home(&key);
let ur = user["card_list"][user["card_list"].len() - 1]["master_card_id"].clone();