From 9f9393cfe5c7e8e68854a894759e0915b25786a1 Mon Sep 17 00:00:00 2001 From: DJMrTV Date: Sat, 8 Mar 2025 00:53:11 +0100 Subject: [PATCH] feat: some refactoring and /v1/api/provider/nex_token/@me --- .gitlab-ci.yml | 7 ++-- Cargo.lock | 11 ++++++ Cargo.toml | 2 +- Dockerfile | 2 + src/account/account.rs | 3 +- src/nnid/oauth/generate_token.rs | 67 +++++++++++++------------------- src/nnid/provider.rs | 42 ++++++++++++++++++-- 7 files changed, 86 insertions(+), 48 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 64ff236..3098a7f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,6 +5,7 @@ variables: IMAGE_TAG: "${CI_COMMIT_REF_SLUG}" before_script: + - git submodule update --init - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" ci.perditum.com stages: @@ -12,10 +13,6 @@ stages: - build - push -initialize-submodules: - stage: initialize-submodules - script: - - git submodule update --init build: stage: build @@ -25,6 +22,8 @@ build: push: stage: push + needs: + - build script: - docker tag "$IMAGE_NAME:$IMAGE_TAG" "$IMAGE_NAME:latest" - docker push "$IMAGE_NAME:$IMAGE_TAG" diff --git a/Cargo.lock b/Cargo.lock index 4bfb3e6..c027ea7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1507,6 +1507,15 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + [[package]] name = "is-terminal" version = "0.4.15" @@ -2760,6 +2769,7 @@ dependencies = [ "hashbrown 0.15.2", "hashlink", "indexmap 2.7.1", + "ipnetwork", "log", "memchr", "native-tls", @@ -2879,6 +2889,7 @@ dependencies = [ "hkdf", "hmac", "home", + "ipnetwork", "itoa", "log", "md-5", diff --git a/Cargo.toml b/Cargo.toml index ab9e71b..b43b857 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ base64 = "0.22.1" hex = "0.4.3" thiserror = "2.0.11" bcrypt = "0.17.0" -sqlx = { version = "0.8.3", features = [ "runtime-tokio", "tls-native-tls", "postgres", "chrono" ] } +sqlx = { version = "0.8.3", features = [ "runtime-tokio", "tls-native-tls", "postgres", "chrono", "ipnetwork" ] } aes = "0.8.4" hmac = "0.12.1" md-5 = "0.10.6" diff --git a/Dockerfile b/Dockerfile index 1641a84..948b1a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,5 @@ +# syntax=docker/dockerfile:1 + FROM rust:alpine as builder RUN apk add --no-cache musl-dev openssl-dev openssl-libs-static protobuf-dev lld diff --git a/src/account/account.rs b/src/account/account.rs index 8d14d2d..a8142ab 100644 --- a/src/account/account.rs +++ b/src/account/account.rs @@ -53,7 +53,8 @@ pub struct User { pub region: i32, pub mii_data: String, pub creation_date: NaiveDateTime, - pub updated: NaiveDateTime + pub updated: NaiveDateTime, + pub nex_password: String } fn generate_nintendo_hash(pid: i32, text_password: &str) -> String{ diff --git a/src/nnid/oauth/generate_token.rs b/src/nnid/oauth/generate_token.rs index c8ffea8..6ffdb49 100644 --- a/src/nnid/oauth/generate_token.rs +++ b/src/nnid/oauth/generate_token.rs @@ -3,10 +3,17 @@ use rocket::form::Form; use serde::{Deserialize, Serialize}; use crate::account::account::User; use crate::error::{Error, Errors}; +use crate::nnid::oauth::generate_token::token_type::{AUTH_REFRESH_TOKEN, AUTH_TOKEN}; use crate::nnid::oauth::TokenData; use crate::Pool; use crate::xml::Xml; +pub mod token_type{ + pub const AUTH_REFRESH_TOKEN: i32 = 1; + pub const AUTH_TOKEN: i32 = 0; + pub const NEX_TOKEN: i32 = 2; +} + const ACCOUNT_ID_OR_PASSWORD_ERRORS: Errors = Errors{ error: &[ Error{ @@ -40,51 +47,33 @@ pub struct TokenReturnData { expires_in: i32 } -impl TokenReturnData { - async fn create_token(pid: i32, pool: &Pool, is_refresh_token: bool) -> (i64, i32){ - let token_type = if is_refresh_token{ - 0x0 - } else { - 0x1 - }; - let data = sqlx::query!( - "insert into tokens (token_type, pid) - values ($1, $2) returning token_id, random", - token_type, pid +pub async fn create_token(pool: &Pool, pid: i32, token_type: i32, title_id: Option<&str>) -> String{ + let data = sqlx::query!( + "insert into tokens (token_type, pid, title_id) + values ($1, $2, $3) returning token_id, random", + token_type, pid, title_id ) - .fetch_one(pool) - .await.unwrap(); + .fetch_one(pool) + .await.unwrap(); - (data.token_id, data.random) - } - async fn create_regular_token(pid: i32, pool: &Pool) -> (i64, i32){ - Self::create_token(pid, pool, false).await - } + let token_id = data.token_id; + let random = data.random; - async fn create_refresh_token(pid: i32, pool: &Pool) -> (i64, i32){ - Self::create_token(pid, pool, true).await - } + let token = TokenData { + token_id, + random, + pid + }; + token.encode().to_string() +} + + +impl TokenReturnData { async fn new(pid: i32, pool: &Pool) -> Self{ - let (token_id, random) = Self::create_regular_token(pid, pool).await; + let token = create_token(pool, pid, AUTH_TOKEN, None).await; - let token = TokenData { - token_id, - random, - pid - }; - - let token = token.encode().to_string(); - - let (token_id, random) = Self::create_refresh_token(pid, pool).await; - - let refresh_token = TokenData { - token_id, - random, - pid - }; - - let refresh_token = refresh_token.encode().to_string(); + let refresh_token = create_token(pool, pid, AUTH_REFRESH_TOKEN, None).await; Self{ token, diff --git a/src/nnid/provider.rs b/src/nnid/provider.rs index 224add1..e24d7e5 100644 --- a/src/nnid/provider.rs +++ b/src/nnid/provider.rs @@ -1,7 +1,12 @@ use std::net::Ipv4Addr; use std::str::FromStr; -use rocket::get; +use rocket::{get, State}; use serde::Serialize; +use sqlx::types::ipnetwork::IpNetwork::V4; +use crate::account::account::Auth; +use crate::nnid::oauth::generate_token::create_token; +use crate::nnid::oauth::generate_token::token_type::NEX_TOKEN; +use crate::Pool; use crate::xml::Xml; #[derive(Serialize)] @@ -15,6 +20,37 @@ struct NexToken{ } #[get("/v1/api/provider/nex_token/@me?")] -pub async fn get_nex_token(game_server_id: String) -> Option>{ - None +pub async fn get_nex_token(pool: &State, auth: Auth, game_server_id: String) -> Option>{ + // just gonna put this here as a side note for the future: + // we could also be using key derivation to derive the nex token as if it were a key + // that way we could reduce the data the database needs to store and also reduce the transfer + // cost of sending an entire row from the user table (which is required for the auth code unless + // we change the way we read in data to essentially having the user object be a proxy for its + // table row) + let pool = pool.inner(); + + let server = sqlx::query!( + "select * from nex_servers where game_server_id = $1", + game_server_id + ) .fetch_one(pool).await.ok()?; + + let token = create_token(pool, auth.pid, NEX_TOKEN, None).await; + + let V4(host) = server.address else { + return None + }; + + let host = host.ip(); + + Some( + Xml( + NexToken{ + host, + port: server.port as u16, + nex_password: auth.nex_password.clone(), + pid: auth.pid, + token + } + ) + ) } \ No newline at end of file