mirror of
https://git.ethanthesleepy.one/ethanaobrien/ew
synced 2026-07-12 08:42:20 +08:00
332 lines
10 KiB
Rust
332 lines
10 KiB
Rust
use actix_web::{HttpRequest, http::header::HeaderValue, web, Responder, HttpMessage};
|
|
use base64::{Engine as _, engine::general_purpose};
|
|
use std::collections::HashMap;
|
|
use actix_web::dev::{ServiceResponse, Service};
|
|
use actix_web::http::header;
|
|
use actix_web::http::header::HeaderName;
|
|
use sha1::Sha1;
|
|
use jzon::{object, JsonValue};
|
|
use hmac::{Hmac, Mac, KeyInit};
|
|
|
|
use crate::router::global;
|
|
use crate::router::userdata;
|
|
|
|
use crate::database::gree::*;
|
|
|
|
const APP_ID: &str = "232610769078541";
|
|
const SRC_APP_ID: &str = "100900301";
|
|
const HMAC_SECRET_HEX: &str = "6438663638653238346566646636306262616563326432323563306366643432";
|
|
|
|
struct RequireGreeAuth;
|
|
|
|
pub fn routes(cfg: &mut web::ServiceConfig) {
|
|
cfg.service(
|
|
web::scope("")
|
|
.wrap_fn(|req, srv| {
|
|
let fut = srv.call(req);
|
|
async move {
|
|
let mut res = fut.await?;
|
|
apply_headers(&mut res);
|
|
Ok(res)
|
|
}
|
|
})
|
|
.service(
|
|
web::scope("/auth")
|
|
.route("/x_uid", web::get().to(uid))
|
|
.route("/initialize", web::post().to(initialize))
|
|
.route("/authorize", web::post().to(authorize))
|
|
)
|
|
.service(
|
|
web::scope("/payment")
|
|
.route("/productlist", web::get().to(payment))
|
|
.route("/balance", web::get().to(balance))
|
|
.route("/subscription/productlist", web::get().to(payment))
|
|
.route("/ticket/status", web::get().to(payment_ticket))
|
|
)
|
|
.service(
|
|
web::scope("/moderate")
|
|
.route("/keywordlist", web::get().to(moderate_keyword))
|
|
.route("/filtering/commit", web::post().to(moderate_commit))
|
|
)
|
|
.service(
|
|
web::scope("/migration")
|
|
.route("", web::post().to(migration))
|
|
.route("/code", web::get().to(migration_code))
|
|
.route("/code/verify", web::post().to(migration_verify))
|
|
.route("/password/register", web::post().to(migration_password_register))
|
|
)
|
|
.default_service(web::route().to(not_found))
|
|
);
|
|
}
|
|
|
|
fn apply_headers(res: &mut ServiceResponse) {
|
|
let gree_auth = res.request().extensions().get::<RequireGreeAuth>().is_some();
|
|
let req = res.request().clone();
|
|
let headers = res.headers_mut();
|
|
|
|
headers.insert(header::CONTENT_TYPE, "application/json".parse().unwrap());
|
|
headers.insert(header::EXPIRES, "-1".parse().unwrap());
|
|
headers.insert(header::PRAGMA, "no-cache".parse().unwrap());
|
|
headers.insert(
|
|
header::CACHE_CONTROL,
|
|
"must-revalidate, no-cache, no-store, private".parse().unwrap()
|
|
);
|
|
headers.insert(header::VARY, "Authorization,Accept-Encoding".parse().unwrap());
|
|
|
|
if gree_auth {
|
|
let auth_str = gree_authorize(&req);
|
|
headers.insert(HeaderName::from_static("x-gree-authorization"), auth_str.parse().unwrap());
|
|
}
|
|
}
|
|
|
|
|
|
fn get_uid(req: &HttpRequest) -> String {
|
|
req.headers()
|
|
.get("Authorization")
|
|
.and_then(|h| h.to_str().ok())
|
|
.and_then(|auth| auth.split(",xoauth_requestor_id=\"").nth(1))
|
|
.and_then(|s| s.split('"').next())
|
|
.unwrap_or("")
|
|
.to_string()
|
|
}
|
|
|
|
fn send(req: HttpRequest, resp: JsonValue) -> impl Responder {
|
|
req.extensions_mut().insert(RequireGreeAuth);
|
|
jzon::stringify(resp)
|
|
}
|
|
|
|
async fn not_found() -> impl Responder {
|
|
let resp = object!{
|
|
code: 10001,
|
|
message: "Not Found",
|
|
result: "NG"
|
|
};
|
|
jzon::stringify(resp)
|
|
}
|
|
|
|
async fn initialize(req: HttpRequest, body: String) -> impl Responder {
|
|
let body = jzon::parse(&body).unwrap();
|
|
let token = create_acc(&body["token"].to_string());
|
|
|
|
let app_id = APP_ID;
|
|
let resp = object!{
|
|
result: "OK",
|
|
app_id: app_id,
|
|
uuid: token
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn authorize(req: HttpRequest, _body: String) -> impl Responder {
|
|
let resp = object!{
|
|
result: "OK"
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn moderate_keyword(req: HttpRequest) -> impl Responder {
|
|
let resp = object!{
|
|
result: "OK",
|
|
entry: {
|
|
timestamp: global::timestamp(),
|
|
keywords: [{"id":"1","type":"0","keyword":"oink","rank":"0"}]
|
|
}
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
async fn moderate_commit(req: HttpRequest, _body: String) -> impl Responder {
|
|
let resp = object!{
|
|
result: "OK"
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn uid(req: HttpRequest) -> impl Responder {
|
|
let uid = get_uid(&req);
|
|
|
|
let user = userdata::get_acc(&uid);
|
|
|
|
let resp = object!{
|
|
result: "OK",
|
|
x_uid: user["user"]["id"].to_string(),
|
|
x_app_id: SRC_APP_ID
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn payment(req: HttpRequest) -> impl Responder {
|
|
let resp = object!{
|
|
result: "OK",
|
|
entry: {
|
|
products :[],
|
|
welcome: "0"
|
|
}
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
async fn payment_ticket(req: HttpRequest) -> impl Responder {
|
|
let resp = object!{
|
|
result: "OK",
|
|
entry: []
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn migration_verify(req: HttpRequest, body: String) -> impl Responder {
|
|
let body = jzon::parse(&body).unwrap();
|
|
let password = decrypt_transfer_password(&body["migration_password"].to_string());
|
|
|
|
let user = userdata::user::migration::get_acc_transfer(&body["migration_code"].to_string(), &password);
|
|
|
|
let resp = if !user["success"].as_bool().unwrap() || user["user_id"] == 0 {
|
|
object!{
|
|
result: "ERR",
|
|
messsage: "User Not Found"
|
|
}
|
|
} else {
|
|
let data_user = userdata::get_acc(&user["login_token"].to_string());
|
|
object!{
|
|
result: "OK",
|
|
src_uuid: user["login_token"].clone(),
|
|
src_x_uid: user["user_id"].to_string(),
|
|
migration_token: user["login_token"].clone(),
|
|
balance_charge_gem: data_user["gem"]["charge"].to_string(),
|
|
balance_free_gem: data_user["gem"]["free"].to_string(),
|
|
balance_total_gem: data_user["gem"]["total"].to_string()
|
|
}
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn migration(req: HttpRequest, body: String) -> impl Responder {
|
|
let body = jzon::parse(&body).unwrap();
|
|
|
|
let user = userdata::get_acc(&body["src_uuid"].to_string());
|
|
//clear old token
|
|
if !body["dst_uuid"].is_null() {
|
|
let user2 = userdata::get_acc(&body["dst_uuid"].to_string());
|
|
update_cert(user2["user"]["id"].as_i64().unwrap(), "none");
|
|
}
|
|
update_cert(user["user"]["id"].as_i64().unwrap(), &body["token"].to_string());
|
|
|
|
let resp = object!{
|
|
result: "OK"
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn balance(req: HttpRequest) -> impl Responder {
|
|
let uid = get_uid(&req);
|
|
|
|
let user = userdata::get_acc(&uid);
|
|
|
|
let resp = object!{
|
|
result: "OK",
|
|
entry: {
|
|
balance_charge_gem: user["gem"]["charge"].to_string(),
|
|
balance_free_gem: user["gem"]["free"].to_string(),
|
|
balance_total_gem: user["gem"]["total"].to_string()
|
|
}
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn migration_code(req: HttpRequest) -> impl Responder {
|
|
let uid = get_uid(&req);
|
|
|
|
let user = userdata::get_acc(&uid);
|
|
|
|
let resp = object!{
|
|
result: "OK",
|
|
migration_code: userdata::user::migration::get_acc_token(user["user"]["id"].as_i64().unwrap())
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
async fn migration_password_register(req: HttpRequest, body: String) -> impl Responder {
|
|
let body = jzon::parse(&body).unwrap();
|
|
let uid = get_uid(&req);
|
|
let user = userdata::get_acc(&uid);
|
|
let pass = decrypt_transfer_password(&body["migration_password"].to_string());
|
|
|
|
userdata::user::migration::save_acc_transfer(user["user"]["id"].as_i64().unwrap(), &pass);
|
|
|
|
let resp = object!{
|
|
result: "OK"
|
|
};
|
|
|
|
send(req, resp)
|
|
}
|
|
|
|
pub fn get_protocol() -> String {
|
|
let args = crate::get_args();
|
|
if args.https {
|
|
return String::from("https");
|
|
}
|
|
String::from("http")
|
|
}
|
|
|
|
fn gree_authorize(req: &HttpRequest) -> String {
|
|
type HmacSha1 = Hmac<Sha1>;
|
|
|
|
let blank_header = HeaderValue::from_static("");
|
|
let auth_header = req.headers().get("Authorization").unwrap_or(&blank_header).to_str().unwrap_or("");
|
|
if auth_header.is_empty() {
|
|
return String::new();
|
|
}
|
|
let auth_header = auth_header.get(6..).unwrap_or("");
|
|
|
|
let auth_list: Vec<&str> = auth_header.split(',').collect();
|
|
let mut header_data = HashMap::new();
|
|
|
|
for auth_data in auth_list {
|
|
let data: Vec<&str> = auth_data.split('=').collect();
|
|
if data.len() == 2 {
|
|
header_data.insert(data[0].to_string(), data[1][1..(data[1].len() - 1)].to_string());
|
|
}
|
|
}
|
|
|
|
let hostname = req.headers().get("host").unwrap_or(&blank_header).to_str().unwrap_or("");
|
|
let current_url = format!("{}://{}{}", get_protocol(), hostname, req.path());
|
|
let uri = req.uri().to_string();
|
|
let extra = if uri.contains('?') {
|
|
format!("&{}", uri.split('?').nth(1).unwrap_or(""))
|
|
} else { String::new() };
|
|
|
|
let nonce = format!("{:x}", md5::compute((global::timestamp() * 1000).to_string()));
|
|
let timestamp = global::timestamp().to_string();
|
|
let method = "HMAC-SHA1";
|
|
let validate_data = format!("{}&{}&{}",
|
|
req.method(),
|
|
urlencoding::encode(¤t_url),
|
|
urlencoding::encode(&format!("oauth_body_hash={}&oauth_consumer_key={}&oauth_nonce={}&oauth_signature_method={}&oauth_timestamp={}&oauth_version=1.0{}",
|
|
header_data.get("oauth_body_hash").unwrap_or(&String::new()),
|
|
header_data.get("oauth_consumer_key").unwrap_or(&String::new()),
|
|
nonce,
|
|
method,
|
|
timestamp,
|
|
extra)));
|
|
let mut hasher = HmacSha1::new_from_slice(&hex::decode(HMAC_SECRET_HEX).unwrap()).unwrap();
|
|
hasher.update(validate_data.as_bytes());
|
|
let signature = general_purpose::STANDARD.encode(hasher.finalize().into_bytes());
|
|
|
|
format!("OAuth oauth_version=\"1.0\",oauth_nonce=\"{}\",oauth_timestamp=\"{}\",oauth_consumer_key=\"{}\",oauth_body_hash=\"{}\",oauth_signature_method=\"{}\",oauth_signature=\"{}\"",
|
|
nonce,
|
|
timestamp,
|
|
header_data.get("oauth_consumer_key").unwrap_or(&String::new()),
|
|
header_data.get("oauth_body_hash").unwrap_or(&String::new()),
|
|
method,
|
|
urlencoding::encode(&signature))
|
|
}
|