Friendsfix #6
6 changed files with 153 additions and 23 deletions
|
|
@ -6,7 +6,6 @@ use std::{
|
||||||
Arc, LazyLock, Weak,
|
Arc, LazyLock, Weak,
|
||||||
atomic::{AtomicBool, AtomicU32},
|
atomic::{AtomicBool, AtomicU32},
|
||||||
},
|
},
|
||||||
thread::sleep,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -30,7 +29,7 @@ use tokio::{
|
||||||
net::{TcpSocket, UdpSocket},
|
net::{TcpSocket, UdpSocket},
|
||||||
spawn,
|
spawn,
|
||||||
sync::{Mutex, RwLock},
|
sync::{Mutex, RwLock},
|
||||||
time::Instant,
|
time::{Instant, sleep},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -73,7 +72,7 @@ pub struct Server<C: Crypto> {
|
||||||
param: ProxyStartupParam,
|
param: ProxyStartupParam,
|
||||||
socket: UdpSocket,
|
socket: UdpSocket,
|
||||||
crypto: C,
|
crypto: C,
|
||||||
connections: RwLock<HashMap<PRUDPSockAddr, Arc<Connection<C::Instance>>>>,
|
connections: RwLock<HashMap<(PRUDPSockAddr, u8), Arc<Connection<C::Instance>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Crypto> Server<C> {
|
impl<C: Crypto> Server<C> {
|
||||||
|
|
@ -167,9 +166,10 @@ impl<C: Crypto> Server<C> {
|
||||||
self.clone().send_data_packet(conn.clone(), &data).await;
|
self.clone().send_data_packet(conn.clone(), &data).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn timeout_thread(self: Arc<Self>, conn: Arc<Connection<C::Instance>>) {
|
async fn timeout_thread(self: Arc<Self>, conn: Weak<Connection<C::Instance>>) {
|
||||||
loop {
|
loop {
|
||||||
sleep(Duration::from_secs(3));
|
let Some(conn) = conn.upgrade() else { break };
|
||||||
|
sleep(Duration::from_secs(3)).await;
|
||||||
let mut inner = conn.inner.lock().await;
|
let mut inner = conn.inner.lock().await;
|
||||||
|
|
||||||
if (Instant::now() - inner.last_action).as_secs() > 5 {
|
if (Instant::now() - inner.last_action).as_secs() > 5 {
|
||||||
|
|
@ -214,7 +214,7 @@ impl<C: Crypto> Server<C> {
|
||||||
drop(inner);
|
drop(inner);
|
||||||
|
|
||||||
let mut conns = self.connections.write().await;
|
let mut conns = self.connections.write().await;
|
||||||
conns.remove(&conn.addr);
|
conns.remove(&(conn.addr, conn.session_id));
|
||||||
drop(conns);
|
drop(conns);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -258,6 +258,7 @@ impl<C: Crypto> Server<C> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let pid = ci.get_user_id();
|
let pid = ci.get_user_id();
|
||||||
|
println!("user with pid {} is connecting", pid);
|
||||||
let buf_conn = new_backend_connection(&self.param, addr, pid).await;
|
let buf_conn = new_backend_connection(&self.param, addr, pid).await;
|
||||||
let Some(buf_conn) = buf_conn else {
|
let Some(buf_conn) = buf_conn else {
|
||||||
error!("unable to connect to backend");
|
error!("unable to connect to backend");
|
||||||
|
|
@ -284,7 +285,10 @@ impl<C: Crypto> Server<C> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut conns = self.connections.write().await;
|
let mut conns = self.connections.write().await;
|
||||||
conns.insert(addr, conn.clone());
|
if conns.contains_key(&(addr, header.session_id)) {
|
||||||
|
error!("client already connected but tried to connect again");
|
||||||
|
}
|
||||||
|
conns.insert((addr, header.session_id), conn.clone());
|
||||||
drop(conns);
|
drop(conns);
|
||||||
|
|
||||||
spawn({
|
spawn({
|
||||||
|
|
@ -294,7 +298,7 @@ impl<C: Crypto> Server<C> {
|
||||||
});
|
});
|
||||||
spawn({
|
spawn({
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
let conn = conn.clone();
|
let conn = Arc::downgrade(&conn);
|
||||||
this.timeout_thread(conn)
|
this.timeout_thread(conn)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -322,7 +326,7 @@ impl<C: Crypto> Server<C> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(res) = self.get_connection(addr).await else {
|
let Some(res) = self.get_connection((addr, header.session_id)).await else {
|
||||||
warn!("data packet on inactive connection from: {:?}", addr);
|
warn!("data packet on inactive connection from: {:?}", addr);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
@ -346,7 +350,8 @@ impl<C: Crypto> Server<C> {
|
||||||
);
|
);
|
||||||
while let Some((_, mut packet)) = {
|
while let Some((_, mut packet)) = {
|
||||||
let ctr = conn.client_packet_counter;
|
let ctr = conn.client_packet_counter;
|
||||||
conn.packet_queue.remove(&ctr)
|
let packet = conn.packet_queue.remove(&ctr);
|
||||||
|
packet
|
||||||
} {
|
} {
|
||||||
info!("processing packet: {}", conn.client_packet_counter);
|
info!("processing packet: {}", conn.client_packet_counter);
|
||||||
let Some(payload) = packet.payload_mut() else {
|
let Some(payload) = packet.payload_mut() else {
|
||||||
|
|
@ -368,7 +373,7 @@ impl<C: Crypto> Server<C> {
|
||||||
info!("got ping");
|
info!("got ping");
|
||||||
let header = packet.header().unwrap();
|
let header = packet.header().unwrap();
|
||||||
|
|
||||||
let Some(conn) = self.get_connection(addr).await else {
|
let Some(conn) = self.get_connection((addr, header.session_id)).await else {
|
||||||
warn!("ping on inactive connection: {:?}", addr);
|
warn!("ping on inactive connection: {:?}", addr);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
@ -394,7 +399,7 @@ impl<C: Crypto> Server<C> {
|
||||||
info!("got disconnect");
|
info!("got disconnect");
|
||||||
let header = packet.header().unwrap();
|
let header = packet.header().unwrap();
|
||||||
|
|
||||||
let Some(conn) = self.get_connection(addr).await else {
|
let Some(conn) = self.get_connection((addr, header.session_id)).await else {
|
||||||
warn!("ping on inactive connection: {:?}", addr);
|
warn!("ping on inactive connection: {:?}", addr);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
@ -410,11 +415,18 @@ impl<C: Crypto> Server<C> {
|
||||||
);
|
);
|
||||||
drop(inner);
|
drop(inner);
|
||||||
|
|
||||||
|
let mut conns = self.connections.write().await;
|
||||||
|
conns.remove(&(addr, header.session_id));
|
||||||
|
drop(conns);
|
||||||
|
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
||||||
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
||||||
}
|
}
|
||||||
async fn get_connection(&self, addr: PRUDPSockAddr) -> Option<Arc<Connection<C::Instance>>> {
|
async fn get_connection(
|
||||||
|
&self,
|
||||||
|
addr: (PRUDPSockAddr, u8),
|
||||||
|
) -> Option<Arc<Connection<C::Instance>>> {
|
||||||
let rd = self.connections.read().await;
|
let rd = self.connections.read().await;
|
||||||
let res = rd.get(&addr).cloned();
|
let res = rd.get(&addr).cloned();
|
||||||
drop(rd);
|
drop(rd);
|
||||||
|
|
@ -436,7 +448,7 @@ impl<C: Crypto> Server<C> {
|
||||||
|
|
||||||
let addr = PRUDPSockAddr::new(SocketAddr::V4(addr), header.source);
|
let addr = PRUDPSockAddr::new(SocketAddr::V4(addr), header.source);
|
||||||
|
|
||||||
if let Some(conn) = self.get_connection(addr).await {
|
if let Some(conn) = self.get_connection((addr, header.session_id)).await {
|
||||||
let mut inner = conn.inner.lock().await;
|
let mut inner = conn.inner.lock().await;
|
||||||
inner.last_action = Instant::now();
|
inner.last_action = Instant::now();
|
||||||
drop(inner);
|
drop(inner);
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,11 @@ pub async fn start_friends_backend() {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Arc::new_cyclic(move |this| FriendsGuest {
|
new_rmc_gateway_connection(stream.into(), move |r| {
|
||||||
fm,
|
Arc::new_cyclic(move |this| FriendsGuest {
|
||||||
addr: c.prudpsock_addr,
|
fm,
|
||||||
|
addr: c.prudpsock_addr,
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,42 @@ impl Client {
|
||||||
Ok(val.as_bytes().try_into().map_err(|_| SomethingHappened)?)
|
Ok(val.as_bytes().try_into().map_err(|_| SomethingHappened)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_pid_from_token(&mut self, token: String) -> Result<PID> {
|
||||||
|
let req = self
|
||||||
|
.do_request(object! {
|
||||||
|
"query":
|
||||||
|
r"query($token: String!){
|
||||||
|
token(tokenData: $token){
|
||||||
|
pid
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
"variables": {
|
||||||
|
"token": token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
// this breaks switch nex servers and should be fixed eventually
|
||||||
|
let Some(val) = req
|
||||||
|
.entries()
|
||||||
|
.find(|v| v.0 == "data")
|
||||||
|
.ok_or(SomethingHappened)?
|
||||||
|
.1
|
||||||
|
.entries()
|
||||||
|
.find(|v| v.0 == "token")
|
||||||
|
.ok_or(SomethingHappened)?
|
||||||
|
.1
|
||||||
|
.entries()
|
||||||
|
.find(|v| v.0 == "pid")
|
||||||
|
.ok_or(SomethingHappened)?
|
||||||
|
.1
|
||||||
|
.as_u32()
|
||||||
|
else {
|
||||||
|
return Err(SomethingHappened);
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(val)
|
||||||
|
}
|
||||||
|
|
||||||
/*pub async fn get_user_data(&mut self , pid: u32) -> Result<GetUserDataResponse>{
|
/*pub async fn get_user_data(&mut self , pid: u32) -> Result<GetUserDataResponse>{
|
||||||
let req = Request::new(GetUserDataRequest{
|
let req = Request::new(GetUserDataRequest{
|
||||||
pid
|
pid
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
|
use std::io::{Cursor, Write};
|
||||||
use std::sync::{Arc, atomic::AtomicU32};
|
use std::sync::{Arc, atomic::AtomicU32};
|
||||||
|
|
||||||
|
use bytemuck::bytes_of;
|
||||||
|
use hmac::Mac;
|
||||||
use log::info;
|
use log::info;
|
||||||
use macros::rmc_struct;
|
use macros::rmc_struct;
|
||||||
|
use rnex_core::rmc::protocols::account_management::{
|
||||||
|
AccountManagement, RawAccountManagement, RawAccountManagementInfo, RemoteAccountManagement,
|
||||||
|
};
|
||||||
use rnex_core::rmc::protocols::friends::{Friends, RawFriends, RawFriendsInfo, RemoteFriends};
|
use rnex_core::rmc::protocols::friends::{Friends, RawFriends, RawFriendsInfo, RemoteFriends};
|
||||||
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||||
use rnex_core::{
|
use rnex_core::{
|
||||||
|
|
@ -24,6 +30,9 @@ use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo};
|
||||||
|
|
||||||
use rnex_core::PID;
|
use rnex_core::PID;
|
||||||
|
|
||||||
|
use crate::rmc::protocols::account_management::NintendoCreateAccountData;
|
||||||
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
define_rmc_proto!(
|
define_rmc_proto!(
|
||||||
proto FriendsUser{
|
proto FriendsUser{
|
||||||
Secure,
|
Secure,
|
||||||
|
|
@ -32,7 +41,8 @@ define_rmc_proto!(
|
||||||
);
|
);
|
||||||
define_rmc_proto!(
|
define_rmc_proto!(
|
||||||
proto FriendsGuest{
|
proto FriendsGuest{
|
||||||
Secure
|
Secure,
|
||||||
|
AccountManagement
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
#[rmc_struct(FriendsUser)]
|
#[rmc_struct(FriendsUser)]
|
||||||
|
|
@ -143,8 +153,14 @@ impl Friends for FriendsUser {
|
||||||
false,
|
false,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn check_setting_status(&self) -> Result<u8, ErrorCode> {
|
||||||
|
Ok(0xFF)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HMacMd5 = hmac::Hmac<md5::Md5>;
|
||||||
|
|
||||||
impl Secure for FriendsUser {
|
impl Secure for FriendsUser {
|
||||||
async fn register(
|
async fn register(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -194,3 +210,39 @@ impl Secure for FriendsGuest {
|
||||||
Err(ErrorCode::Core_NotImplemented)
|
Err(ErrorCode::Core_NotImplemented)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AccountManagement for FriendsGuest {
|
||||||
|
async fn nintendo_create_account(
|
||||||
|
&self,
|
||||||
|
principal_name: String,
|
||||||
|
key: String,
|
||||||
|
groups: u32,
|
||||||
|
email: String,
|
||||||
|
auth_data: Any,
|
||||||
|
) -> Result<(PID, String), ErrorCode> {
|
||||||
|
println!("{}, {}, {}, {}", principal_name, key, groups, email);
|
||||||
|
if auth_data.name == "NintendoCreateAccountData" {
|
||||||
|
let Ok(data) =
|
||||||
|
NintendoCreateAccountData::deserialize(&mut Cursor::new(&auth_data.data))
|
||||||
|
else {
|
||||||
|
return Err(ErrorCode::Authentication_InvalidParam);
|
||||||
|
};
|
||||||
|
|
||||||
|
let pid = data.nna_info.principal_basic_info.pid;
|
||||||
|
info!("create account: {}", pid);
|
||||||
|
|
||||||
|
let Ok(mut mac) = HMacMd5::new_from_slice(key.as_bytes()) else {
|
||||||
|
return Err(ErrorCode::Authentication_InvalidParam);
|
||||||
|
};
|
||||||
|
|
||||||
|
mac.write_all(bytes_of(&pid))
|
||||||
|
.expect("failed to write to hmac???");
|
||||||
|
let mac = mac.finalize().into_bytes();
|
||||||
|
|
||||||
|
let hex_str = hex::encode(mac);
|
||||||
|
|
||||||
|
return Ok((pid, hex_str));
|
||||||
|
}
|
||||||
|
Err(ErrorCode::Core_NotImplemented)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,30 @@
|
||||||
use macros::rmc_proto;
|
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||||
|
|
||||||
|
use rnex_core::{
|
||||||
|
PID,
|
||||||
|
rmc::{response::ErrorCode, structures::any::Any},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{kerberos::KerberosDateTime, rmc::protocols::friends::NNAInfo};
|
||||||
|
|
||||||
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
|
#[rmc_struct(0)]
|
||||||
|
pub struct NintendoCreateAccountData {
|
||||||
|
pub nna_info: NNAInfo,
|
||||||
|
pub nex_token: String,
|
||||||
|
pub birthday: KerberosDateTime,
|
||||||
|
pub unk: u64,
|
||||||
|
}
|
||||||
|
|
||||||
#[rmc_proto(25)]
|
#[rmc_proto(25)]
|
||||||
pub trait AccountManagement {}
|
pub trait AccountManagement {
|
||||||
|
#[method_id(27)]
|
||||||
|
async fn nintendo_create_account(
|
||||||
|
&self,
|
||||||
|
principal_name: String,
|
||||||
|
key: String,
|
||||||
|
groups: u32,
|
||||||
|
email: String,
|
||||||
|
auth_data: Any,
|
||||||
|
) -> Result<(PID, String), ErrorCode>;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use macros::{RmcSerialize, method_id, rmc_proto};
|
||||||
|
|
||||||
use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode};
|
use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode};
|
||||||
|
|
||||||
#[derive(RmcSerialize)]
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct MiiV2 {
|
pub struct MiiV2 {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -12,7 +12,7 @@ pub struct MiiV2 {
|
||||||
pub date_time: KerberosDateTime,
|
pub date_time: KerberosDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize)]
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct PrincipalBasicInfo {
|
pub struct PrincipalBasicInfo {
|
||||||
pub pid: u32,
|
pub pid: u32,
|
||||||
|
|
@ -21,7 +21,7 @@ pub struct PrincipalBasicInfo {
|
||||||
pub unk: u8,
|
pub unk: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(RmcSerialize)]
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct NNAInfo {
|
pub struct NNAInfo {
|
||||||
pub principal_basic_info: PrincipalBasicInfo,
|
pub principal_basic_info: PrincipalBasicInfo,
|
||||||
|
|
@ -143,4 +143,6 @@ pub trait Friends {
|
||||||
),
|
),
|
||||||
ErrorCode,
|
ErrorCode,
|
||||||
>;
|
>;
|
||||||
|
#[method_id(19)]
|
||||||
|
async fn check_setting_status(&self) -> Result<u8, ErrorCode>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue