progress
Some checks failed
Build and Test / super-mario-maker (push) Failing after 10m30s
Build and Test / fast-racing-neo (push) Failing after 11m40s
Build and Test / friends (push) Failing after 11m56s
Build and Test / wii-sports-club (push) Failing after 12m9s
Build and Test / splatoon (push) Failing after 12m14s
Build and Test / puyopuyo (push) Failing after 12m23s
Build and Test / wii-u-chat (push) Failing after 12m23s
Build and Test / mario-tennis (push) Failing after 12m23s
Build and Test / sonic-transformed (push) Failing after 12m23s
Build and Test / splatoon-testfire (push) Failing after 12m30s
Build and Test / minecraft-wiiu (push) Failing after 12m37s
Some checks failed
Build and Test / super-mario-maker (push) Failing after 10m30s
Build and Test / fast-racing-neo (push) Failing after 11m40s
Build and Test / friends (push) Failing after 11m56s
Build and Test / wii-sports-club (push) Failing after 12m9s
Build and Test / splatoon (push) Failing after 12m14s
Build and Test / puyopuyo (push) Failing after 12m23s
Build and Test / wii-u-chat (push) Failing after 12m23s
Build and Test / mario-tennis (push) Failing after 12m23s
Build and Test / sonic-transformed (push) Failing after 12m23s
Build and Test / splatoon-testfire (push) Failing after 12m30s
Build and Test / minecraft-wiiu (push) Failing after 12m37s
This commit is contained in:
parent
7dd502aa7a
commit
4ff0a5efcc
187 changed files with 4526 additions and 5132 deletions
1430
Cargo.lock
generated
1430
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
38
Cargo.toml
38
Cargo.toml
|
|
@ -1,8 +1,38 @@
|
|||
[workspace]
|
||||
resolver = "3"
|
||||
members = [
|
||||
"macros",
|
||||
"rnex-core",
|
||||
"prudpv1",
|
||||
"prudpv0"
|
||||
, "proxy", "proxy-common", "prudplite"]
|
||||
"prudpv0",
|
||||
"proxy",
|
||||
"proxy-common",
|
||||
"rnex-rmc",
|
||||
"rnex-rmc/macros",
|
||||
"rnex-util",
|
||||
"rnex-protocols/mm-protos",
|
||||
"rnex-protocols/ds-protos",
|
||||
"rnex-protocols/rk-protos",
|
||||
"rnex-protocols/base-protos",
|
||||
"rnex-protocols/auth-protos",
|
||||
"rnex-protocols/reggie-protos",
|
||||
"rnex-protocols/msg-protos",
|
||||
"rnex-protocols/fpd-protos",
|
||||
"rnex-prudp",
|
||||
"rnex-server",
|
||||
"rnex-server/backend-auth",
|
||||
"rnex-server/backend-secure",
|
||||
"rnex-server/backend-node-holder",
|
||||
"rnex-server-nex-modules/rnex-mm",
|
||||
"rnex-server-nex-modules/rnex-ds",
|
||||
"rnex-server-nex-modules/rnex-rk",
|
||||
"rnex-server-nex-modules/rnex-fpd",
|
||||
"rnex-server-nex-modules/rnex-node-holder",
|
||||
"rnex-server-nex-modules/rnex-base",
|
||||
"rnex-server-nex-modules/rnex-msg",
|
||||
"rnex-server-nex-modules/rnex-auth"
|
||||
]
|
||||
|
||||
|
||||
[workspace.lints.clippy]
|
||||
print_stdout = { level = "deny", priority = 1}
|
||||
pedantic = { level = "warn", priority = 0 }
|
||||
all = { level = "warn", priority = -1 }
|
||||
|
|
|
|||
|
|
@ -13,4 +13,6 @@ echo CHECKING $EDITION
|
|||
echo FEATURES:
|
||||
echo $EDITION_FEATURES
|
||||
|
||||
RUSTFLAGS="--deny warnings" cargo check --features "$EDITION_FEATURES"
|
||||
#RUSTFLAGS="--deny warnings" cargo clippy --workspace --features "$EDITION_FEATURES"
|
||||
# cargo check --workspace --features "$EDITION_FEATURES"
|
||||
echo "edition checks are disabled right now due to being in"
|
||||
|
|
|
|||
|
|
@ -3,9 +3,16 @@ name = "proxy-common"
|
|||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
thiserror = "2.0.12"
|
||||
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
||||
rnex-prudp = { path = "../rnex-prudp" }
|
||||
rnex-server = { path = "../rnex-server" }
|
||||
rnex-util = { path = "../rnex-util" }
|
||||
rnex-reggie-protos = { path = "../rnex-protocols/reggie-protos" }
|
||||
rnex-rmc = { path = "../rnex-rmc" }
|
||||
tokio = { version = "1.47.0", features = ["full"] }
|
||||
log = "0.4.25"
|
||||
hex = "0.4.3"
|
||||
tracing = "0.1.44"
|
||||
|
|
|
|||
|
|
@ -1,21 +1,14 @@
|
|||
use log::{error, info};
|
||||
use rnex_core::{
|
||||
PID,
|
||||
executables::common::try_get_ip,
|
||||
prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort},
|
||||
reggie::{RemoteEdgeNodeHolder, UnitPacketWrite},
|
||||
rmc::{
|
||||
protocols::{
|
||||
RemoteDisconnectable, RmcCallable, RmcConnection, RmcPureRemoteObject,
|
||||
new_rmc_gateway_connection,
|
||||
},
|
||||
structures::RmcSerialize,
|
||||
},
|
||||
rnex_proxy_common::ConnectionInitData,
|
||||
util::{SendingBufferConnection, SplittableBufferConnection},
|
||||
use rnex_prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort};
|
||||
use rnex_reggie_protos::reggie::{EdgeNodeHolderConnectOption, RemoteEdgeNodeHolder};
|
||||
use rnex_rmc::{
|
||||
RemoteDisconnectable, RmcCallable, RmcConnection, RmcPureRemoteObject,
|
||||
new_rmc_gateway_connection, serialization::RmcSerialize,
|
||||
};
|
||||
use rnex_server::{ConnectionInitData, try_get_ip};
|
||||
use rnex_util::{PID, SendingBufferConnection, SplittableBufferConnection, UnitPacketWrite};
|
||||
use std::{
|
||||
env::{self, VarError},
|
||||
fmt::Debug,
|
||||
net::{AddrParseError, Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
ops::Deref,
|
||||
panic,
|
||||
|
|
@ -24,6 +17,7 @@ use std::{
|
|||
};
|
||||
use thiserror::Error;
|
||||
use tokio::net::TcpStream;
|
||||
use tracing::{error, info, instrument};
|
||||
|
||||
const RNEX_DEFAULT_PORT: u16 = match u16::from_str_radix(env!("RNEX_DEFAULT_PORT"), 10) {
|
||||
Ok(v) => v,
|
||||
|
|
@ -104,6 +98,15 @@ impl ProxyStartupParam {
|
|||
}
|
||||
|
||||
struct OnRemoteDrop<T: RemoteDisconnectable, C: FnOnce() + Send + Sync + 'static>(T, Option<C>);
|
||||
impl<T: RemoteDisconnectable + Debug, C: FnOnce() + Send + Sync + 'static> Debug
|
||||
for OnRemoteDrop<T, C>
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut tuple_builder = f.debug_tuple("OnRemoteDrop");
|
||||
tuple_builder.field(&self.0);
|
||||
tuple_builder.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
impl<T: RemoteDisconnectable, C: FnOnce() + Send + Sync + 'static> Deref for OnRemoteDrop<T, C> {
|
||||
type Target = T;
|
||||
|
||||
|
|
@ -136,10 +139,10 @@ impl<T: RemoteDisconnectable, C: FnOnce() + Send + Sync + 'static> RmcCallable
|
|||
_protocol_id: u16,
|
||||
_method_id: u32,
|
||||
_call_id: u32,
|
||||
_rest: Vec<u8>,
|
||||
) -> impl Future<Output = ()> + Send {
|
||||
_rest: &[u8],
|
||||
) -> impl Future<Output = bool> + Send {
|
||||
// maybe respond with not implemented or something
|
||||
async {}
|
||||
async { false }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +163,7 @@ pub async fn setup_edge_node_connection(
|
|||
let conn: SplittableBufferConnection = conn.into();
|
||||
|
||||
conn.send(
|
||||
rnex_core::reggie::EdgeNodeHolderConnectOption::Register(param.self_public)
|
||||
EdgeNodeHolderConnectOption::Register(param.self_public)
|
||||
.to_data()
|
||||
.unwrap(),
|
||||
)
|
||||
|
|
@ -168,7 +171,7 @@ pub async fn setup_edge_node_connection(
|
|||
|
||||
println!("{:?}", param.self_public);
|
||||
//leave the inner object floating so that it gets destroyed once we disconnect
|
||||
new_rmc_gateway_connection(conn, move |r| {
|
||||
new_rmc_gateway_connection(conn, async move |r| {
|
||||
Arc::new(OnRemoteDrop::<RemoteEdgeNodeHolder, _>::new(
|
||||
r,
|
||||
shutdown_callback,
|
||||
|
|
@ -191,7 +194,7 @@ pub async fn new_backend_connection(
|
|||
};
|
||||
|
||||
let data = ConnectionInitData {
|
||||
prudpsock_addr: addr,
|
||||
addr: addr.regular_socket_addr,
|
||||
pid: pid,
|
||||
}
|
||||
.to_data()
|
||||
|
|
|
|||
|
|
@ -3,20 +3,20 @@ name = "proxy"
|
|||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.47.0", features = ["full"] }
|
||||
prudpv0 = { path = "../prudpv0", optional = true }
|
||||
prudpv1 = { path = "../prudpv1", optional = true }
|
||||
prudplite = { path = "../prudplite", optional = true }
|
||||
proxy-common = { path = "../proxy-common" }
|
||||
cfg-if = "1.0.4"
|
||||
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
||||
log = "0.4.25"
|
||||
rnex-prudp = { path = "../rnex-prudp" }
|
||||
|
||||
[features]
|
||||
prudpv0 = ["dep:prudpv0"]
|
||||
prudpv1 = ["dep:prudpv1"]
|
||||
prudplite = ["dep:prudplite"]
|
||||
friends = ["prudpv0", "prudpv0/friends"]
|
||||
splatoon = ["prudpv1"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
name = "prudplite"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
nx = []
|
||||
v4-3-11 = []
|
||||
|
||||
[dependencies]
|
||||
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
||||
tokio = { version = "1.47.0", features = ["full"] }
|
||||
bytemuck = { version = "1.23.1", features = ["derive"] }
|
||||
proxy-common = {path = "../proxy-common"}
|
||||
tokio-tungstenite = {version = "0.29.0", features = ["rustls", "rustls-tls-native-roots"]}
|
||||
log = "0.4.25"
|
||||
futures-util = "0.3.31"
|
||||
v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" }
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
use rnex_core::PID;
|
||||
|
||||
use crate::crypto::Crypto;
|
||||
|
||||
pub struct Insecure;
|
||||
|
||||
impl Crypto for Insecure {
|
||||
fn new_connection(&self, _data: &[u8]) -> Option<(PID, Vec<u8>)> {
|
||||
Some((100, vec![]))
|
||||
}
|
||||
fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
use rnex_core::PID;
|
||||
|
||||
pub mod insecure;
|
||||
pub mod secure;
|
||||
|
||||
pub trait Crypto: 'static + Send + Sync {
|
||||
fn new_connection(&self, data: &[u8]) -> Option<(PID, Vec<u8>)>;
|
||||
fn new() -> Self;
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
use rnex_core::{
|
||||
PID, executables::common::SECURE_SERVER_ACCOUNT, nex::account::Account,
|
||||
prudp::ticket::read_secure_connection_data, rmc::structures::RmcSerialize,
|
||||
};
|
||||
|
||||
use crate::crypto::Crypto;
|
||||
|
||||
pub struct Secure(&'static Account);
|
||||
|
||||
impl Crypto for Secure {
|
||||
fn new_connection(&self, data: &[u8]) -> Option<(PID, Vec<u8>)> {
|
||||
let (_, pid, check_value) = read_secure_connection_data(data, &self.0)?;
|
||||
|
||||
let check_value_response = check_value + 1;
|
||||
|
||||
let data = bytemuck::bytes_of(&check_value_response);
|
||||
|
||||
let mut response = Vec::new();
|
||||
|
||||
data.serialize(&mut response).ok()?;
|
||||
|
||||
Some((pid, response))
|
||||
}
|
||||
fn new() -> Self {
|
||||
Self(&SECURE_SERVER_ACCOUNT)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
use futures_util::{SinkExt, StreamExt};
|
||||
use rnex_core::prudp::types_flags::{TypesFlags, flags::NEED_ACK, types::SYN};
|
||||
use tokio_tungstenite::tungstenite::{Message, client::IntoClientRequest, http::header};
|
||||
|
||||
use crate::packet::{LiteHeader, LitePacket, PacketSpecificData, StreamTypes, create_packet_from};
|
||||
|
||||
mod packet;
|
||||
|
||||
const KEY: &str = "4eb18d39";
|
||||
|
||||
const URL: &str = "wss://g2DF33D01-lp1.s.n.srv.nintendo.net";
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let login = URL.into_client_request().unwrap();
|
||||
let (mut stream, response) = tokio_tungstenite::connect_async(login).await.unwrap();
|
||||
|
||||
println!("response: {:?}", response);
|
||||
|
||||
let packet = create_packet_from(
|
||||
LiteHeader {
|
||||
stream_types: StreamTypes::new(10, 10),
|
||||
source_port: 1,
|
||||
destination_port: 1,
|
||||
fragment_id: 0,
|
||||
types_flags: TypesFlags::default().types(SYN).flags(NEED_ACK),
|
||||
sequence_id: 0,
|
||||
..Default::default()
|
||||
},
|
||||
&[PacketSpecificData::SupportedFunctions(0x8)],
|
||||
&[],
|
||||
);
|
||||
|
||||
println!("sending ack");
|
||||
stream.send(Message::Binary(packet.into())).await.unwrap();
|
||||
println!("waiting for response");
|
||||
let packet = stream.next().await.unwrap();
|
||||
let Message::Binary(packet) = packet.unwrap() else {
|
||||
panic!()
|
||||
};
|
||||
let packet = LitePacket::new(packet);
|
||||
|
||||
let header = packet.header().unwrap();
|
||||
|
||||
println!("{:?}", header);
|
||||
}
|
||||
|
|
@ -1,316 +0,0 @@
|
|||
pub mod crypto;
|
||||
mod packet;
|
||||
|
||||
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
crypto::{Crypto, insecure::Insecure, secure::Secure},
|
||||
packet::{LiteHeader, LitePacket, PacketSpecificData, StreamTypes, create_packet_from},
|
||||
};
|
||||
use futures_util::{SinkExt, StreamExt};
|
||||
use log::{error, info, warn};
|
||||
use proxy_common::{ProxyStartupParam, new_backend_connection};
|
||||
use rnex_core::{
|
||||
PID,
|
||||
prudp::{
|
||||
socket_addr::PRUDPSockAddr,
|
||||
types_flags::{
|
||||
TypesFlags,
|
||||
flags::{ACK, NEED_ACK, RELIABLE},
|
||||
types::{CONNECT, DATA, DISCONNECT, PING, SYN},
|
||||
},
|
||||
virtual_port::VirtualPort,
|
||||
},
|
||||
util::SplittableBufferConnection,
|
||||
};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio_tungstenite::{
|
||||
WebSocketStream,
|
||||
tungstenite::{Bytes, Message},
|
||||
};
|
||||
|
||||
struct ConnectionState {
|
||||
param: Arc<ProxyStartupParam>,
|
||||
active: bool,
|
||||
websocket: WebSocketStream<TcpStream>,
|
||||
#[allow(dead_code)]
|
||||
pid: PID,
|
||||
backend_conn: SplittableBufferConnection,
|
||||
addr: PRUDPSockAddr,
|
||||
incoming_reliable: HashMap<u16, LitePacket<Bytes>>,
|
||||
client_reliable_counter: u16,
|
||||
#[allow(dead_code)]
|
||||
server_reliable_counter: u16,
|
||||
}
|
||||
|
||||
impl ConnectionState {
|
||||
pub async fn handle_incoming_prudp(&mut self, packet: LitePacket<Bytes>, sorted: bool) {
|
||||
let Some(header) = packet.header() else {
|
||||
warn!("invalid data on connection");
|
||||
return;
|
||||
};
|
||||
|
||||
if (header.types_flags.get_flags() & NEED_ACK) != 0 {
|
||||
let data = create_packet_from(
|
||||
LiteHeader {
|
||||
stream_types: StreamTypes::new(
|
||||
self.param.virtual_port.get_stream_type(),
|
||||
self.addr.virtual_port.get_stream_type(),
|
||||
),
|
||||
source_port: self.param.virtual_port.get_port_number(),
|
||||
destination_port: self.addr.virtual_port.get_port_number(),
|
||||
fragment_id: header.fragment_id,
|
||||
types_flags: TypesFlags::default()
|
||||
.types(header.types_flags.get_types())
|
||||
.flags(ACK),
|
||||
sequence_id: header.sequence_id,
|
||||
..Default::default()
|
||||
},
|
||||
&[],
|
||||
&[],
|
||||
);
|
||||
let data: Bytes = data.into();
|
||||
if header.types_flags.get_types() == DISCONNECT {
|
||||
self.websocket
|
||||
.send(Message::Binary(data.clone()))
|
||||
.await
|
||||
.ok();
|
||||
self.websocket
|
||||
.send(Message::Binary(data.clone()))
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
self.websocket.send(Message::Binary(data)).await.ok();
|
||||
}
|
||||
|
||||
if (header.types_flags.get_flags() & ACK) != 0 {
|
||||
// we can just safely ignore acks, we ARE sending over tcp after all already guarantees that our packets will arrive
|
||||
// we can however not guarantee the order of incoming client packets so we should still take care of that
|
||||
// (the client might be doing some funny things which we dont know of)
|
||||
return;
|
||||
}
|
||||
|
||||
if (header.types_flags.get_flags() & RELIABLE != 0) & !sorted {
|
||||
self.incoming_reliable.insert(header.sequence_id, packet);
|
||||
if self.incoming_reliable.len() > 5 {
|
||||
self.active = false;
|
||||
warn!("client is spamming out of order reliable packets, throwing out");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
match header.types_flags.get_types() {
|
||||
DATA => {
|
||||
if header.fragment_id != 0 {
|
||||
warn!("fragmented packets arent yet supported");
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(payload) = packet.payload() else {
|
||||
return;
|
||||
};
|
||||
self.backend_conn.send(payload.into()).await;
|
||||
}
|
||||
PING => {}
|
||||
v => {
|
||||
info!("unimplemented packet type: {}", v);
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub async fn process_reliable(&mut self) {
|
||||
while let Some(v) = self.incoming_reliable.remove(&self.client_reliable_counter) {
|
||||
self.handle_incoming_prudp(v, true).await;
|
||||
self.client_reliable_counter += 1;
|
||||
}
|
||||
}
|
||||
pub async fn handle_connection(&mut self) {
|
||||
while self.active {
|
||||
tokio::select! {
|
||||
v = self.websocket.next() => {
|
||||
match v {
|
||||
Some(Ok(Message::Binary(v))) => {
|
||||
self.handle_incoming_prudp(LitePacket::new(v), false).await;
|
||||
}
|
||||
_ => {
|
||||
info!("client disconnected or errored out");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = self.backend_conn.recv() => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn websocket_thread_unconnected<C: Crypto>(
|
||||
param: Arc<ProxyStartupParam>,
|
||||
crypto: Arc<C>,
|
||||
conn: TcpStream,
|
||||
addr: SocketAddr,
|
||||
) {
|
||||
let mut websocket = match tokio_tungstenite::accept_async(conn).await {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("error accepting websocket connection: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
while let Some(Ok(v)) = websocket.next().await {
|
||||
match v {
|
||||
Message::Binary(b) => {
|
||||
let packet = LitePacket::new(b);
|
||||
|
||||
let Some(header) = packet.header() else {
|
||||
error!("got malformed message, disconnecting");
|
||||
return;
|
||||
};
|
||||
|
||||
match header.types_flags.get_types() {
|
||||
SYN => {
|
||||
let Some(supported) = packet.packet_specific_iter() else {
|
||||
error!("got malformed message, disconnecting");
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(PacketSpecificData::SupportedFunctions(s)) = supported
|
||||
.into_iter()
|
||||
.find(|v| matches!(v, PacketSpecificData::SupportedFunctions(_)))
|
||||
else {
|
||||
error!("got malformed message, disconnecting");
|
||||
return;
|
||||
};
|
||||
|
||||
let data = create_packet_from(
|
||||
LiteHeader {
|
||||
destination_port: header.source_port,
|
||||
source_port: param.virtual_port.get_port_number(),
|
||||
stream_types: StreamTypes::new(
|
||||
param.virtual_port.get_stream_type(),
|
||||
header.stream_types.source(),
|
||||
),
|
||||
fragment_id: 0,
|
||||
sequence_id: 0,
|
||||
types_flags: TypesFlags::default().types(SYN).flags(ACK),
|
||||
..Default::default()
|
||||
},
|
||||
&[
|
||||
PacketSpecificData::SupportedFunctions(s & 0xFF),
|
||||
PacketSpecificData::ConnectionSignature([0; 16]),
|
||||
],
|
||||
&[],
|
||||
);
|
||||
websocket.send(Message::Binary(data.into())).await.ok();
|
||||
}
|
||||
CONNECT => {
|
||||
let Some(supported) = packet.packet_specific_iter() else {
|
||||
error!("got malformed message, disconnecting");
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(PacketSpecificData::SupportedFunctions(s)) = supported
|
||||
.into_iter()
|
||||
.find(|v| matches!(v, PacketSpecificData::SupportedFunctions(_)))
|
||||
else {
|
||||
error!("got malformed message, disconnecting");
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(data) = packet.payload() else {
|
||||
error!("got malformed message, disconnecting");
|
||||
return;
|
||||
};
|
||||
|
||||
let Some((pid, data)) = crypto.new_connection(data) else {
|
||||
error!("invalid login data");
|
||||
return;
|
||||
};
|
||||
|
||||
let data = create_packet_from(
|
||||
LiteHeader {
|
||||
destination_port: header.source_port,
|
||||
source_port: param.virtual_port.get_port_number(),
|
||||
stream_types: StreamTypes::new(
|
||||
param.virtual_port.get_stream_type(),
|
||||
header.stream_types.source(),
|
||||
),
|
||||
fragment_id: 0,
|
||||
sequence_id: 0,
|
||||
types_flags: TypesFlags::default().types(CONNECT).flags(ACK),
|
||||
..Default::default()
|
||||
},
|
||||
&[
|
||||
PacketSpecificData::SupportedFunctions(s & 0xFF),
|
||||
PacketSpecificData::ConnectionSignature([0; 16]),
|
||||
],
|
||||
&data,
|
||||
);
|
||||
websocket.send(Message::Binary(data.into())).await.ok();
|
||||
|
||||
let addr = PRUDPSockAddr::new(
|
||||
addr,
|
||||
VirtualPort::new(header.source_port, header.stream_types.source()),
|
||||
);
|
||||
let Some(backend_conn) = new_backend_connection(¶m, addr, pid).await
|
||||
else {
|
||||
error!("unable to connect to backend");
|
||||
return;
|
||||
};
|
||||
let mut connection = ConnectionState {
|
||||
active: true,
|
||||
addr,
|
||||
pid,
|
||||
backend_conn,
|
||||
client_reliable_counter: 2,
|
||||
server_reliable_counter: 1,
|
||||
param,
|
||||
incoming_reliable: HashMap::new(),
|
||||
websocket,
|
||||
};
|
||||
|
||||
connection.handle_connection().await;
|
||||
break;
|
||||
}
|
||||
v => {
|
||||
error!(
|
||||
"invalid packet type for unconnected client {}, disconnecting",
|
||||
v,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
v => {
|
||||
error!("non binary message({:?}) , disconnecting", v);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start_proxy<C: Crypto>(param: ProxyStartupParam) {
|
||||
let param = Arc::new(param);
|
||||
let crypto = Arc::new(C::new());
|
||||
let listener = TcpListener::bind(param.self_private)
|
||||
.await
|
||||
.expect("unable to bind to port");
|
||||
|
||||
while let Ok((connection, addr)) = listener.accept().await {
|
||||
let param = param.clone();
|
||||
let crypto = crypto.clone();
|
||||
tokio::spawn(websocket_thread_unconnected(
|
||||
param, crypto, connection, addr,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start_secure(param: ProxyStartupParam) {
|
||||
start_proxy::<Secure>(param).await;
|
||||
}
|
||||
|
||||
pub async fn start_insecure(param: ProxyStartupParam) {
|
||||
start_proxy::<Insecure>(param).await;
|
||||
}
|
||||
|
|
@ -1,222 +0,0 @@
|
|||
use std::{
|
||||
fmt::Debug,
|
||||
io::{self, Cursor, Read, Write},
|
||||
};
|
||||
|
||||
use bytemuck::{Pod, Zeroable, bytes_of_mut};
|
||||
use rnex_core::prudp::types_flags::TypesFlags;
|
||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
||||
|
||||
#[derive(Pod, Zeroable, Copy, Clone, Default, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct LiteHeader {
|
||||
pub magic: u8,
|
||||
pub packet_specific_length: u8,
|
||||
pub payload_size: u16,
|
||||
pub stream_types: StreamTypes,
|
||||
pub source_port: u8,
|
||||
pub destination_port: u8,
|
||||
pub fragment_id: u8,
|
||||
pub types_flags: TypesFlags,
|
||||
pub sequence_id: u16,
|
||||
}
|
||||
|
||||
pub enum PacketSpecificData {
|
||||
SupportedFunctions(u32),
|
||||
ConnectionSignature([u8; 16]),
|
||||
LiteSignature([u8; 16]),
|
||||
}
|
||||
|
||||
impl PacketSpecificData {
|
||||
fn consume(reader: &mut impl Read) -> io::Result<Self> {
|
||||
let mut option_id = 0u8;
|
||||
reader.read_exact(bytes_of_mut(&mut option_id))?;
|
||||
let mut size = 0u8;
|
||||
reader.read_exact(bytes_of_mut(&mut size))?;
|
||||
|
||||
match option_id {
|
||||
0 => {
|
||||
if size != 4 {
|
||||
Err(io::Error::other(
|
||||
"invalid option size for supported functions",
|
||||
))
|
||||
} else {
|
||||
Ok(Self::SupportedFunctions(reader.read_le_u32()?))
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
if size != 16 {
|
||||
Err(io::Error::other(
|
||||
"invalid option size for connection signature",
|
||||
))
|
||||
} else {
|
||||
Ok(Self::ConnectionSignature(
|
||||
reader.read_struct(IS_BIG_ENDIAN)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
0x80 => {
|
||||
if size != 16 {
|
||||
Err(io::Error::other("invalid option size for lite signature"))
|
||||
} else {
|
||||
Ok(Self::LiteSignature(reader.read_struct(IS_BIG_ENDIAN)?))
|
||||
}
|
||||
}
|
||||
_ => Err(io::Error::other("invalid option id")),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_size(&self) -> usize {
|
||||
2 + match self {
|
||||
PacketSpecificData::SupportedFunctions(_) => 4,
|
||||
Self::ConnectionSignature(_) => 16,
|
||||
Self::LiteSignature(_) => 16,
|
||||
}
|
||||
}
|
||||
|
||||
fn write_self(&self, writer: &mut impl Write) -> io::Result<()> {
|
||||
match self {
|
||||
PacketSpecificData::SupportedFunctions(v) => {
|
||||
writer.write_all(&[0, 4])?;
|
||||
writer.write_all(&v.to_le_bytes())?;
|
||||
}
|
||||
Self::ConnectionSignature(v) => {
|
||||
writer.write_all(&[1, 16])?;
|
||||
writer.write_all(&v[..])?;
|
||||
}
|
||||
Self::LiteSignature(v) => {
|
||||
writer.write_all(&[0x80, 16])?;
|
||||
writer.write_all(&v[..])?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LitePacket<T: AsRef<[u8]>>(T);
|
||||
|
||||
pub struct PacketSpecificIter<'a>(Cursor<&'a [u8]>);
|
||||
|
||||
impl<'a> Iterator for PacketSpecificIter<'a> {
|
||||
type Item = PacketSpecificData;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
PacketSpecificData::consume(&mut self.0).ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> LitePacket<T> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
|
||||
pub fn header(&self) -> Option<&LiteHeader> {
|
||||
bytemuck::try_from_bytes(self.0.as_ref().get(..size_of::<LiteHeader>())?).ok()
|
||||
}
|
||||
pub fn header_mut(&mut self) -> Option<&mut LiteHeader>
|
||||
where
|
||||
T: AsMut<[u8]>,
|
||||
{
|
||||
bytemuck::try_from_bytes_mut(self.0.as_mut().get_mut(..size_of::<LiteHeader>())?).ok()
|
||||
}
|
||||
|
||||
pub fn payload(&self) -> Option<&[u8]> {
|
||||
let header = self.header()?;
|
||||
self.0
|
||||
.as_ref()
|
||||
.get(size_of::<LiteHeader>() + header.packet_specific_length as usize..)
|
||||
}
|
||||
|
||||
pub fn payload_mut(&mut self) -> Option<&mut [u8]>
|
||||
where
|
||||
T: AsMut<[u8]>,
|
||||
{
|
||||
let len = self.header()?.packet_specific_length;
|
||||
self.0
|
||||
.as_mut()
|
||||
.get_mut(size_of::<LiteHeader>() + len as usize..)
|
||||
}
|
||||
|
||||
pub fn packet_specific_raw(&self) -> Option<&[u8]> {
|
||||
let header = self.header()?;
|
||||
self.0.as_ref().get(
|
||||
size_of::<LiteHeader>()
|
||||
..size_of::<LiteHeader>() + header.packet_specific_length as usize,
|
||||
)
|
||||
}
|
||||
pub fn packet_specific_raw_mut(&mut self) -> Option<&mut [u8]>
|
||||
where
|
||||
T: AsMut<[u8]>,
|
||||
{
|
||||
let len = self.header()?.packet_specific_length;
|
||||
self.0
|
||||
.as_mut()
|
||||
.get_mut(size_of::<LiteHeader>()..size_of::<LiteHeader>() + len as usize)
|
||||
}
|
||||
|
||||
pub fn packet_specific_iter<'a>(&'a self) -> Option<PacketSpecificIter<'a>> {
|
||||
self.packet_specific_raw()
|
||||
.map(Cursor::new)
|
||||
.map(PacketSpecificIter)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_packet_from(
|
||||
header: LiteHeader,
|
||||
specific_data: &[PacketSpecificData],
|
||||
data: &[u8],
|
||||
) -> Vec<u8> {
|
||||
let specific_size: usize = specific_data.iter().map(|v| v.write_size()).sum();
|
||||
let mut packet = LitePacket::new(vec![
|
||||
0u8;
|
||||
size_of::<LiteHeader>() + specific_size + data.len()
|
||||
]);
|
||||
|
||||
*packet.header_mut().expect("packet malformed in creation") = LiteHeader {
|
||||
magic: 0x80,
|
||||
packet_specific_length: specific_size as u8,
|
||||
payload_size: data.len() as u16,
|
||||
..header
|
||||
};
|
||||
|
||||
let mut cursor = Cursor::new(
|
||||
packet
|
||||
.packet_specific_raw_mut()
|
||||
.expect("packet malformed in creation"),
|
||||
);
|
||||
|
||||
for specific in specific_data {
|
||||
specific.write_self(&mut cursor).unwrap();
|
||||
}
|
||||
|
||||
packet
|
||||
.payload_mut()
|
||||
.expect("packet malformed in creation")
|
||||
.copy_from_slice(data);
|
||||
|
||||
packet.0
|
||||
}
|
||||
|
||||
#[derive(Pod, Zeroable, Copy, Clone, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct StreamTypes(u8);
|
||||
|
||||
impl Debug for StreamTypes {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "({},{})", self.source(), self.destination())
|
||||
}
|
||||
}
|
||||
|
||||
impl StreamTypes {
|
||||
pub fn new(source_stream: u8, dest_stream: u8) -> Self {
|
||||
Self((source_stream & 0xF << 4) & dest_stream & 0xF)
|
||||
}
|
||||
|
||||
pub fn source(&self) -> u8 {
|
||||
self.0 >> 4
|
||||
}
|
||||
pub fn destination(&self) -> u8 {
|
||||
self.0 & 0xF
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,15 @@ name = "prudpv0"
|
|||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
||||
rnex-prudp = { path = "../rnex-prudp" }
|
||||
tokio = { version = "1.47.0", features = ["full"] }
|
||||
bytemuck = { version = "1.23.1", features = ["derive"] }
|
||||
typenum = "1.18.0"
|
||||
rc4 = "0.1.0"
|
||||
log = "0.4.25"
|
||||
cfg-if = "1.0.4"
|
||||
proxy-common = {path = "../proxy-common"}
|
||||
hmac = "0.12.1"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ name = "prudpv1"
|
|||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
|
||||
bytemuck = { version = "1.23.1", features = ["derive"] }
|
||||
tokio = { version = "1.47.0", features = ["full"] }
|
||||
hmac = "0.12.1"
|
||||
|
|
@ -11,11 +15,11 @@ md-5 = "^0.10.6"
|
|||
rc4 = "0.1.0"
|
||||
v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" }
|
||||
thiserror = "2.0.12"
|
||||
log = "0.4.27"
|
||||
async-trait = "0.1.88"
|
||||
typenum = "1.18.0"
|
||||
once_cell = "1.21.3"
|
||||
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
||||
rnex-prudp = { path = "../rnex-prudp" }
|
||||
rnex-util = { path = "../rnex-util" }
|
||||
proxy-common = {path = "../proxy-common"}
|
||||
cfg-if = "1.0.4"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use crate::prudp::packet::PRUDPV1Packet;
|
|||
use crate::prudp::router::Error::VirtualPortTaken;
|
||||
use crate::prudp::socket::{AnyInternalSocket, CryptoHandler, ExternalSocket, new_socket_pair};
|
||||
use log::{error, info};
|
||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||
use std::io;
|
||||
use std::io::Cursor;
|
||||
use std::marker::PhantomData;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,6 @@ use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance};
|
|||
use hmac::digest::consts::U32;
|
||||
use rc4::cipher::StreamCipherCoreWrapper;
|
||||
use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher};
|
||||
use rnex_core::PID;
|
||||
use rnex_core::nex::account::Account;
|
||||
use rnex_core::prudp::encryption::EncryptionPair;
|
||||
use rnex_core::prudp::ticket::read_secure_connection_data;
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use typenum::U5;
|
||||
|
||||
type Rc4U32 = StreamCipherCoreWrapper<Rc4Core<U32>>;
|
||||
|
|
|
|||
|
|
@ -6,12 +6,6 @@ use async_trait::async_trait;
|
|||
use log::error;
|
||||
use log::{info, warn};
|
||||
use rc4::StreamCipher;
|
||||
use rnex_core::PID;
|
||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||
use rnex_core::prudp::types_flags::TypesFlags;
|
||||
use rnex_core::prudp::types_flags::flags::{ACK, HAS_SIZE, MULTI_ACK, NEED_ACK, RELIABLE};
|
||||
use rnex_core::prudp::types_flags::types::{CONNECT, DATA, DISCONNECT, PING, SYN};
|
||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::io::Cursor;
|
||||
use std::marker::PhantomData;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::prudp::packet::PRUDPV1Packet;
|
||||
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance};
|
||||
use rc4::{KeyInit, Rc4, StreamCipher};
|
||||
use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair};
|
||||
use rnex_prudp::encryption::{DEFAULT_KEY, EncryptionPair};
|
||||
use typenum::U5;
|
||||
|
||||
pub struct Unsecure(pub &'static str);
|
||||
|
||||
pub struct UnsecureInstance {
|
||||
key: &'static str,
|
||||
streams: Vec<EncryptionPair<Rc4<U5>>>,
|
||||
streams: Vec<EncryptionPair<Rc4>>,
|
||||
self_signature: [u8; 16],
|
||||
#[allow(dead_code)]
|
||||
remote_signature: [u8; 16],
|
||||
|
|
@ -32,7 +32,11 @@ impl CryptoHandler for Unsecure {
|
|||
Vec::new(),
|
||||
UnsecureInstance {
|
||||
streams: (0..substream_count)
|
||||
.map(|_| EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)))
|
||||
.map(|_| {
|
||||
EncryptionPair::init_both(|| {
|
||||
Rc4::new_from_slice(DEFAULT_KEY).expect("invalid key length")
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
key: self.0,
|
||||
remote_signature,
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@ name = "rnex-core"
|
|||
version = "0.1.1"
|
||||
edition = "2024"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
bytemuck = { version = "1.21.0", features = ["derive"] }
|
||||
dotenv = "0.15.0"
|
||||
once_cell = "1.20.2"
|
||||
rc4 = "0.1.0"
|
||||
thiserror = "2.0.11"
|
||||
v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" }
|
||||
simplelog = "0.12.2"
|
||||
chrono = "0.4.39"
|
||||
log = "0.4.25"
|
||||
rand = "0.10.0"
|
||||
cfg-if = "1.0.4"
|
||||
hmac = "0.12.1"
|
||||
|
|
@ -20,7 +20,7 @@ md-5 = "^0.10.6"
|
|||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
hex = "0.4.3"
|
||||
|
||||
macros = { path = "../macros" }
|
||||
rnex-rmc = { path = "../rnex-rmc" }
|
||||
paste = "1.0.15"
|
||||
typenum = "1.18.0"
|
||||
json = "0.12.4"
|
||||
|
|
@ -39,7 +39,7 @@ async-trait = "0.1.89"
|
|||
ctor = "1.0.7"
|
||||
nex-account = { version = "0.2.1", registry = "spbr" }
|
||||
tonic = "0.14.6"
|
||||
tracing = { version = "0.1.44", features = ["log"] }
|
||||
tracing = { version = "0.1.44" }
|
||||
tracing-subscriber = "0.3.23"
|
||||
sentry-tracing = "0.48.4"
|
||||
sentry = { version = "0.48.4", features = ["tracing"] }
|
||||
|
|
@ -52,8 +52,8 @@ rmc_struct_header = []
|
|||
guest_login = []
|
||||
friends = ["guest_login", "database-support"]
|
||||
big_pid = []
|
||||
v3-3-2 = []
|
||||
third-notif-param = []
|
||||
v3-3-2 = []
|
||||
v3-4-0 = ["v3-3-2", "third-notif-param", "rmc_struct_header"]
|
||||
v3-5-0 = ["v3-4-0"]
|
||||
v3-8-15 = ["v3-5-0"]
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
use crate::reggie::UnitPacketRead;
|
||||
use cfg_if::cfg_if;
|
||||
use log::error;
|
||||
use once_cell::sync::Lazy;
|
||||
use rnex_core::nex::account::Account;
|
||||
use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection};
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
|
|
@ -13,6 +11,7 @@ use std::io::{Cursor, Read, Write};
|
|||
use std::net::{Ipv4Addr, SocketAddrV4, TcpStream};
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpListener;
|
||||
use tracing::error;
|
||||
|
||||
const IP_REQ_SERVICE_URLS: &[(&str, &str, &str)] = &[
|
||||
("ipinfo.io:80", "ipinfo.io", "/ip"),
|
||||
|
|
@ -70,12 +69,12 @@ pub fn try_get_ip() -> Option<Ipv4Addr> {
|
|||
let mut stream = TcpStream::connect(url.0)?;
|
||||
stream.write_all(
|
||||
format!(
|
||||
r#"GET {} HTTP/1.0
|
||||
"GET {} HTTP/1.0
|
||||
Host: {}
|
||||
User-Agent: RNEX
|
||||
Accept: */*
|
||||
|
||||
"#,
|
||||
",
|
||||
url.2, url.1
|
||||
)
|
||||
.as_str()
|
||||
|
|
@ -95,37 +94,37 @@ Accept: */*
|
|||
None
|
||||
}
|
||||
|
||||
pub static OWN_IP_PRIVATE: Lazy<Ipv4Addr> = Lazy::new(|| {
|
||||
pub static OWN_IP_PRIVATE: LazyLock<Ipv4Addr> = LazyLock::new(|| {
|
||||
env::var("SERVER_IP")
|
||||
.ok()
|
||||
.map(|s| s.parse().expect("invalid ip address"))
|
||||
.unwrap_or(Ipv4Addr::UNSPECIFIED)
|
||||
});
|
||||
|
||||
pub static OWN_IP_PUBLIC: Lazy<Ipv4Addr> = Lazy::new(|| {
|
||||
pub static OWN_IP_PUBLIC: LazyLock<Ipv4Addr> = LazyLock::new(|| {
|
||||
env::var("SERVER_IP_PUBLIC")
|
||||
.ok()
|
||||
.map(|s| s.parse().expect("invalid ip address"))
|
||||
.unwrap_or_else(|| try_get_ip().unwrap())
|
||||
});
|
||||
|
||||
pub static SERVER_PORT: Lazy<u16> = Lazy::new(|| {
|
||||
pub static SERVER_PORT: LazyLock<u16> = LazyLock::new(|| {
|
||||
env::var("SERVER_PORT")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(10000)
|
||||
});
|
||||
|
||||
pub static KERBEROS_SERVER_PASSWORD: Lazy<String> = Lazy::new(|| {
|
||||
pub static KERBEROS_SERVER_PASSWORD: LazyLock<String> = LazyLock::new(|| {
|
||||
env::var("AUTH_SERVER_PASSWORD")
|
||||
.ok()
|
||||
.unwrap_or("password".to_owned())
|
||||
});
|
||||
|
||||
pub static AUTH_SERVER_ACCOUNT: Lazy<Account> =
|
||||
Lazy::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD));
|
||||
pub static SECURE_SERVER_ACCOUNT: Lazy<Account> =
|
||||
Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
|
||||
pub static AUTH_SERVER_ACCOUNT: LazyLock<Account> =
|
||||
LazyLock::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD));
|
||||
pub static SECURE_SERVER_ACCOUNT: LazyLock<Account> =
|
||||
LazyLock::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
|
||||
|
||||
pub async fn new_simple_backend<T: RmcCallable + Sync + Send + 'static, F>(mut creation_function: F)
|
||||
where
|
||||
|
|
@ -4,8 +4,8 @@ use std::{
|
|||
sync::{Arc, atomic::AtomicU32},
|
||||
};
|
||||
|
||||
use log::error;
|
||||
use tokio::net::TcpListener;
|
||||
use tracing::error;
|
||||
|
||||
use crate::{
|
||||
executables::common::{OWN_IP_PRIVATE, SERVER_PORT},
|
||||
|
|
@ -11,8 +11,6 @@ pub type PID = i32;
|
|||
|
||||
pub use ctor::ctor;
|
||||
|
||||
extern crate self as rnex_core;
|
||||
|
||||
pub mod prudp;
|
||||
pub mod rmc;
|
||||
//mod protocols;
|
||||
|
|
@ -23,12 +21,6 @@ pub mod grpc;
|
|||
pub mod kerberos;
|
||||
pub mod nex;
|
||||
pub mod reggie;
|
||||
pub mod result;
|
||||
pub mod rnex_proxy_common;
|
||||
pub mod util;
|
||||
pub mod versions;
|
||||
pub use macros::*;
|
||||
|
||||
pub mod config {
|
||||
pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header");
|
||||
}
|
||||
|
|
@ -23,10 +23,10 @@ pub async fn get_station_urls(
|
|||
|
||||
for station in station_urls {
|
||||
let is_public = station.options.iter().any(|v| {
|
||||
if let NatType(v) = v {
|
||||
if *v & PUBLIC != 0 {
|
||||
return true;
|
||||
}
|
||||
if let NatType(v) = v
|
||||
&& *v & PUBLIC != 0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
false
|
||||
});
|
||||
|
|
@ -63,14 +63,16 @@ pub async fn get_station_urls(
|
|||
} else {
|
||||
let mut public_station = private_station.clone();
|
||||
|
||||
public_station.options.retain(|v| match v {
|
||||
Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false,
|
||||
_ => true,
|
||||
public_station.options.retain(|v| {
|
||||
!matches!(
|
||||
v,
|
||||
Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_)
|
||||
)
|
||||
});
|
||||
|
||||
public_station
|
||||
.options
|
||||
.push(Address(addr.regular_socket_addr.ip().clone()));
|
||||
.push(Address(addr.regular_socket_addr.ip()));
|
||||
public_station
|
||||
.options
|
||||
.push(Port(addr.regular_socket_addr.port()));
|
||||
|
|
@ -84,10 +86,9 @@ pub async fn get_station_urls(
|
|||
let both = [&mut public_station, &mut private_station];
|
||||
|
||||
for station in both {
|
||||
station.options.retain(|v| match v {
|
||||
PrincipalID(_) | RVConnectionID(_) => false,
|
||||
_ => true,
|
||||
});
|
||||
station
|
||||
.options
|
||||
.retain(|v| !matches!(v, PrincipalID(_) | RVConnectionID(_)));
|
||||
|
||||
station.options.push(PrincipalID(pid));
|
||||
station.options.push(RVConnectionID(cid));
|
||||
|
|
@ -96,3 +97,7 @@ pub async fn get_station_urls(
|
|||
|
||||
Ok(vec![public_station])
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(feature = "database-support")]
|
||||
fn test() {}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use std::convert;
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use crate::rmc::protocols::datastore::DataStoreGetCustomRankingParam;
|
||||
use chrono::Utc;
|
||||
use futures::TryStreamExt;
|
||||
use futures::future::join_all;
|
||||
use rnex_core::PID;
|
||||
|
|
@ -15,16 +15,17 @@ use rnex_core::rmc::protocols::datastore::{
|
|||
};
|
||||
use rnex_core::rmc::protocols::datastore::{
|
||||
BufferQueueParam, CompletePostParam, DataStoreChangeMetaParam, DataStoreCustomRankingResult,
|
||||
DataStoreGetCustomRankingByDataIDParam, DataStorePrepareGetParam, DataStoreReqGetInfo,
|
||||
DataStoreSearchParam, GetMetaInfo, GetMetaParam, KeyValue, Permission, PersistenceTarget,
|
||||
RateCustomRankingParam, RatingInfo, RatingInfoWithSlot, RatingInitParamWithSlot,
|
||||
DataStoreDeleteParam, DataStoreFileServerObjectInfo, DataStoreGetCourseRecordParam,
|
||||
DataStoreGetCourseRecordResult, DataStoreReportCourseParam, DataStoreUploadCourseRecordParam
|
||||
DataStoreGetCourseRecordResult, DataStoreGetCustomRankingByDataIDParam,
|
||||
DataStorePrepareGetParam, DataStoreReportCourseParam, DataStoreReqGetInfo,
|
||||
DataStoreSearchParam, DataStoreUploadCourseRecordParam, GetMetaInfo, GetMetaParam, KeyValue,
|
||||
Permission, PersistenceTarget, RateCustomRankingParam, RatingInfo, RatingInfoWithSlot,
|
||||
RatingInitParamWithSlot,
|
||||
};
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_core::rmc::structures::qbuffer::QBuffer;
|
||||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
use crate::rmc::protocols::datastore::DataStoreGetCustomRankingParam;
|
||||
use std::convert;
|
||||
|
||||
fn map_row_to_meta_info(
|
||||
row_data_id: i64,
|
||||
|
|
@ -324,7 +325,7 @@ fn filter_properties_by_result_option(meta_info: &mut GetMetaInfo, result_option
|
|||
|
||||
async fn init_object_rating_slot(data_id: i64, rating_param: RatingInitParamWithSlot) {
|
||||
log::info!("running init object rating slot");
|
||||
let row = sqlx::query!(
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO datastore.object_ratings (
|
||||
data_id,
|
||||
|
|
@ -610,7 +611,7 @@ async fn rate_object(
|
|||
|
||||
let rating = RatingInfo::default();
|
||||
|
||||
let row = sqlx::query!(
|
||||
sqlx::query!(
|
||||
r#"
|
||||
UPDATE datastore.object_ratings
|
||||
SET total_value=total_value+$1, count=count+1
|
||||
|
|
@ -690,7 +691,7 @@ async fn get_rating_with_slot_data_id(dataid: i64) -> Result<Vec<RatingInfoWithS
|
|||
pub async fn insert_buffer(dataid: i64, slot: i32, buffer: &QBuffer) {
|
||||
let db_now = Utc::now().naive_utc();
|
||||
|
||||
let row = sqlx::query!(
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO datastore.buffer_queues (
|
||||
data_id,
|
||||
|
|
@ -914,52 +915,65 @@ impl DataStore for User {
|
|||
|
||||
let config = match appid {
|
||||
0 => vec![
|
||||
0x00000001,
|
||||
0x00000032,
|
||||
0x00000096,
|
||||
0x0000012c,
|
||||
0x000001f4,
|
||||
0x00000320,
|
||||
0x00000514,
|
||||
0x000007d0,
|
||||
0x00000bb8,
|
||||
0x00001388,
|
||||
0x0000_0001,
|
||||
0x0000_0032,
|
||||
0x0000_0096,
|
||||
0x0000_012c,
|
||||
0x0000_01f4,
|
||||
0x0000_0320,
|
||||
0x0000_0514,
|
||||
0x0000_07d0,
|
||||
0x0000_0bb8,
|
||||
0x0000_1388,
|
||||
MAX_COURSE_UPLOADS,
|
||||
0x00000014,
|
||||
0x0000001e,
|
||||
0x00000028,
|
||||
0x00000032,
|
||||
0x0000003c,
|
||||
0x00000046,
|
||||
0x00000050,
|
||||
0x0000005a,
|
||||
0x00000064,
|
||||
0x00000023,
|
||||
0x0000004b,
|
||||
0x00000023,
|
||||
0x0000004b,
|
||||
0x00000032,
|
||||
0x00000000,
|
||||
0x00000003,
|
||||
0x00000003,
|
||||
0x00000064,
|
||||
0x00000006,
|
||||
0x00000001,
|
||||
0x00000060,
|
||||
0x00000005,
|
||||
0x00000060,
|
||||
0x00000000,
|
||||
0x000007e4,
|
||||
0x00000001,
|
||||
0x00000001,
|
||||
0x0000000c,
|
||||
0x00000000,
|
||||
0x0000_0014,
|
||||
0x0000_001e,
|
||||
0x0000_0028,
|
||||
0x0000_0032,
|
||||
0x0000_003c,
|
||||
0x0000_0046,
|
||||
0x0000_0050,
|
||||
0x0000_005a,
|
||||
0x0000_0064,
|
||||
0x0000_0023,
|
||||
0x0000_004b,
|
||||
0x0000_0023,
|
||||
0x0000_004b,
|
||||
0x0000_0032,
|
||||
0x0000_0000,
|
||||
0x0000_0003,
|
||||
0x0000_0003,
|
||||
0x0000_0064,
|
||||
0x0000_0006,
|
||||
0x0000_0001,
|
||||
0x0000_0060,
|
||||
0x0000_0005,
|
||||
0x0000_0060,
|
||||
0x0000_0000,
|
||||
0x0000_07e4,
|
||||
0x0000_0001,
|
||||
0x0000_0001,
|
||||
0x0000_000c,
|
||||
0x0000_0000,
|
||||
],
|
||||
1 => vec![
|
||||
2, 1770179696, 1770179664, 1770179640, 1770180827, 1770180777, 1770180745,
|
||||
1770177625, 1770177590,
|
||||
2,
|
||||
1_770_179_696,
|
||||
1_770_179_664,
|
||||
1_770_179_640,
|
||||
1_770_180_827,
|
||||
1_770_180_777,
|
||||
1_770_180_745,
|
||||
1_770_177_625,
|
||||
1_770_177_590,
|
||||
],
|
||||
2 => vec![
|
||||
0x0000_07df,
|
||||
0x0000_000c,
|
||||
0x0000_0016,
|
||||
0x0000_0005,
|
||||
0x0000_0000,
|
||||
],
|
||||
2 => vec![0x000007df, 0x0000000c, 0x00000016, 0x00000005, 0x00000000],
|
||||
10 => vec![35, 75, 96, 40, 5, 6],
|
||||
_ => {
|
||||
log::error!("unknown SMM app id: {}", appid);
|
||||
|
|
@ -1489,7 +1503,7 @@ impl DataStore for User {
|
|||
.map(KerberosDateTime::from_naive)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut meta_info = GetMetaInfo {
|
||||
let meta_info = GetMetaInfo {
|
||||
dataid: row.data_id,
|
||||
owner: row.owner.unwrap_or(0),
|
||||
size: row.size.unwrap_or(0) as u32,
|
||||
|
|
@ -1529,7 +1543,7 @@ impl DataStore for User {
|
|||
) -> Result<(), ErrorCode> {
|
||||
let now = Utc::now().naive_utc();
|
||||
|
||||
let row = sqlx::query!(
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO datastore.course_records (
|
||||
data_id,
|
||||
|
|
@ -1667,12 +1681,18 @@ impl DataStore for User {
|
|||
&self,
|
||||
application_id: u32,
|
||||
) -> Result<bool, ErrorCode> {
|
||||
// official servers always return true? application ID is always 0 as far as i know. maybe a check is warranted for the app id?
|
||||
Ok(true)
|
||||
if application_id == 0 {
|
||||
Ok(true)
|
||||
} else {
|
||||
Err(ErrorCode::Core_Unknown)
|
||||
}
|
||||
}
|
||||
|
||||
async fn report_course(&self, report_course_param: DataStoreReportCourseParam) -> Result<(), ErrorCode> {
|
||||
let row = sqlx::query!(
|
||||
async fn report_course(
|
||||
&self,
|
||||
report_course_param: DataStoreReportCourseParam,
|
||||
) -> Result<(), ErrorCode> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO datastore.reports (
|
||||
data_id,
|
||||
|
|
@ -1688,12 +1708,12 @@ impl DataStore for User {
|
|||
report_course_param.report_category as i16,
|
||||
report_course_param.report_reason
|
||||
)
|
||||
.execute(get_db())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
ErrorCode::Core_NotImplemented // i don't know why, but returning this makes the game show "Report sent OK" so i'll use it
|
||||
})?;
|
||||
.execute(get_db())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
ErrorCode::Core_NotImplemented // i don't know why, but returning this makes the game show "Report sent OK" so i'll use it
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1707,12 +1727,12 @@ impl DataStore for User {
|
|||
"#,
|
||||
param.dataid
|
||||
)
|
||||
.fetch_one(get_db())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
ErrorCode::DataStore_NotFound
|
||||
})?;
|
||||
.fetch_one(get_db())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
ErrorCode::DataStore_NotFound
|
||||
})?;
|
||||
|
||||
let passwd = row.update_password;
|
||||
|
||||
|
|
@ -1722,23 +1742,23 @@ impl DataStore for User {
|
|||
|
||||
log::info!("update password check passed");
|
||||
|
||||
let deletequery = sqlx::query!(
|
||||
sqlx::query!(
|
||||
"UPDATE datastore.objects SET deleted=true WHERE data_id=$1",
|
||||
param.dataid
|
||||
)
|
||||
.execute(get_db())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
ErrorCode::DataStore_NotFound
|
||||
})?;
|
||||
.execute(get_db())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
ErrorCode::DataStore_NotFound
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_custom_ranking(
|
||||
&self,
|
||||
param: DataStoreGetCustomRankingParam
|
||||
param: DataStoreGetCustomRankingParam,
|
||||
) -> Result<(Vec<DataStoreCustomRankingResult>, Vec<QResult>), ErrorCode> {
|
||||
let mut ranking_results = Vec::new();
|
||||
|
||||
|
|
@ -1760,12 +1780,12 @@ impl DataStore for User {
|
|||
param.result_range.size as i64,
|
||||
param.result_range.offset as i64,
|
||||
)
|
||||
.fetch_all(get_db())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
ErrorCode::DataStore_NotFound
|
||||
})?;
|
||||
.fetch_all(get_db())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("DB Error: {:?}", e);
|
||||
ErrorCode::DataStore_NotFound
|
||||
})?;
|
||||
|
||||
let mut current_order = param.result_range.offset + 1;
|
||||
|
||||
|
|
@ -1811,7 +1831,12 @@ impl DataStore for User {
|
|||
Ok((ranking_results, q_results))
|
||||
}
|
||||
|
||||
async fn ctr_pickup_course_search_object(&self, course_search_param: DataStoreSearchParam, extra_data: Vec<String>) -> Result<Vec<DataStoreCustomRankingResult>, ErrorCode> {
|
||||
// todo: respect the search parameters and extra data
|
||||
async fn ctr_pickup_course_search_object(
|
||||
&self,
|
||||
_course_search_param: DataStoreSearchParam,
|
||||
_extra_data: Vec<String>,
|
||||
) -> Result<Vec<DataStoreCustomRankingResult>, ErrorCode> {
|
||||
let mut courses = Vec::new();
|
||||
|
||||
let mut stream = sqlx::query!(
|
||||
|
|
@ -1852,7 +1877,7 @@ impl DataStore for User {
|
|||
LIMIT 100
|
||||
"#
|
||||
)
|
||||
.fetch(get_db());
|
||||
.fetch(get_db());
|
||||
|
||||
while let Some(row) = stream.try_next().await.map_err(|e| {
|
||||
eprintln!("stream error: {:?}", e);
|
||||
|
|
@ -1885,7 +1910,7 @@ impl DataStore for User {
|
|||
.map(KerberosDateTime::from_naive)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut meta_info = GetMetaInfo {
|
||||
let meta_info = GetMetaInfo {
|
||||
dataid: row.data_id,
|
||||
owner: row.owner.unwrap_or(0),
|
||||
size: row.size.unwrap_or(0) as u32,
|
||||
|
|
@ -4,26 +4,22 @@ use std::sync::{LazyLock, Weak};
|
|||
use std::time::Duration;
|
||||
use std::{env, mem};
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use log::info;
|
||||
use macros::rmc_struct;
|
||||
use rnex_core::rmc::protocols::account_management::{
|
||||
use crate::rmc::protocols::account_management::{
|
||||
AccountExtraInfo, AccountManagement, RawAccountManagement, RawAccountManagementInfo,
|
||||
RemoteAccountManagement,
|
||||
};
|
||||
use rnex_core::rmc::protocols::friends_3ds::{
|
||||
use crate::rmc::protocols::friends_3ds::{
|
||||
Friends3DS, RawFriends3DS, RawFriends3DSInfo, RemoteFriends3DS,
|
||||
};
|
||||
use rnex_core::rmc::protocols::friends_wiiu::{
|
||||
use crate::rmc::protocols::friends_wiiu::{
|
||||
FriendsWiiU, RawFriendsWiiU, RawFriendsWiiUInfo, RemoteFriendsWiiU,
|
||||
};
|
||||
use rnex_core::rmc::protocols::nintendo_notification::{
|
||||
use crate::rmc::protocols::nintendo_notification::{
|
||||
NintendoNotification, RawNintendoNotification, RawNintendoNotificationInfo,
|
||||
RemoteNintendoNotification,
|
||||
};
|
||||
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||
use rnex_core::{
|
||||
use crate::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||
use crate::{
|
||||
define_rmc_proto,
|
||||
kerberos::KerberosDateTime,
|
||||
nex::common::get_station_urls,
|
||||
|
|
@ -37,20 +33,25 @@ use rnex_core::{
|
|||
structures::{any::Any, qresult::QResult},
|
||||
},
|
||||
};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use rnex_rmc::rmc_struct;
|
||||
use sqlx::query;
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::time::sleep;
|
||||
use tracing::warn;
|
||||
use tracing::{error, info};
|
||||
|
||||
use rnex_core::rmc::protocols::friends_wiiu::{GameKey, MiiV2, PrincipalBasicInfo};
|
||||
use crate::rmc::protocols::friends_wiiu::{GameKey, MiiV2, PrincipalBasicInfo};
|
||||
|
||||
use rnex_core::PID;
|
||||
use crate::PID;
|
||||
|
||||
use rnex_core::rmc::protocols::account_management::NintendoCreateAccountData;
|
||||
use rnex_core::rmc::protocols::nintendo_notification::NintendoNotificationEvent;
|
||||
use crate::rmc::protocols::account_management::NintendoCreateAccountData;
|
||||
use crate::rmc::protocols::nintendo_notification::NintendoNotificationEvent;
|
||||
|
||||
use rnex_core::rmc::structures::data::Data;
|
||||
use crate::rmc::structures::data::Data;
|
||||
|
||||
use crate::executables::common::get_db;
|
||||
|
||||
|
|
@ -61,9 +62,9 @@ use crate::rmc::protocols::friends_3ds::{
|
|||
use crate::rmc::protocols::friends_wiiu::FriendRequestMessage;
|
||||
use crate::rmc::protocols::nintendo_notification::NintendoNotificationEventGeneral;
|
||||
use crate::rmc::response::ErrorCode::FPD_InvalidArgument;
|
||||
use crate::rmc::structures::qbuffer::QBuffer;
|
||||
use nex_account::grpc::ActCreateInfo;
|
||||
use nex_account::{derive_pid_hmac, grpc_client};
|
||||
use rnex_core::rmc::structures::qbuffer::QBuffer;
|
||||
|
||||
define_rmc_proto!(
|
||||
proto FriendsUser{
|
||||
|
|
@ -223,7 +224,7 @@ impl Friends3DS for FriendsUser {
|
|||
let dummy = FriendRelationship {
|
||||
data: Data {},
|
||||
pid: 69,
|
||||
local_friend_code: 3268487429723707977,
|
||||
local_friend_code: 3_268_487_429_723_707_977,
|
||||
relationship_type: 1,
|
||||
};
|
||||
|
||||
|
|
@ -258,7 +259,7 @@ impl Friends3DS for FriendsUser {
|
|||
let dummy = FriendRelationship {
|
||||
data: Data {},
|
||||
pid: 69,
|
||||
local_friend_code: 3268487429723707977,
|
||||
local_friend_code: 3_268_487_429_723_707_977,
|
||||
relationship_type: 1,
|
||||
};
|
||||
|
||||
|
|
@ -275,12 +276,12 @@ impl Friends3DS for FriendsUser {
|
|||
unk2: Vec<u32>,
|
||||
unk3: Vec<u64>,
|
||||
) -> Result<Vec<FriendRelationship>, ErrorCode> {
|
||||
log::info!("params: {:?}, {:?}, {:?}", unk1, unk2, unk3);
|
||||
info!("params: {:?}, {:?}, {:?}", unk1, unk2, unk3);
|
||||
|
||||
let dummy = FriendRelationship {
|
||||
data: Data {},
|
||||
pid: 69,
|
||||
local_friend_code: 3268487429723707977,
|
||||
local_friend_code: 3_268_487_429_723_707_977,
|
||||
relationship_type: 1,
|
||||
};
|
||||
|
||||
|
|
@ -320,10 +321,10 @@ impl Friends3DS for FriendsUser {
|
|||
pid: 69,
|
||||
presence: NintendoPresence {
|
||||
data: Data {},
|
||||
changed_bit_flag: 0xFFFFFFFF,
|
||||
changed_bit_flag: 0xFFFF_FFFF,
|
||||
game_key: rnex_core::rmc::protocols::friends_3ds::GameKey {
|
||||
data: Data {},
|
||||
title_id: 1125899907457280,
|
||||
title_id: 1_125_899_907_457_280,
|
||||
version: 2064,
|
||||
},
|
||||
game_mode_desctiption: "".to_string(),
|
||||
|
|
@ -365,7 +366,7 @@ impl Friends3DS for FriendsUser {
|
|||
platform: 0,
|
||||
game_key: rnex_core::rmc::protocols::friends_3ds::GameKey {
|
||||
data: Data {},
|
||||
title_id: 1125899907457280,
|
||||
title_id: 1_125_899_907_457_280,
|
||||
version: 2064,
|
||||
},
|
||||
message: "yo whats up".to_string(),
|
||||
|
|
@ -603,24 +604,24 @@ impl FriendsWiiU for FriendsUser {
|
|||
let users = self.fm.users.read().await;
|
||||
let user = users.get(&friend.pid).cloned();
|
||||
drop(users);
|
||||
if let Some(user) = user {
|
||||
if let Some(user) = user.upgrade() {
|
||||
let online_presence = user.presence.read().await;
|
||||
if let Some(online_presence) = online_presence.as_ref() {
|
||||
presence = online_presence.clone();
|
||||
} else {
|
||||
println!(
|
||||
"internal server error, user is somehow online and in the friends manager yet has not set their presence yet..."
|
||||
);
|
||||
}
|
||||
drop(online_presence);
|
||||
let mut other_friend_remotes = user.maybe_remote_friend.write().await;
|
||||
other_friend_remotes.insert(self.pid, self.this.clone());
|
||||
drop(other_friend_remotes);
|
||||
let mut remo_friends = self.maybe_remote_friend.write().await;
|
||||
remo_friends.insert(friend.pid, Arc::downgrade(&user));
|
||||
drop(remo_friends);
|
||||
if let Some(user) = user
|
||||
&& let Some(user) = user.upgrade()
|
||||
{
|
||||
let online_presence = user.presence.read().await;
|
||||
if let Some(online_presence) = online_presence.as_ref() {
|
||||
presence = online_presence.clone();
|
||||
} else {
|
||||
println!(
|
||||
"internal server error, user is somehow online and in the friends manager yet has not set their presence yet..."
|
||||
);
|
||||
}
|
||||
drop(online_presence);
|
||||
let mut other_friend_remotes = user.maybe_remote_friend.write().await;
|
||||
other_friend_remotes.insert(self.pid, self.this.clone());
|
||||
drop(other_friend_remotes);
|
||||
let mut remo_friends = self.maybe_remote_friend.write().await;
|
||||
remo_friends.insert(friend.pid, Arc::downgrade(&user));
|
||||
drop(remo_friends);
|
||||
}
|
||||
|
||||
friends.push(FriendInfo {
|
||||
|
|
@ -852,7 +853,7 @@ impl FriendsWiiU for FriendsUser {
|
|||
.process_nintendo_notification_event_1(NintendoNotificationEvent {
|
||||
event_type: 30,
|
||||
sender: pid,
|
||||
data: data,
|
||||
data,
|
||||
})
|
||||
.await;
|
||||
});
|
||||
|
|
@ -865,7 +866,7 @@ impl FriendsWiiU for FriendsUser {
|
|||
friend_request_id: i64::MAX,
|
||||
is_recieved: true,
|
||||
unk: 0,
|
||||
message: message,
|
||||
message,
|
||||
unk2: 1,
|
||||
unk3: "Dummy".into(),
|
||||
game_key,
|
||||
|
|
@ -976,10 +977,9 @@ impl FriendsWiiU for FriendsUser {
|
|||
return Err(ErrorCode::Core_Exception);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("unknown db error occurred");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
}
|
||||
println!("unknown db error occurred");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1100,57 +1100,57 @@ impl FriendsWiiU for FriendsUser {
|
|||
let users = self.fm.users.read().await;
|
||||
let user = users.get(&sender).cloned();
|
||||
drop(users);
|
||||
if let Some(user) = user {
|
||||
if let Some(user) = user.upgrade() {
|
||||
let mut friends = user.friend_pids.write().await;
|
||||
friends.push(self.pid);
|
||||
drop(friends);
|
||||
let mut friends = user.maybe_remote_friend.write().await;
|
||||
friends.insert(self.pid, self.this.clone());
|
||||
drop(friends);
|
||||
if let Some(user) = user
|
||||
&& let Some(user) = user.upgrade()
|
||||
{
|
||||
let mut friends = user.friend_pids.write().await;
|
||||
friends.push(self.pid);
|
||||
drop(friends);
|
||||
let mut friends = user.maybe_remote_friend.write().await;
|
||||
friends.insert(self.pid, self.this.clone());
|
||||
drop(friends);
|
||||
|
||||
let Ok(r) = query!(
|
||||
"select * from nintendo_network_accounts where pid = $1",
|
||||
self.pid
|
||||
)
|
||||
.fetch_one(&mut *tx)
|
||||
.await
|
||||
else {
|
||||
println!("internal server error whilest getting nna info");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
let data = Any::new(&FriendInfo {
|
||||
let Ok(r) = query!(
|
||||
"select * from nintendo_network_accounts where pid = $1",
|
||||
self.pid
|
||||
)
|
||||
.fetch_one(&mut *tx)
|
||||
.await
|
||||
else {
|
||||
println!("internal server error whilest getting nna info");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
};
|
||||
let data = Any::new(&FriendInfo {
|
||||
data: Data {},
|
||||
nna_info: nna_info_from_record!(r),
|
||||
became_friends: KerberosDateTime::now(),
|
||||
comment: Comment {
|
||||
data: Data {},
|
||||
nna_info: nna_info_from_record!(r),
|
||||
became_friends: KerberosDateTime::now(),
|
||||
comment: Comment {
|
||||
data: Data {},
|
||||
last_changed: KerberosDateTime::from_naive(r.comment_lastchanged),
|
||||
message: r.comment_message,
|
||||
unk: (bytemuck::cast::<_, u16>(r.comment_unk) & 0xFF) as u8,
|
||||
},
|
||||
last_online: KerberosDateTime::now(),
|
||||
presence: self.presence.read().await.clone().unwrap_or_default(),
|
||||
unk: 0,
|
||||
last_changed: KerberosDateTime::from_naive(r.comment_lastchanged),
|
||||
message: r.comment_message,
|
||||
unk: (bytemuck::cast::<_, u16>(r.comment_unk) & 0xFF) as u8,
|
||||
},
|
||||
last_online: KerberosDateTime::now(),
|
||||
presence: self.presence.read().await.clone().unwrap_or_default(),
|
||||
unk: 0,
|
||||
})
|
||||
.expect("type error");
|
||||
user.remote
|
||||
.process_nintendo_notification_event_1(NintendoNotificationEvent {
|
||||
event_type: 30,
|
||||
sender: self.pid,
|
||||
data,
|
||||
})
|
||||
.expect("type error");
|
||||
user.remote
|
||||
.process_nintendo_notification_event_1(NintendoNotificationEvent {
|
||||
event_type: 30,
|
||||
sender: self.pid,
|
||||
data: data,
|
||||
})
|
||||
.await;
|
||||
let online_presence = user.presence.read().await;
|
||||
if let Some(online_presence) = online_presence.as_ref() {
|
||||
presence = online_presence.clone();
|
||||
} else {
|
||||
println!(
|
||||
"internal server error, user is somehow online and in the friends manager yet has not set their presence yet..."
|
||||
);
|
||||
}
|
||||
drop(online_presence);
|
||||
.await;
|
||||
let online_presence = user.presence.read().await;
|
||||
if let Some(online_presence) = online_presence.as_ref() {
|
||||
presence = online_presence.clone();
|
||||
} else {
|
||||
println!(
|
||||
"internal server error, user is somehow online and in the friends manager yet has not set their presence yet..."
|
||||
);
|
||||
}
|
||||
drop(online_presence);
|
||||
}
|
||||
|
||||
tx.commit().await.ok();
|
||||
|
|
@ -1483,7 +1483,7 @@ impl FriendsWiiU for FriendsUser {
|
|||
.execute(get_db())
|
||||
.await
|
||||
{
|
||||
println!("internal server error whilest updating mii: {}", e);
|
||||
println!("internal server error whilest updating mii: {e}");
|
||||
return Err(ErrorCode::Core_Exception);
|
||||
}
|
||||
|
||||
|
|
@ -1546,7 +1546,7 @@ impl FriendsWiiU for FriendsUser {
|
|||
let mut principal_infos = Vec::with_capacity(pids.len());
|
||||
|
||||
for pid in pids {
|
||||
println!("looking up pid: {}", pid);
|
||||
println!("looking up pid: {pid}");
|
||||
let Ok(user) = query!(
|
||||
"select * from nintendo_network_accounts where pid = $1",
|
||||
pid
|
||||
|
|
@ -1594,8 +1594,8 @@ impl FriendsWiiU for FriendsUser {
|
|||
.fetch_optional(get_db())
|
||||
.await
|
||||
else {
|
||||
println!("error whilest getting friend requests");
|
||||
return Err(ErrorCode::Core_SystemError);
|
||||
warn!("user requested request setting of invalid user");
|
||||
continue;
|
||||
};
|
||||
|
||||
if denylist.is_some() {
|
||||
|
|
@ -1712,8 +1712,6 @@ impl AccountManagement for FriendsGuest {
|
|||
email: String,
|
||||
auth_data: Any,
|
||||
) -> Result<(PID, String), ErrorCode> {
|
||||
println!("{}, {}, {}, {}", principal_name, key, groups, email);
|
||||
|
||||
let nex_token = if let Ok(extra_info) = auth_data.try_get_as::<AccountExtraInfo>() {
|
||||
extra_info.nex_token
|
||||
} else if let Ok(data) = auth_data.try_get_as::<NintendoCreateAccountData>() {
|
||||
|
|
@ -1722,15 +1720,15 @@ impl AccountManagement for FriendsGuest {
|
|||
return Err(ErrorCode::Authentication_InvalidParam);
|
||||
};
|
||||
let (pid, nex_key) = nex_account::decode_nexact_token(&nex_token).map_err(|e| {
|
||||
log::error!("failed to decode token: {}", e);
|
||||
log::info!("{:?}", nex_token);
|
||||
error!("failed to decode token: {e}");
|
||||
info!("{nex_token:?}");
|
||||
ErrorCode::Authentication_InvalidParam
|
||||
})?;
|
||||
|
||||
//let mac = derive_pid_hmac(data.nna_info.principal_basic_info.pid, &nexkey);
|
||||
|
||||
let mut client = grpc_client().await.map_err(|e| {
|
||||
eprintln!("error occurred: {:?}", e);
|
||||
eprintln!("error occurred: {e:?}");
|
||||
ErrorCode::Core_Unknown
|
||||
})?;
|
||||
|
||||
|
|
@ -1741,23 +1739,23 @@ impl AccountManagement for FriendsGuest {
|
|||
pid,
|
||||
};
|
||||
|
||||
let nexkey = client
|
||||
let nex_key = client
|
||||
.create_new_sequential_or_update_and_get_account(new_account)
|
||||
.await
|
||||
.map_err(|_| ErrorCode::Core_Unknown)?
|
||||
.into_inner();
|
||||
|
||||
if nexkey.key.len() != 16 {
|
||||
log::error!("nex key was not 16 bytes long");
|
||||
if nex_key.key.len() != 16 {
|
||||
error!("nex key was not 16 bytes long");
|
||||
return Err(ErrorCode::Authentication_InvalidParam);
|
||||
}
|
||||
|
||||
let nexkeyarray: [u8; 16] = nexkey.key.try_into().expect("how...?");
|
||||
let nexkeyarray: [u8; 16] = nex_key.key.try_into().expect("how...?");
|
||||
|
||||
let mac = derive_pid_hmac(pid, &nexkeyarray);
|
||||
|
||||
let hex_str = hex::encode(mac);
|
||||
|
||||
return Ok((pid, hex_str));
|
||||
Ok((pid, hex_str))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
use std::borrow::Cow;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
pub fn rnex_release() -> String {
|
||||
let edition_piece = if let Some(e) = option_env!("EDITION") {
|
||||
format!("{}", e)
|
||||
} else {
|
||||
env!("FEATURESET").into()
|
||||
};
|
||||
|
||||
format!(
|
||||
"rnex {} v{}({})",
|
||||
edition_piece,
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
env!("GIT_HASH")
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn with_setup(f: impl AsyncFnOnce()) {
|
||||
println!("setting up logger and dotenv");
|
||||
dotenv::dotenv().ok();
|
||||
let _maybe_sentry = if let Ok(sentry_url) = std::env::var("SENTRY_URL") {
|
||||
Some(sentry::init((
|
||||
sentry_url,
|
||||
sentry::ClientOptions {
|
||||
release: Some(Cow::Owned(rnex_release())),
|
||||
send_default_pii: true,
|
||||
..Default::default()
|
||||
},
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
tracing_subscriber::registry()
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.with(sentry::integrations::tracing::layer())
|
||||
.try_init()
|
||||
.expect("failed to init tracing subscriber");
|
||||
|
||||
f().await;
|
||||
|
||||
/*ctrlc::set_handler(||{
|
||||
FORCE_EXIT.call_once_force(|_|{
|
||||
println!("attempting exit");
|
||||
});
|
||||
}).unwrap();*/
|
||||
}
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
use nex_account::grpc::Pid;
|
||||
use nex_account::grpc::nex_account_service_client::NexAccountServiceClient;
|
||||
use once_cell::sync::Lazy;
|
||||
use rnex_core::PID;
|
||||
use std::array::TryFromSliceError;
|
||||
use std::sync::LazyLock;
|
||||
use std::{env, result};
|
||||
use thiserror::Error;
|
||||
use tokio::task::JoinError;
|
||||
use tonic::transport::Channel;
|
||||
|
||||
static API_KEY: Lazy<String> = Lazy::new(|| {
|
||||
let key = env::var("ACCOUNT_GQL_API_KEY").expect("no graphql ip specified");
|
||||
|
||||
key
|
||||
});
|
||||
|
||||
static CLIENT_URI: Lazy<String> = Lazy::new(|| {
|
||||
env::var("ACCOUNT_GQL_URL")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.expect("no graphql ip specified")
|
||||
});
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
RequestError(#[from] ureq::Error),
|
||||
#[error(transparent)]
|
||||
Json(#[from] json::Error),
|
||||
#[error(transparent)]
|
||||
Status(#[from] tonic::Status),
|
||||
#[error(transparent)]
|
||||
Transport(#[from] tonic::transport::Error),
|
||||
#[error("invalid password size: {0}")]
|
||||
PasswordConversion(#[from] TryFromSliceError),
|
||||
#[error("something happened")]
|
||||
SomethingHappened,
|
||||
#[error("error joining blocking task: {0}")]
|
||||
Join(#[from] JoinError),
|
||||
}
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
static NEX_ACCOUNT_URL: LazyLock<String> =
|
||||
LazyLock::new(|| env::var("NEX_ACCOUNT_ENDPOINT").expect("NEX_ACCOUNT_ENDPOINT not set"));
|
||||
|
||||
pub struct Client(NexAccountServiceClient<Channel>); //(reqwest::Client);
|
||||
|
||||
impl Client {
|
||||
pub async fn new() -> Result<Self> {
|
||||
let client = nex_account::grpc_client().await.unwrap();
|
||||
Ok(Self(client))
|
||||
}
|
||||
|
||||
pub async fn get_nex_key(&mut self, pid: PID) -> Result<[u8; 16]> {
|
||||
let prekey = self.0.get_nex_key_by_pid(Pid { pid }).await?.into_inner();
|
||||
|
||||
log::warn!("prekey is {:?}", prekey);
|
||||
|
||||
let nexkey: [u8; 16] = prekey
|
||||
.key
|
||||
.try_into()
|
||||
.map_err(|_| Error::SomethingHappened)?;
|
||||
|
||||
Ok(nexkey)
|
||||
}
|
||||
|
||||
pub async fn get_user_level(&mut self, _pid: PID) -> Result<i32> {
|
||||
// let req = self
|
||||
// .do_request(object! {
|
||||
// "query": r"query($pid: Int!){
|
||||
// userByPid(pid: $pid){
|
||||
// accountLevel
|
||||
// }
|
||||
// }",
|
||||
// "variables": {
|
||||
// "pid": pid
|
||||
// }
|
||||
// })
|
||||
// .await?;
|
||||
//
|
||||
// let Some(val) = req
|
||||
// .entries()
|
||||
// .find(|v| v.0 == "data")
|
||||
// .ok_or(SomethingHappened)?
|
||||
// .1
|
||||
// .entries()
|
||||
// .find(|v| v.0 == "userByPid")
|
||||
// .ok_or(SomethingHappened)?
|
||||
// .1
|
||||
// .entries()
|
||||
// .find(|v| v.0 == "accountLevel")
|
||||
// .ok_or(SomethingHappened)?
|
||||
// .1
|
||||
// .as_i32()
|
||||
// else {
|
||||
// return Err(SomethingHappened);
|
||||
// };
|
||||
|
||||
// everyone is tester until this is implemented
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
// 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_i32()
|
||||
// else {
|
||||
// return Err(SomethingHappened);
|
||||
// };
|
||||
//
|
||||
// Ok(val)
|
||||
// }
|
||||
|
||||
/*pub async fn get_user_data(&mut self , pid: u32) -> Result<GetUserDataResponse>{
|
||||
let req = Request::new(GetUserDataRequest{
|
||||
pid
|
||||
});
|
||||
|
||||
let response = self.0.get_user_data(req).await?.into_inner();
|
||||
|
||||
Ok(response)
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
pub struct Client(AccountClient<InterceptedService<Channel, InterceptorFunc>>);
|
||||
|
||||
impl Client{
|
||||
pub async fn new() -> Result<Self>{
|
||||
let channel = Channel::from_static(&*CLIENT_URI).connect().await?;
|
||||
|
||||
let func = Box::new(&|mut req: Request<()>|{
|
||||
req.metadata_mut().insert("x-api-key", API_KEY.clone());
|
||||
Ok(req)
|
||||
}) as InterceptorFunc;
|
||||
|
||||
let client = AccountClient::with_interceptor(channel, func);
|
||||
Ok(Self(client))
|
||||
}
|
||||
|
||||
pub async fn get_nex_password(&mut self , pid: u32) -> Result<[u8; 16]>{
|
||||
let req = Request::new(GetNexPasswordRequest{
|
||||
pid
|
||||
});
|
||||
|
||||
let response = self.0.get_nex_password(req).await?.into_inner();
|
||||
|
||||
Ok(response.password.as_bytes().try_into()?)
|
||||
}
|
||||
|
||||
pub async fn get_user_data(&mut self , pid: u32) -> Result<GetUserDataResponse>{
|
||||
let req = Request::new(GetUserDataRequest{
|
||||
pid
|
||||
});
|
||||
|
||||
let response = self.0.get_user_data(req).await?.into_inner();
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
//! Legacy grpc communication server for being able to use this with pretendos infrastructure
|
||||
//! before account rs is finished.
|
||||
//!
|
||||
//! This WILL be deprecated as soon as account rs is in a stable state.
|
||||
//use tonic::{Request, Status};
|
||||
|
||||
//type InterceptorFunc = Box<dyn Fn(Request<()>) -> Result<Request<()>, Status> + Send>;
|
||||
pub mod account;
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
use bytemuck::{Pod, Zeroable, bytes_of};
|
||||
use cfg_if::cfg_if;
|
||||
use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc};
|
||||
use hmac::Hmac;
|
||||
use hmac::Mac;
|
||||
use rc4::KeyInit;
|
||||
use rc4::cipher::StreamCipherCoreWrapper;
|
||||
use rc4::{Rc4, Rc4Core, StreamCipher};
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use std::fmt::Display;
|
||||
use std::io::{Read, Write};
|
||||
use typenum::U16;
|
||||
use typenum::Unsigned;
|
||||
|
||||
use rnex_core::rmc::structures::Result;
|
||||
|
||||
use rnex_core::PID;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "friends")]{
|
||||
pub type SessionLengthTy = U16;
|
||||
} else {
|
||||
use rc4::consts::U32;
|
||||
pub type SessionLengthTy = U32;
|
||||
}
|
||||
}
|
||||
pub const SESSION_KEY_LENGTH: usize = SessionLengthTy::USIZE;
|
||||
|
||||
type Md5Hmac = Hmac<md5::Md5>;
|
||||
|
||||
#[derive(Pod, Zeroable, Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
pub struct KerberosDateTime(pub u64);
|
||||
|
||||
impl Display for KerberosDateTime {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}.{}.{} {}:{}:{}",
|
||||
self.get_year(),
|
||||
self.get_month(),
|
||||
self.get_days(),
|
||||
self.get_hours(),
|
||||
self.get_minutes(),
|
||||
self.get_seconds()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl KerberosDateTime {
|
||||
// this is the time which smm returned as the expriy date, we use it as a
|
||||
// date so far into the future that it might as well just be never more generally
|
||||
pub const PRACTICALLY_NEVER: Self = Self::new(0, 0, 0, 31, 12, 9999);
|
||||
pub fn from_naive(dt: chrono::NaiveDateTime) -> Self {
|
||||
use chrono::Datelike;
|
||||
use chrono::Timelike;
|
||||
Self::new(
|
||||
dt.second() as u64,
|
||||
dt.minute() as u64,
|
||||
dt.hour() as u64,
|
||||
dt.day() as u64,
|
||||
dt.month() as u64,
|
||||
dt.year() as u64,
|
||||
)
|
||||
}
|
||||
|
||||
pub const fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year: u64) -> Self {
|
||||
Self(second | (minute << 6) | (hour << 12) | (day << 17) | (month << 22) | (year << 26))
|
||||
}
|
||||
|
||||
pub fn now() -> Self {
|
||||
let now = chrono::Utc::now();
|
||||
Self::new(
|
||||
now.second() as u64,
|
||||
now.minute() as u64,
|
||||
now.hour() as u64,
|
||||
now.day() as u64,
|
||||
now.month() as u64,
|
||||
now.year() as u64,
|
||||
)
|
||||
}
|
||||
|
||||
pub const fn get_seconds(&self) -> u8 {
|
||||
(self.0 & 0b111111) as u8
|
||||
}
|
||||
|
||||
pub const fn get_minutes(&self) -> u8 {
|
||||
((self.0 >> 6) & 0b111111) as u8
|
||||
}
|
||||
pub const fn get_hours(&self) -> u8 {
|
||||
((self.0 >> 12) & 0b11111) as u8
|
||||
}
|
||||
pub const fn get_days(&self) -> u8 {
|
||||
((self.0 >> 17) & 0b111111) as u8
|
||||
}
|
||||
pub const fn get_month(&self) -> u8 {
|
||||
((self.0 >> 22) & 0b1111) as u8
|
||||
}
|
||||
pub const fn get_year(&self) -> u64 {
|
||||
(self.0 >> 26) & 0xFFFFFFFF
|
||||
}
|
||||
pub fn to_regular_time(&self) -> chrono::DateTime<Utc> {
|
||||
let date = match NaiveDate::from_ymd_opt(
|
||||
self.get_year() as i32,
|
||||
self.get_month() as u32,
|
||||
self.get_days() as u32,
|
||||
) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
println!("invalid datetime...: {}", self);
|
||||
Default::default()
|
||||
}
|
||||
};
|
||||
|
||||
NaiveDateTime::new(
|
||||
date,
|
||||
NaiveTime::from_hms_opt(
|
||||
self.get_hours() as u32,
|
||||
self.get_minutes() as u32,
|
||||
self.get_seconds() as u32,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.and_utc()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for KerberosDateTime {
|
||||
fn default() -> Self {
|
||||
KerberosDateTime(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl RmcSerialize for KerberosDateTime {
|
||||
fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> {
|
||||
Ok(self.0.serialize(writer)?)
|
||||
}
|
||||
|
||||
fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result<Self> {
|
||||
Ok(Self(u64::deserialize(reader)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Pod, Zeroable, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct TicketInternalData {
|
||||
pub issued_time: KerberosDateTime,
|
||||
pub pid: PID,
|
||||
pub session_key: [u8; SESSION_KEY_LENGTH],
|
||||
}
|
||||
|
||||
impl TicketInternalData {
|
||||
pub(crate) fn new(pid: PID) -> Self {
|
||||
Self {
|
||||
issued_time: KerberosDateTime::now(),
|
||||
pid,
|
||||
session_key: rand::random(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]> {
|
||||
let mut data = bytes_of(self).to_vec();
|
||||
|
||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<U16>> = Rc4::new_from_slice(&key).unwrap();
|
||||
rc4.apply_keystream(&mut data);
|
||||
|
||||
let mut hmac = <Md5Hmac as KeyInit>::new_from_slice(&key).unwrap();
|
||||
|
||||
hmac.write_all(&data[..])
|
||||
.expect("failed to write data to hmac");
|
||||
|
||||
let hmac_result = &hmac.finalize().into_bytes()[..];
|
||||
|
||||
data.write_all(&hmac_result)
|
||||
.expect("failed to write data to vec");
|
||||
|
||||
data.into_boxed_slice()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Pod, Zeroable, Debug, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct Ticket {
|
||||
pub session_key: [u8; SESSION_KEY_LENGTH],
|
||||
pub pid: PID,
|
||||
}
|
||||
|
||||
impl Ticket {
|
||||
pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]> {
|
||||
let mut data = bytes_of(self).to_vec();
|
||||
|
||||
internal_data
|
||||
.serialize(&mut data)
|
||||
.expect("unable to write to vec");
|
||||
|
||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<U16>> = Rc4::new_from_slice(&key).unwrap();
|
||||
rc4.apply_keystream(&mut data);
|
||||
|
||||
let mut hmac = <Md5Hmac as KeyInit>::new_from_slice(&key).unwrap();
|
||||
|
||||
hmac.write_all(&data[..])
|
||||
.expect("failed to write data to hmac");
|
||||
|
||||
let hmac_result = &hmac.finalize().into_bytes()[..];
|
||||
|
||||
data.write_all(&hmac_result)
|
||||
.expect("failed to write data to vec");
|
||||
|
||||
data.into_boxed_slice()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::kerberos::KerberosDateTime;
|
||||
|
||||
#[test]
|
||||
fn kerberos_time_convert_test() {
|
||||
let time = KerberosDateTime(135904948834);
|
||||
|
||||
println!("{}", time.to_regular_time().to_rfc2822());
|
||||
|
||||
let time = KerberosDateTime(0x9C3F3E0000);
|
||||
|
||||
println!(
|
||||
"{}.{}.{} {}:{}:{}",
|
||||
time.get_year(),
|
||||
time.get_month(),
|
||||
time.get_days(),
|
||||
time.get_hours(),
|
||||
time.get_minutes(),
|
||||
time.get_seconds()
|
||||
);
|
||||
println!("{}", time.to_regular_time().to_rfc2822());
|
||||
|
||||
assert_eq!(KerberosDateTime::PRACTICALLY_NEVER, time);
|
||||
|
||||
println!("{}", KerberosDateTime(134222053376));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
pub mod encryption;
|
||||
pub mod socket_addr;
|
||||
pub mod station_url;
|
||||
pub mod ticket;
|
||||
pub mod types_flags;
|
||||
pub mod virtual_port;
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
use crate::define_rmc_proto;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use std::io;
|
||||
use std::net::SocketAddrV4;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
|
||||
pub trait UnitPacketRead: AsyncRead + Unpin {
|
||||
async fn read_buffer(&mut self) -> Result<Vec<u8>, io::Error> {
|
||||
let mut len_raw: [u8; 4] = [0; 4];
|
||||
|
||||
self.read_exact(&mut len_raw).await?;
|
||||
|
||||
let len = u32::from_le_bytes(len_raw);
|
||||
|
||||
let mut vec = vec![0u8; len as _];
|
||||
|
||||
self.read_exact(&mut vec).await?;
|
||||
|
||||
Ok(vec)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncRead + Unpin> UnitPacketRead for T {}
|
||||
pub trait UnitPacketWrite: AsyncWrite + Unpin {
|
||||
async fn send_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> {
|
||||
let mut dest_data = Vec::new();
|
||||
|
||||
data.serialize(&mut dest_data)
|
||||
.expect("ran out of memory or something");
|
||||
|
||||
self.write_all(&dest_data[..]).await?;
|
||||
|
||||
self.flush().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite + Unpin> UnitPacketWrite for T {}
|
||||
|
||||
#[rmc_proto(1)]
|
||||
pub trait EdgeNodeManagement {
|
||||
#[method_id(1)]
|
||||
async fn get_url(&self, seed: u64) -> Result<SocketAddrV4, ErrorCode>;
|
||||
}
|
||||
|
||||
define_rmc_proto!(
|
||||
proto EdgeNodeHolder{
|
||||
EdgeNodeManagement
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(RmcSerialize, Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum EdgeNodeHolderConnectOption {
|
||||
DontRegister = 0,
|
||||
Register(SocketAddrV4) = 1,
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
pub mod message;
|
||||
pub mod structures;
|
||||
pub mod response;
|
||||
pub mod protocols;
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
use macros::{method_id, rmc_proto};
|
||||
use rnex_core::prudp::station_url::StationUrl;
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
|
||||
use rnex_core::PID;
|
||||
|
||||
use crate::rmc::structures::any::Any;
|
||||
use crate::rmc::structures::matchmake::Gathering;
|
||||
|
||||
#[rmc_proto(21)]
|
||||
pub trait Matchmake {
|
||||
#[method_id(2)]
|
||||
async fn unregister_gathering(&self, gid: u32) -> Result<bool, ErrorCode>;
|
||||
#[method_id(21)]
|
||||
async fn find_by_single_id(&self, gid: u32) -> Result<(bool, Any<Gathering>), ErrorCode>;
|
||||
#[method_id(41)]
|
||||
async fn get_session_urls(&self, gid: u32) -> Result<Vec<StationUrl>, ErrorCode>;
|
||||
#[method_id(42)]
|
||||
async fn update_session_host(&self, gid: u32, change_owner: bool) -> Result<(), ErrorCode>;
|
||||
#[method_id(44)]
|
||||
async fn migrate_gathering_ownership(
|
||||
&self,
|
||||
gid: u32,
|
||||
candidates: Vec<PID>,
|
||||
participants_only: bool,
|
||||
) -> Result<(), ErrorCode>;
|
||||
}
|
||||
|
|
@ -1,371 +0,0 @@
|
|||
#![allow(async_fn_in_trait)]
|
||||
|
||||
pub mod account_management;
|
||||
pub mod auth;
|
||||
pub mod datastore;
|
||||
pub mod friends_3ds;
|
||||
pub mod friends_wiiu;
|
||||
pub mod matchmake;
|
||||
pub mod matchmake_ext;
|
||||
pub mod matchmake_extension;
|
||||
pub mod message_delivery;
|
||||
pub mod messaging;
|
||||
pub mod nat_traversal;
|
||||
pub mod nintendo_notification;
|
||||
pub mod notifications;
|
||||
pub mod ranking;
|
||||
pub mod secure;
|
||||
pub mod util;
|
||||
|
||||
use crate::result::ResultExtension;
|
||||
use crate::rmc::message::RMCMessage;
|
||||
use crate::rmc::protocols::RemoteCallError::ConnectionBroke;
|
||||
use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult};
|
||||
use crate::rmc::structures;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
use crate::util::{SendingBufferConnection, SplittableBufferConnection};
|
||||
use log::{error, info};
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::io::Cursor;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::{Mutex, Notify};
|
||||
use tokio::time::{Instant, sleep, sleep_until};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum RemoteCallError {
|
||||
#[error("Call to remote timed out whilst waiting on response.")]
|
||||
Timeout,
|
||||
#[error("A server side rmc error occurred: {0:?}")]
|
||||
ServerError(ErrorCode),
|
||||
#[error("Connection broke")]
|
||||
ConnectionBroke,
|
||||
#[error("Error reading response data: {0}")]
|
||||
InvalidResponse(#[from] structures::Error),
|
||||
}
|
||||
|
||||
pub struct RmcConnection(pub SendingBufferConnection, pub RmcResponseReceiver);
|
||||
|
||||
pub struct RmcResponseReceiver(Arc<Notify>, Arc<Mutex<HashMap<u32, RMCResponse>>>);
|
||||
|
||||
impl RmcConnection {
|
||||
pub async fn make_raw_call<T: RmcSerialize>(
|
||||
&self,
|
||||
message: &RMCMessage,
|
||||
) -> Result<T, RemoteCallError> {
|
||||
self.make_raw_call_no_response(message).await?;
|
||||
|
||||
let data = self.1.get_response_data(message.call_id).await?;
|
||||
|
||||
let out = <T as RmcSerialize>::deserialize(&mut Cursor::new(data))?;
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub async fn make_raw_call_no_response(
|
||||
&self,
|
||||
message: &RMCMessage,
|
||||
) -> Result<(), RemoteCallError> {
|
||||
let message_data = message.to_data();
|
||||
|
||||
self.0.send(message_data).await.ok_or(ConnectionBroke)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn disconnect(&self) {
|
||||
self.0.disconnect().await;
|
||||
}
|
||||
}
|
||||
|
||||
impl RmcResponseReceiver {
|
||||
// returns none if timed out
|
||||
pub async fn get_response_data(&self, call_id: u32) -> Result<Vec<u8>, RemoteCallError> {
|
||||
let mut end_wait_time = Instant::now();
|
||||
end_wait_time += Duration::from_secs(5);
|
||||
|
||||
let sleep_fut = sleep_until(end_wait_time);
|
||||
tokio::pin!(sleep_fut);
|
||||
|
||||
let mut sleep_manual_unlock_fut = Instant::now();
|
||||
sleep_manual_unlock_fut += Duration::from_secs(4);
|
||||
|
||||
let sleep_manual_unlock_fut = sleep_until(sleep_manual_unlock_fut);
|
||||
tokio::pin!(sleep_manual_unlock_fut);
|
||||
|
||||
loop {
|
||||
let mut locked = self.1.lock().await;
|
||||
|
||||
if let Some(v) = locked.remove(&call_id) {
|
||||
match v.response_result {
|
||||
RMCResponseResult::Success { data, .. } => return Ok(data),
|
||||
RMCResponseResult::Error { error_code, .. } => {
|
||||
return Err(RemoteCallError::ServerError(error_code));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drop(locked);
|
||||
|
||||
let notif_fut = self.0.notified();
|
||||
|
||||
tokio::select! {
|
||||
_ = &mut sleep_manual_unlock_fut => {
|
||||
continue;
|
||||
}
|
||||
_ = &mut sleep_fut => {
|
||||
return Err(RemoteCallError::Timeout);
|
||||
}
|
||||
_ = notif_fut => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasRmcConnection {
|
||||
fn get_connection(&self) -> &RmcConnection;
|
||||
}
|
||||
|
||||
pub trait RemoteObject {
|
||||
fn new(conn: RmcConnection) -> Self;
|
||||
}
|
||||
|
||||
impl RemoteObject for () {
|
||||
fn new(_: RmcConnection) -> Self {}
|
||||
}
|
||||
|
||||
pub trait RmcCallable {
|
||||
//type Remote: RemoteObject;
|
||||
fn rmc_call(
|
||||
&self,
|
||||
responder: &SendingBufferConnection,
|
||||
protocol_id: u16,
|
||||
method_id: u32,
|
||||
call_id: u32,
|
||||
rest: Vec<u8>,
|
||||
) -> impl std::future::Future<Output = ()> + Send;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_rmc_proto {
|
||||
(proto $name:ident{
|
||||
$($protocol:path),*
|
||||
}) => {
|
||||
paste::paste!{
|
||||
#[allow(unused_variables)]
|
||||
pub trait [<Local $name>]: std::any::Any $( + [<Raw $protocol>] + $protocol)* {
|
||||
async fn rmc_call(&self, remote_response_connection: &rnex_core::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>){
|
||||
match protocol_id{
|
||||
$(
|
||||
[<Raw $protocol Info>]::PROTOCOL_ID => <Self as [<Raw $protocol>]>::rmc_call_proto(self, remote_response_connection, method_id, call_id, rest).await,
|
||||
)*
|
||||
v => log::error!("invalid protocol called on rmc object {}", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct [<Remote $name>](rnex_core::rmc::protocols::RmcConnection);
|
||||
|
||||
impl rnex_core::rmc::protocols::RmcPureRemoteObject for [<Remote $name>]{
|
||||
fn new(conn: rnex_core::rmc::protocols::RmcConnection) -> Self{
|
||||
Self(conn)
|
||||
}
|
||||
}
|
||||
|
||||
impl rnex_core::rmc::protocols::RemoteDisconnectable for [<Remote $name>]{
|
||||
|
||||
async fn disconnect(&self){
|
||||
self.0.disconnect().await;
|
||||
}
|
||||
}
|
||||
|
||||
impl rnex_core::rmc::protocols::HasRmcConnection for [<Remote $name>]{
|
||||
fn get_connection(&self) -> &rnex_core::rmc::protocols::RmcConnection{
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
impl [<Remote $protocol>] for [<Remote $name>]{}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// This is a special case to allow unit to represent the fact that no object is represented.
|
||||
impl RmcCallable for () {
|
||||
async fn rmc_call(
|
||||
&self,
|
||||
_remote_response_connection: &SendingBufferConnection,
|
||||
_protocol_id: u16,
|
||||
_method_id: u32,
|
||||
_call_id: u32,
|
||||
_rest: Vec<u8>,
|
||||
) {
|
||||
//todo: maybe reply with not implemented(?)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RmcPureRemoteObject {
|
||||
fn new(conn: RmcConnection) -> Self;
|
||||
}
|
||||
|
||||
pub trait RemoteDisconnectable {
|
||||
async fn disconnect(&self);
|
||||
}
|
||||
|
||||
pub struct OnlyRemote<T: RemoteDisconnectable>(T);
|
||||
|
||||
impl<T: RemoteDisconnectable + RmcPureRemoteObject> OnlyRemote<T> {
|
||||
pub fn new(conn: RmcConnection) -> Self {
|
||||
Self(T::new(conn))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RemoteDisconnectable> Deref for OnlyRemote<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RemoteDisconnectable> OnlyRemote<T> {
|
||||
pub async fn disconnect(&self) {
|
||||
self.0.disconnect().await;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RemoteDisconnectable> RmcCallable for OnlyRemote<T> {
|
||||
fn rmc_call(
|
||||
&self,
|
||||
_responder: &SendingBufferConnection,
|
||||
_protocol_id: u16,
|
||||
_method_id: u32,
|
||||
_call_id: u32,
|
||||
_rest: Vec<u8>,
|
||||
) -> impl Future<Output = ()> + Send {
|
||||
// maybe respond with not implemented or something
|
||||
async {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_incoming<T: RmcCallable + Send + Sync + 'static>(
|
||||
mut connection: SplittableBufferConnection,
|
||||
remote: Arc<T>,
|
||||
notify: Arc<Notify>,
|
||||
incoming: Arc<Mutex<HashMap<u32, RMCResponse>>>,
|
||||
) {
|
||||
let sending_conn = connection.duplicate_sender();
|
||||
|
||||
while let Some(v) = connection.recv().await {
|
||||
let Some(proto_id) = v.get(4) else {
|
||||
error!("received too small rmc message.");
|
||||
error!("ending rmc gateway.");
|
||||
return;
|
||||
};
|
||||
|
||||
// protocol 0 is hardcoded to be the no protocol protocol aka keepalive protocol
|
||||
if *proto_id == 0 {
|
||||
println!("got keepalive");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (proto_id & 0x80) == 0 {
|
||||
let Some(response) = RMCResponse::new(&mut Cursor::new(v)).display_err_or_some() else {
|
||||
error!("ending rmc gateway.");
|
||||
return;
|
||||
};
|
||||
|
||||
info!("got rmc response");
|
||||
|
||||
let mut locked = incoming.lock().await;
|
||||
|
||||
locked.insert(response.get_call_id(), response);
|
||||
notify.notify_waiters();
|
||||
} else {
|
||||
let Some(message) = RMCMessage::new(&mut Cursor::new(v)).display_err_or_some() else {
|
||||
error!("ending rmc gateway.");
|
||||
return;
|
||||
};
|
||||
|
||||
let RMCMessage {
|
||||
protocol_id,
|
||||
method_id,
|
||||
call_id,
|
||||
rest_of_data,
|
||||
} = message;
|
||||
|
||||
info!(
|
||||
"RMC REQUEST: Proto: {}; Method: {}; cid: {}",
|
||||
protocol_id, method_id, call_id
|
||||
);
|
||||
|
||||
remote
|
||||
.rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
info!("rmc disconnected")
|
||||
}
|
||||
|
||||
pub fn new_rmc_gateway_connection<T: RmcCallable + Sync + Send + 'static, F>(
|
||||
conn: SplittableBufferConnection,
|
||||
create_internal: F,
|
||||
) -> Arc<T>
|
||||
where
|
||||
F: FnOnce(RmcConnection) -> Arc<T>,
|
||||
{
|
||||
let notify = Arc::new(Notify::new());
|
||||
let incoming: Arc<Mutex<HashMap<u32, RMCResponse>>> = Default::default();
|
||||
|
||||
let response_recv = RmcResponseReceiver(notify.clone(), incoming.clone());
|
||||
|
||||
let sending_conn = conn.duplicate_sender();
|
||||
|
||||
let rmc_conn = RmcConnection(sending_conn, response_recv);
|
||||
|
||||
let sending_conn = conn.duplicate_sender();
|
||||
|
||||
let exposed_object = (create_internal)(rmc_conn);
|
||||
|
||||
{
|
||||
let exposed_object = exposed_object.clone();
|
||||
tokio::spawn(async move {
|
||||
handle_incoming(conn, exposed_object, notify, incoming).await;
|
||||
});
|
||||
|
||||
tokio::spawn(async move {
|
||||
while sending_conn.is_alive() {
|
||||
sending_conn.send([0, 0, 0, 0, 0].to_vec()).await;
|
||||
sleep(Duration::from_secs(10)).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exposed_object
|
||||
}
|
||||
|
||||
impl<T: RmcCallable> RmcCallable for Arc<T> {
|
||||
fn rmc_call(
|
||||
&self,
|
||||
responder: &SendingBufferConnection,
|
||||
protocol_id: u16,
|
||||
method_id: u32,
|
||||
call_id: u32,
|
||||
rest: Vec<u8>,
|
||||
) -> impl Future<Output = ()> + Send {
|
||||
self.as_ref()
|
||||
.rmc_call(responder, protocol_id, method_id, call_id, rest)
|
||||
}
|
||||
}
|
||||
|
||||
define_rmc_proto! {
|
||||
proto NoProto{}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
use macros::{method_id, rmc_proto};
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
|
||||
#[rmc_proto(3)]
|
||||
pub trait NatTraversal{
|
||||
#[method_id(2)]
|
||||
async fn request_probe_initiation(&self, station_to_probe: String) -> Result<(),ErrorCode>;
|
||||
|
||||
#[method_id(3)]
|
||||
async fn request_probe_initialization_ext(&self, target_list: Vec<String>, station_to_probe: String) -> Result<(),ErrorCode>;
|
||||
|
||||
#[method_id(4)]
|
||||
async fn report_nat_traversal_result(&self, cid: u32, result: bool, rtt: u32) -> Result<(),ErrorCode>;
|
||||
|
||||
#[method_id(5)]
|
||||
async fn report_nat_properties(&self, nat_mapping: u32, nat_filtering: u32, rtt: u32) -> Result<(),ErrorCode>;
|
||||
}
|
||||
|
||||
#[rmc_proto(3, NoReturn)]
|
||||
pub trait NatTraversalConsole{
|
||||
#[method_id(2)]
|
||||
async fn request_probe_initiation(&self, station_to_probe: String);
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
|
||||
use rnex_core::PID;
|
||||
|
||||
pub mod notification_types {
|
||||
pub const OWNERSHIP_CHANGED: u32 = 4000;
|
||||
pub const HOST_CHANGED: u32 = 110000;
|
||||
pub const REQUEST_JOIN_GATHERING: u32 = 101;
|
||||
pub const END_GATHERING: u32 = 102;
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "third-notif-param")]{
|
||||
#[derive(RmcSerialize, Debug, Default, Clone)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct NotificationEvent {
|
||||
pub pid_source: PID,
|
||||
pub notif_type: u32,
|
||||
pub param_1: PID,
|
||||
pub param_2: PID,
|
||||
pub str_param: String,
|
||||
pub param_3: PID,
|
||||
}
|
||||
} else {
|
||||
#[derive(RmcSerialize, Debug, Default, Clone)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct NotificationEvent {
|
||||
pub pid_source: PID,
|
||||
pub notif_type: u32,
|
||||
pub param_1: PID,
|
||||
pub param_2: PID,
|
||||
pub str_param: String,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[rmc_proto(14, NoReturn)]
|
||||
pub trait Notification {
|
||||
#[method_id(1)]
|
||||
async fn process_notification_event(&self, event: NotificationEvent);
|
||||
}
|
||||
|
|
@ -1,502 +0,0 @@
|
|||
// i seriously dont know why the compiler is complaining about unused parentheses in the repr
|
||||
// attributes but this gets it to not complain anymore
|
||||
#![allow(unused_parens)]
|
||||
|
||||
use crate::rmc::response::ErrorCode::Core_Exception;
|
||||
use crate::rmc::structures::qresult::ERROR_MASK;
|
||||
use crate::util::SendingBufferConnection;
|
||||
use bytemuck::bytes_of;
|
||||
use log::{error, warn};
|
||||
use std::io;
|
||||
use std::io::{Read, Seek, Write};
|
||||
use std::mem::transmute;
|
||||
use v_byte_helpers::EnumTryInto;
|
||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RMCResponseResult {
|
||||
Success {
|
||||
call_id: u32,
|
||||
method_id: u32,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
Error {
|
||||
error_code: ErrorCode,
|
||||
call_id: u32,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RMCResponse {
|
||||
pub protocol_id: u8,
|
||||
pub response_result: RMCResponseResult,
|
||||
}
|
||||
|
||||
impl RMCResponse {
|
||||
pub fn new(stream: &mut (impl Seek + Read)) -> io::Result<Self> {
|
||||
// ignore the size for now this will only be used for checking
|
||||
let size: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||
|
||||
let protocol_id: u8 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||
|
||||
/*let protocol_id: u16 = match protocol_id{
|
||||
0x7F => {
|
||||
stream.read_struct(IS_BIG_ENDIAN)?
|
||||
},
|
||||
_ => protocol_id as u16
|
||||
};*/
|
||||
|
||||
let is_success: u8 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||
|
||||
let response_result = if is_success == 0x01 {
|
||||
let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||
let method_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||
let method_id = method_id & (!0x8000);
|
||||
|
||||
let mut data: Vec<u8> = vec![0u8; (size - 2 - 4 - 4) as _];
|
||||
|
||||
stream.read(&mut data)?;
|
||||
|
||||
RMCResponseResult::Success {
|
||||
call_id,
|
||||
method_id,
|
||||
data,
|
||||
}
|
||||
} else {
|
||||
let error_code: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||
let error_code = error_code & (!0x80000000);
|
||||
let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||
|
||||
RMCResponseResult::Error {
|
||||
error_code: {
|
||||
match ErrorCode::try_from(error_code) {
|
||||
Ok(v) => v,
|
||||
Err(()) => {
|
||||
error!("invalid error code {:#010x}", error_code);
|
||||
Core_Exception
|
||||
}
|
||||
}
|
||||
},
|
||||
call_id,
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
protocol_id,
|
||||
response_result,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_call_id(&self) -> u32 {
|
||||
match &self.response_result {
|
||||
RMCResponseResult::Success { call_id, .. } => *call_id,
|
||||
RMCResponseResult::Error { call_id, .. } => *call_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_data(self) -> Vec<u8> {
|
||||
generate_response(self.protocol_id, self.response_result)
|
||||
.expect("failed to generate response")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result<Vec<u8>> {
|
||||
let size = 1
|
||||
+ 1
|
||||
+ match &response {
|
||||
RMCResponseResult::Success { data, .. } => 4 + 4 + data.len(),
|
||||
RMCResponseResult::Error { .. } => 4 + 4,
|
||||
};
|
||||
|
||||
let mut data_out = Vec::with_capacity(size + 4);
|
||||
|
||||
let u32_size: u32 = size as _;
|
||||
|
||||
data_out.write_all(bytes_of(&u32_size))?;
|
||||
data_out.push(protocol_id);
|
||||
|
||||
match response {
|
||||
RMCResponseResult::Success {
|
||||
call_id,
|
||||
method_id,
|
||||
data,
|
||||
} => {
|
||||
data_out.push(1);
|
||||
data_out.write_all(bytes_of(&call_id))?;
|
||||
let ored_method_id = method_id | 0x8000;
|
||||
data_out.write_all(bytes_of(&ored_method_id))?;
|
||||
data_out.write_all(&data)?;
|
||||
}
|
||||
RMCResponseResult::Error {
|
||||
call_id,
|
||||
error_code,
|
||||
} => {
|
||||
data_out.push(0);
|
||||
let error_code_val: u32 = error_code.into();
|
||||
let error_code_val = error_code_val | ERROR_MASK;
|
||||
data_out.write_all(bytes_of(&error_code_val))?;
|
||||
data_out.write_all(bytes_of(&call_id))?;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(data_out.len(), size + 4);
|
||||
|
||||
Ok(data_out)
|
||||
}
|
||||
|
||||
pub async fn send_result(
|
||||
connection: &SendingBufferConnection,
|
||||
result: Result<Vec<u8>, ErrorCode>,
|
||||
protocol_id: u8,
|
||||
method_id: u32,
|
||||
call_id: u32,
|
||||
) {
|
||||
let response_result = match result {
|
||||
Ok(v) => RMCResponseResult::Success {
|
||||
call_id,
|
||||
method_id,
|
||||
data: v,
|
||||
},
|
||||
Err(e) => {
|
||||
warn!("error occurred during call: {:?}", e);
|
||||
RMCResponseResult::Error {
|
||||
call_id,
|
||||
error_code: e.into(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let response = RMCResponse {
|
||||
response_result,
|
||||
protocol_id,
|
||||
};
|
||||
|
||||
send_response(connection, response).await
|
||||
}
|
||||
|
||||
pub async fn send_response(connection: &SendingBufferConnection, rmcresponse: RMCResponse) {
|
||||
connection.send(rmcresponse.to_data()).await;
|
||||
}
|
||||
|
||||
//taken from kinnays error list directly
|
||||
#[allow(nonstandard_style)]
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, EnumTryInto, Clone, Copy)]
|
||||
pub enum ErrorCode {
|
||||
Core_Unknown = 0x00010001,
|
||||
Core_NotImplemented = 0x00010002,
|
||||
Core_InvalidPointer = 0x00010003,
|
||||
Core_OperationAborted = 0x00010004,
|
||||
Core_Exception = 0x00010005,
|
||||
Core_AccessDenied = 0x00010006,
|
||||
Core_InvalidHandle = 0x00010007,
|
||||
Core_InvalidIndex = 0x00010008,
|
||||
Core_OutOfMemory = 0x00010009,
|
||||
Core_InvalidArgument = 0x0001000A,
|
||||
Core_Timeout = 0x0001000B,
|
||||
Core_InitializationFailure = 0x0001000C,
|
||||
Core_CallInitiationFailure = 0x0001000D,
|
||||
Core_RegistrationError = 0x0001000E,
|
||||
Core_BufferOverflow = 0x0001000F,
|
||||
Core_InvalidLockState = 0x00010010,
|
||||
Core_InvalidSequence = 0x00010011,
|
||||
Core_SystemError = 0x00010012,
|
||||
Core_Cancelled = 0x00010013,
|
||||
DDL_InvalidSignature = 0x00020001,
|
||||
DDL_IncorrectVersion = 0x00020002,
|
||||
RendezVous_ConnectionFailure = 0x00030001,
|
||||
RendezVous_NotAuthenticated = 0x00030002,
|
||||
RendezVous_InvalidUsername = 0x00030064,
|
||||
RendezVous_InvalidPassword = 0x00030065,
|
||||
RendezVous_UsernameAlreadyExists = 0x00030066,
|
||||
RendezVous_AccountDisabled = 0x00030067,
|
||||
RendezVous_AccountExpired = 0x00030068,
|
||||
RendezVous_ConcurrentLoginDenied = 0x00030069,
|
||||
RendezVous_EncryptionFailure = 0x0003006A,
|
||||
RendezVous_InvalidPID = 0x0003006B,
|
||||
RendezVous_MaxConnectionsReached = 0x0003006C,
|
||||
RendezVous_InvalidGID = 0x0003006D,
|
||||
RendezVous_InvalidControlScriptID = 0x0003006E,
|
||||
RendezVous_InvalidOperationInLiveEnvironment = 0x0003006F,
|
||||
RendezVous_DuplicateEntry = 0x00030070,
|
||||
RendezVous_ControlScriptFailure = 0x00030071,
|
||||
RendezVous_ClassNotFound = 0x00030072,
|
||||
RendezVous_SessionVoid = 0x00030073,
|
||||
RendezVous_DDLMismatch = 0x00030075,
|
||||
RendezVous_InvalidConfiguration = 0x00030076,
|
||||
RendezVous_SessionFull = 0x000300C8,
|
||||
RendezVous_InvalidGatheringPassword = 0x000300C9,
|
||||
RendezVous_WithoutParticipationPeriod = 0x000300CA,
|
||||
RendezVous_PersistentGatheringCreationMax = 0x000300CB,
|
||||
RendezVous_PersistentGatheringParticipationMax = 0x000300CC,
|
||||
RendezVous_DeniedByParticipants = 0x000300CD,
|
||||
RendezVous_ParticipantInBlackList = 0x000300CE,
|
||||
RendezVous_GameServerMaintenance = 0x000300CF,
|
||||
RendezVous_OperationPostpone = 0x000300D0,
|
||||
RendezVous_OutOfRatingRange = 0x000300D1,
|
||||
RendezVous_ConnectionDisconnected = 0x000300D2,
|
||||
RendezVous_InvalidOperation = 0x000300D3,
|
||||
RendezVous_NotParticipatedGathering = 0x000300D4,
|
||||
RendezVous_MatchmakeSessionUserPasswordUnmatch = 0x000300D5,
|
||||
RendezVous_MatchmakeSessionSystemPasswordUnmatch = 0x000300D6,
|
||||
RendezVous_UserIsOffline = 0x000300D7,
|
||||
RendezVous_AlreadyParticipatedGathering = 0x000300D8,
|
||||
RendezVous_PermissionDenied = 0x000300D9,
|
||||
RendezVous_NotFriend = 0x000300DA,
|
||||
RendezVous_SessionClosed = 0x000300DB,
|
||||
RendezVous_DatabaseTemporarilyUnavailable = 0x000300DC,
|
||||
RendezVous_InvalidUniqueId = 0x000300DD,
|
||||
RendezVous_MatchmakingWithdrawn = 0x000300DE,
|
||||
RendezVous_LimitExceeded = 0x000300DF,
|
||||
RendezVous_AccountTemporarilyDisabled = 0x000300E0,
|
||||
RendezVous_PartiallyServiceClosed = 0x000300E1,
|
||||
RendezVous_ConnectionDisconnectedForConcurrentLogin = 0x000300E2,
|
||||
PythonCore_Exception = 0x00040001,
|
||||
PythonCore_TypeError = 0x00040002,
|
||||
PythonCore_IndexError = 0x00040003,
|
||||
PythonCore_InvalidReference = 0x00040004,
|
||||
PythonCore_CallFailure = 0x00040005,
|
||||
PythonCore_MemoryError = 0x00040006,
|
||||
PythonCore_KeyError = 0x00040007,
|
||||
PythonCore_OperationError = 0x00040008,
|
||||
PythonCore_ConversionError = 0x00040009,
|
||||
PythonCore_ValidationError = 0x0004000A,
|
||||
Transport_Unknown = 0x00050001,
|
||||
Transport_ConnectionFailure = 0x00050002,
|
||||
Transport_InvalidUrl = 0x00050003,
|
||||
Transport_InvalidKey = 0x00050004,
|
||||
Transport_InvalidURLType = 0x00050005,
|
||||
Transport_DuplicateEndpoint = 0x00050006,
|
||||
Transport_IOError = 0x00050007,
|
||||
Transport_Timeout = 0x00050008,
|
||||
Transport_ConnectionReset = 0x00050009,
|
||||
Transport_IncorrectRemoteAuthentication = 0x0005000A,
|
||||
Transport_ServerRequestError = 0x0005000B,
|
||||
Transport_DecompressionFailure = 0x0005000C,
|
||||
Transport_ReliableSendBufferFullFatal = 0x0005000D,
|
||||
Transport_UPnPCannotInit = 0x0005000E,
|
||||
Transport_UPnPCannotAddMapping = 0x0005000F,
|
||||
Transport_NatPMPCannotInit = 0x00050010,
|
||||
Transport_NatPMPCannotAddMapping = 0x00050011,
|
||||
Transport_UnsupportedNAT = 0x00050013,
|
||||
Transport_DnsError = 0x00050014,
|
||||
Transport_ProxyError = 0x00050015,
|
||||
Transport_DataRemaining = 0x00050016,
|
||||
Transport_NoBuffer = 0x00050017,
|
||||
Transport_NotFound = 0x00050018,
|
||||
Transport_TemporaryServerError = 0x00050019,
|
||||
Transport_PermanentServerError = 0x0005001A,
|
||||
Transport_ServiceUnavailable = 0x0005001B,
|
||||
Transport_ReliableSendBufferFull = 0x0005001C,
|
||||
Transport_InvalidStation = 0x0005001D,
|
||||
Transport_InvalidSubStreamID = 0x0005001E,
|
||||
Transport_PacketBufferFull = 0x0005001F,
|
||||
Transport_NatTraversalError = 0x00050020,
|
||||
Transport_NatCheckError = 0x00050021,
|
||||
DOCore_StationNotReached = 0x00060001,
|
||||
DOCore_TargetStationDisconnect = 0x00060002,
|
||||
DOCore_LocalStationLeaving = 0x00060003,
|
||||
DOCore_ObjectNotFound = 0x00060004,
|
||||
DOCore_InvalidRole = 0x00060005,
|
||||
DOCore_CallTimeout = 0x00060006,
|
||||
DOCore_RMCDispatchFailed = 0x00060007,
|
||||
DOCore_MigrationInProgress = 0x00060008,
|
||||
DOCore_NoAuthority = 0x00060009,
|
||||
DOCore_NoTargetStationSpecified = 0x0006000A,
|
||||
DOCore_JoinFailed = 0x0006000B,
|
||||
DOCore_JoinDenied = 0x0006000C,
|
||||
DOCore_ConnectivityTestFailed = 0x0006000D,
|
||||
DOCore_Unknown = 0x0006000E,
|
||||
DOCore_UnfreedReferences = 0x0006000F,
|
||||
DOCore_JobTerminationFailed = 0x00060010,
|
||||
DOCore_InvalidState = 0x00060011,
|
||||
DOCore_FaultRecoveryFatal = 0x00060012,
|
||||
DOCore_FaultRecoveryJobProcessFailed = 0x00060013,
|
||||
DOCore_StationInconsitency = 0x00060014,
|
||||
DOCore_AbnormalMasterState = 0x00060015,
|
||||
DOCore_VersionMismatch = 0x00060016,
|
||||
FPD_NotInitialized = 0x00650000,
|
||||
FPD_AlreadyInitialized = 0x00650001,
|
||||
FPD_NotConnected = 0x00650002,
|
||||
FPD_Connected = 0x00650003,
|
||||
FPD_InitializationFailure = 0x00650004,
|
||||
FPD_OutOfMemory = 0x00650005,
|
||||
FPD_RmcFailed = 0x00650006,
|
||||
FPD_InvalidArgument = 0x00650007,
|
||||
FPD_InvalidLocalAccountID = 0x00650008,
|
||||
FPD_InvalidPrincipalID = 0x00650009,
|
||||
FPD_InvalidLocalFriendCode = 0x0065000A,
|
||||
FPD_LocalAccountNotExists = 0x0065000B,
|
||||
FPD_LocalAccountNotLoaded = 0x0065000C,
|
||||
FPD_LocalAccountAlreadyLoaded = 0x0065000D,
|
||||
FPD_FriendAlreadyExists = 0x0065000E,
|
||||
FPD_FriendNotExists = 0x0065000F,
|
||||
FPD_FriendNumMax = 0x00650010,
|
||||
FPD_NotFriend = 0x00650011,
|
||||
FPD_FileIO = 0x00650012,
|
||||
FPD_P2PInternetProhibited = 0x00650013,
|
||||
FPD_Unknown = 0x00650014,
|
||||
FPD_InvalidState = 0x00650015,
|
||||
FPD_AddFriendProhibited = 0x00650017,
|
||||
FPD_InvalidAccount = 0x00650019,
|
||||
FPD_BlacklistedByMe = 0x0065001A,
|
||||
FPD_FriendAlreadyAdded = 0x0065001C,
|
||||
FPD_MyFriendListLimitExceed = 0x0065001D,
|
||||
FPD_RequestLimitExceed = 0x0065001E,
|
||||
FPD_InvalidMessageID = 0x0065001F,
|
||||
FPD_MessageIsNotMine = 0x00650020,
|
||||
FPD_MessageIsNotForMe = 0x00650021,
|
||||
FPD_FriendRequestBlocked = 0x00650022,
|
||||
FPD_NotInMyFriendList = 0x00650023,
|
||||
FPD_FriendListedByMe = 0x00650024,
|
||||
FPD_NotInMyBlacklist = 0x00650025,
|
||||
FPD_IncompatibleAccount = 0x00650026,
|
||||
FPD_BlockSettingChangeNotAllowed = 0x00650027,
|
||||
FPD_SizeLimitExceeded = 0x00650028,
|
||||
FPD_OperationNotAllowed = 0x00650029,
|
||||
FPD_NotNetworkAccount = 0x0065002A,
|
||||
FPD_NotificationNotFound = 0x0065002B,
|
||||
FPD_PreferenceNotInitialized = 0x0065002C,
|
||||
FPD_FriendRequestNotAllowed = 0x0065002D,
|
||||
Ranking_NotInitialized = 0x00670001,
|
||||
Ranking_InvalidArgument = 0x00670002,
|
||||
Ranking_RegistrationError = 0x00670003,
|
||||
Ranking_NotFound = 0x00670005,
|
||||
Ranking_InvalidScore = 0x00670006,
|
||||
Ranking_InvalidDataSize = 0x00670007,
|
||||
Ranking_PermissionDenied = 0x00670009,
|
||||
Ranking_Unknown = 0x0067000A,
|
||||
Ranking_NotImplemented = 0x0067000B,
|
||||
Authentication_NASAuthenticateError = 0x00680001,
|
||||
Authentication_TokenParseError = 0x00680002,
|
||||
Authentication_HttpConnectionError = 0x00680003,
|
||||
Authentication_HttpDNSError = 0x00680004,
|
||||
Authentication_HttpGetProxySetting = 0x00680005,
|
||||
Authentication_TokenExpired = 0x00680006,
|
||||
Authentication_ValidationFailed = 0x00680007,
|
||||
Authentication_InvalidParam = 0x00680008,
|
||||
Authentication_PrincipalIdUnmatched = 0x00680009,
|
||||
Authentication_MoveCountUnmatch = 0x0068000A,
|
||||
Authentication_UnderMaintenance = 0x0068000B,
|
||||
Authentication_UnsupportedVersion = 0x0068000C,
|
||||
Authentication_ServerVersionIsOld = 0x0068000D,
|
||||
Authentication_Unknown = 0x0068000E,
|
||||
Authentication_ClientVersionIsOld = 0x0068000F,
|
||||
Authentication_AccountLibraryError = 0x00680010,
|
||||
Authentication_ServiceNoLongerAvailable = 0x00680011,
|
||||
Authentication_UnknownApplication = 0x00680012,
|
||||
Authentication_ApplicationVersionIsOld = 0x00680013,
|
||||
Authentication_OutOfService = 0x00680014,
|
||||
Authentication_NetworkServiceLicenseRequired = 0x00680015,
|
||||
Authentication_NetworkServiceLicenseSystemError = 0x00680016,
|
||||
Authentication_NetworkServiceLicenseError3 = 0x00680017,
|
||||
Authentication_NetworkServiceLicenseError4 = 0x00680018,
|
||||
DataStore_Unknown = 0x00690001,
|
||||
DataStore_InvalidArgument = 0x00690002,
|
||||
DataStore_PermissionDenied = 0x00690003,
|
||||
DataStore_NotFound = 0x00690004,
|
||||
DataStore_AlreadyLocked = 0x00690005,
|
||||
DataStore_UnderReviewing = 0x00690006,
|
||||
DataStore_Expired = 0x00690007,
|
||||
DataStore_InvalidCheckToken = 0x00690008,
|
||||
DataStore_SystemFileError = 0x00690009,
|
||||
DataStore_OverCapacity = 0x0069000A,
|
||||
DataStore_OperationNotAllowed = 0x0069000B,
|
||||
DataStore_InvalidPassword = 0x0069000C,
|
||||
DataStore_ValueNotEqual = 0x0069000D,
|
||||
ServiceItem_Unknown = 0x006C0001,
|
||||
ServiceItem_InvalidArgument = 0x006C0002,
|
||||
ServiceItem_EShopUnknownHttpError = 0x006C0003,
|
||||
ServiceItem_EShopResponseParseError = 0x006C0004,
|
||||
ServiceItem_NotOwned = 0x006C0005,
|
||||
ServiceItem_InvalidLimitationType = 0x006C0006,
|
||||
ServiceItem_ConsumptionRightShortage = 0x006C0007,
|
||||
MatchmakeReferee_Unknown = 0x006F0001,
|
||||
MatchmakeReferee_InvalidArgument = 0x006F0002,
|
||||
MatchmakeReferee_AlreadyExists = 0x006F0003,
|
||||
MatchmakeReferee_NotParticipatedGathering = 0x006F0004,
|
||||
MatchmakeReferee_NotParticipatedRound = 0x006F0005,
|
||||
MatchmakeReferee_StatsNotFound = 0x006F0006,
|
||||
MatchmakeReferee_RoundNotFound = 0x006F0007,
|
||||
MatchmakeReferee_RoundArbitrated = 0x006F0008,
|
||||
MatchmakeReferee_RoundNotArbitrated = 0x006F0009,
|
||||
Subscriber_Unknown = 0x00700001,
|
||||
Subscriber_InvalidArgument = 0x00700002,
|
||||
Subscriber_OverLimit = 0x00700003,
|
||||
Subscriber_PermissionDenied = 0x00700004,
|
||||
Ranking2_Unknown = 0x00710001,
|
||||
Ranking2_InvalidArgument = 0x00710002,
|
||||
Ranking2_InvalidScore = 0x00710003,
|
||||
SmartDeviceVoiceChat_Unknown = 0x00720001,
|
||||
SmartDeviceVoiceChat_InvalidArgument = 0x00720002,
|
||||
SmartDeviceVoiceChat_InvalidResponse = 0x00720003,
|
||||
SmartDeviceVoiceChat_InvalidAccessToken = 0x00720004,
|
||||
SmartDeviceVoiceChat_Unauthorized = 0x00720005,
|
||||
SmartDeviceVoiceChat_AccessError = 0x00720006,
|
||||
SmartDeviceVoiceChat_UserNotFound = 0x00720007,
|
||||
SmartDeviceVoiceChat_RoomNotFound = 0x00720008,
|
||||
SmartDeviceVoiceChat_RoomNotActivated = 0x00720009,
|
||||
SmartDeviceVoiceChat_ApplicationNotSupported = 0x0072000A,
|
||||
SmartDeviceVoiceChat_InternalServerError = 0x0072000B,
|
||||
SmartDeviceVoiceChat_ServiceUnavailable = 0x0072000C,
|
||||
SmartDeviceVoiceChat_UnexpectedError = 0x0072000D,
|
||||
SmartDeviceVoiceChat_UnderMaintenance = 0x0072000E,
|
||||
SmartDeviceVoiceChat_ServiceNoLongerAvailable = 0x0072000F,
|
||||
SmartDeviceVoiceChat_AccountTemporarilyDisabled = 0x00720010,
|
||||
SmartDeviceVoiceChat_PermissionDenied = 0x00720011,
|
||||
SmartDeviceVoiceChat_NetworkServiceLicenseRequired = 0x00720012,
|
||||
SmartDeviceVoiceChat_AccountLibraryError = 0x00720013,
|
||||
SmartDeviceVoiceChat_GameModeNotFound = 0x00720014,
|
||||
Screening_Unknown = 0x00730001,
|
||||
Screening_InvalidArgument = 0x00730002,
|
||||
Screening_NotFound = 0x00730003,
|
||||
Custom_Unknown = 0x00740001,
|
||||
Ess_Unknown = 0x00750001,
|
||||
Ess_GameSessionError = 0x00750002,
|
||||
Ess_GameSessionMaintenance = 0x00750003,
|
||||
}
|
||||
|
||||
impl From<super::structures::Error> for ErrorCode {
|
||||
fn from(value: super::structures::Error) -> Self {
|
||||
error!("rmc error occurred during method runtime: {}", value);
|
||||
Self::Core_InvalidArgument
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u32> for ErrorCode {
|
||||
fn into(self) -> u32 {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::rmc::response::ErrorCode;
|
||||
use hmac::digest::KeyInit;
|
||||
use hmac::digest::consts::U5;
|
||||
use rc4::{Rc4, StreamCipher};
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20];
|
||||
let mut data = data_orig;
|
||||
|
||||
let mut rc4: Rc4<U5> = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key");
|
||||
|
||||
rc4.apply_keystream(&mut data);
|
||||
|
||||
assert_ne!(data_orig, data);
|
||||
|
||||
let mut rc4: Rc4<U5> = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key");
|
||||
|
||||
rc4.apply_keystream(&mut data);
|
||||
|
||||
assert_eq!(data_orig, data);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum_equivilance() {
|
||||
let val: u32 = ErrorCode::Core_Unknown.into();
|
||||
assert_eq!(val, 0x00010001)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
use macros::RmcSerialize;
|
||||
use rnex_core::kerberos::KerberosDateTime;
|
||||
|
||||
#[derive(Debug, RmcSerialize)]
|
||||
#[rmc_struct(1)]
|
||||
pub struct ConnectionData {
|
||||
pub station_url: String,
|
||||
pub special_protocols: Vec<u8>,
|
||||
pub special_station_url: String,
|
||||
pub date_time: KerberosDateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, RmcSerialize)]
|
||||
#[rmc_struct(1)]
|
||||
pub struct ConnectionDataOld {
|
||||
pub station_url: String,
|
||||
pub special_protocols: Vec<u8>,
|
||||
pub special_station_url: String,
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
use macros::RmcSerialize;
|
||||
|
||||
#[derive(RmcSerialize, Debug, Clone, Copy, Default)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct Data {}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
use bytemuck::{Pod, Zeroable};
|
||||
use macros::RmcSerialize;
|
||||
use rnex_core::rmc::structures::qbuffer::QBuffer;
|
||||
|
||||
#[derive(RmcSerialize, Debug)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct UploadCompetitionData{
|
||||
pub unk_1/*?*/: u32,
|
||||
pub splatfest_id: u32,
|
||||
pub unk_2/*?*/: u32,
|
||||
pub score: u32,
|
||||
pub team_id: u8,
|
||||
pub team_win: u8,
|
||||
pub is_first_upload: bool,
|
||||
pub appdata: QBuffer,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
struct UserData {
|
||||
name: [u16; 0x10],
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
use crate::{PID, prudp::socket_addr::PRUDPSockAddr};
|
||||
use macros::RmcSerialize;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, RmcSerialize)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct ConnectionInitData {
|
||||
pub prudpsock_addr: PRUDPSockAddr,
|
||||
pub pid: PID,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::{
|
||||
io::Cursor,
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort},
|
||||
rmc::structures::RmcSerialize,
|
||||
rnex_proxy_common::ConnectionInitData,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let data = ConnectionInitData {
|
||||
prudpsock_addr: PRUDPSockAddr {
|
||||
regular_socket_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::BROADCAST, 19293)),
|
||||
virtual_port: VirtualPort::new(10, 2),
|
||||
},
|
||||
pid: 100,
|
||||
};
|
||||
|
||||
let ser = data.to_data().unwrap();
|
||||
|
||||
let de = ConnectionInitData::deserialize(&mut Cursor::new(ser)).unwrap();
|
||||
|
||||
assert_eq!(data, de);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
use std::{
|
||||
hash::{DefaultHasher, Hash, Hasher},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use rnex_server_api::gatherings::{
|
||||
Gatherings, gathering_info_service_server::GatheringInfoService,
|
||||
};
|
||||
use tonic::{Request, Response, Status, async_trait};
|
||||
|
||||
use crate::{
|
||||
nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager},
|
||||
rmc::structures::matchmake::{self, MatchmakeSession},
|
||||
server_api,
|
||||
};
|
||||
|
||||
impl Into<rnex_server_api::gatherings::Gathering> for &ExtendedMatchmakeSession {
|
||||
fn into(self) -> rnex_server_api::gatherings::Gathering {
|
||||
let players = self.get_active_players().map(|p| *p.pid as u64).collect();
|
||||
let ExtendedMatchmakeSession {
|
||||
session:
|
||||
MatchmakeSession {
|
||||
gathering:
|
||||
matchmake::Gathering {
|
||||
state,
|
||||
flags,
|
||||
host_pid,
|
||||
description,
|
||||
maximum_participants,
|
||||
minimum_participants,
|
||||
owner_pid,
|
||||
participant_policy,
|
||||
policy_argument,
|
||||
self_gid,
|
||||
},
|
||||
application_buffer,
|
||||
attributes,
|
||||
gamemode,
|
||||
matchmake_system_type,
|
||||
open_participation,
|
||||
participation_count,
|
||||
session_key,
|
||||
},
|
||||
connected_players,
|
||||
} = self;
|
||||
rnex_server_api::gatherings::Gathering {
|
||||
players,
|
||||
description: description.clone(),
|
||||
flags: *flags,
|
||||
host_pid: *host_pid as _,
|
||||
maximum_participants: *maximum_participants as _,
|
||||
minimum_participants: *minimum_participants as _,
|
||||
owner_pid: *owner_pid as _,
|
||||
participant_policy: *participant_policy,
|
||||
policy_argument: *policy_argument,
|
||||
self_gid: *self_gid,
|
||||
state: *state,
|
||||
application_buffer: application_buffer.clone(),
|
||||
attributes: attributes.clone(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GatheringsApi(Arc<MatchmakeManager>);
|
||||
|
||||
#[async_trait]
|
||||
impl GatheringInfoService for GatheringsApi {
|
||||
async fn get_gatherings(
|
||||
&self,
|
||||
request: Request<()>,
|
||||
) -> std::result::Result<Response<Gatherings>, Status> {
|
||||
Ok(Response::new(Gatherings {
|
||||
gatherings: self
|
||||
.0
|
||||
.sessions
|
||||
.read()
|
||||
.await
|
||||
.keys()
|
||||
.map(|gid| {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
gid.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
})
|
||||
.collect(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
use rnex_server_api::meta::{
|
||||
ApiFeature, ApiFeatures, BuildInfo, server_meta_service_server::ServerMetaService,
|
||||
};
|
||||
use tonic::{Request, Response, Status, async_trait, transport::Server};
|
||||
|
||||
pub struct ServerMeta;
|
||||
|
||||
#[async_trait]
|
||||
impl ServerMetaService for ServerMeta {
|
||||
async fn get_build_info(&self, request: Request<()>) -> Result<Response<BuildInfo>, Status> {
|
||||
Ok(Response::new(BuildInfo {
|
||||
version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||
edition: env!("EDITION").to_owned(),
|
||||
build_hash: env!("GIT_HASH").to_owned(),
|
||||
feature_set: env!("FEATURESET").to_owned(),
|
||||
}))
|
||||
}
|
||||
async fn get_api_features(
|
||||
&self,
|
||||
request: Request<()>,
|
||||
) -> Result<Response<ApiFeatures>, Status> {
|
||||
let mut api_features = vec![ApiFeature {
|
||||
name: "meta".to_owned(),
|
||||
needs_admin: false,
|
||||
version: 0,
|
||||
}];
|
||||
|
||||
#[cfg(not(feature = "friends"))]
|
||||
api_features.push(ApiFeature {
|
||||
name: "gatherings".to_owned(),
|
||||
version: 0,
|
||||
needs_admin: true,
|
||||
});
|
||||
Ok(Response::new(ApiFeatures { api_features }))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
use std::{net::SocketAddr, str::FromStr};
|
||||
|
||||
use rnex_server_api::meta::server_meta_service_server::ServerMetaServiceServer;
|
||||
use tonic::transport::Server;
|
||||
|
||||
#[cfg(not(feature = "friends"))]
|
||||
use crate::nex::matchmake::MatchmakeManager;
|
||||
use crate::server_api::meta::ServerMeta;
|
||||
#[cfg(not(feature = "friends"))]
|
||||
use std::sync::Arc;
|
||||
#[cfg(not(feature = "friends"))]
|
||||
mod gatherings;
|
||||
|
||||
mod meta;
|
||||
|
||||
pub async fn launch_server_api(#[cfg(not(feature = "friends"))] mmm: Arc<MatchmakeManager>) {
|
||||
let mut server = Server::builder().add_service(ServerMetaServiceServer::new(ServerMeta));
|
||||
|
||||
server
|
||||
.serve(SocketAddr::from_str("0.0.0.0:80").expect("unable to make sockaddr from ip"))
|
||||
.await;
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::ops::{BitAnd, BitOr};
|
||||
use typenum::{Cmp, IsEqual, IsLess, IsLessOrEqual, Unsigned};
|
||||
|
||||
/// This trait represents a version at compile time
|
||||
trait Version {
|
||||
type Major: Unsigned;
|
||||
type Minor: Unsigned;
|
||||
}
|
||||
|
||||
/// This struct contains nothing and is used to represent specific versions as an instance of
|
||||
/// [`Version`]. It is instances as `Ver<Major, Minor>`
|
||||
struct Ver<MAJ: Unsigned, MIN: Unsigned> {
|
||||
_phantom: PhantomData<(MAJ, MIN)>,
|
||||
}
|
||||
|
||||
impl<MAJ: Unsigned, MIN: Unsigned> Version for Ver<MAJ, MIN> {
|
||||
type Major = MAJ;
|
||||
type Minor = MIN;
|
||||
}
|
||||
|
||||
/// Represents two versions which can be compared
|
||||
trait ComparableVersion<T: Version>: Version {
|
||||
type IsAtLeast: SameOrUnit;
|
||||
}
|
||||
|
||||
impl<T: Version, U: Version> ComparableVersion<T> for U
|
||||
where
|
||||
<T as Version>::Major: Cmp<Self::Major>,
|
||||
<T as Version>::Minor: IsLessOrEqual<Self::Minor>,
|
||||
<T as Version>::Major:
|
||||
IsEqual<Self::Major, Output: BitAnd<typenum::LeEq<T::Minor, Self::Minor>>>,
|
||||
<T as Version>::Major: IsLess<
|
||||
Self::Major,
|
||||
Output: BitOr<
|
||||
typenum::And<
|
||||
typenum::Eq<T::Major, Self::Major>,
|
||||
typenum::LeEq<T::Minor, Self::Minor>,
|
||||
>,
|
||||
Output: SameOrUnit,
|
||||
>,
|
||||
>,
|
||||
{
|
||||
type IsAtLeast = typenum::Or<
|
||||
typenum::Le<T::Major, Self::Major>,
|
||||
typenum::And<typenum::Eq<T::Major, Self::Major>, typenum::LeEq<T::Minor, Self::Minor>>,
|
||||
>;
|
||||
}
|
||||
|
||||
/// Simple check for testing if the `TEST` version is at least `REQ` or higher.
|
||||
type VersionAbove<REQ, TEST> = <TEST as ComparableVersion<REQ>>::IsAtLeast;
|
||||
|
||||
trait VersionIsAtLeast<VER: Version> {}
|
||||
|
||||
impl<VER: Version, T: ComparableVersion<VER, IsAtLeast = typenum::True>> VersionIsAtLeast<VER>
|
||||
for T
|
||||
{
|
||||
}
|
||||
|
||||
/// Trait for containing the result of elements which only conditionally exist
|
||||
trait CondElemResult {
|
||||
type Output;
|
||||
}
|
||||
|
||||
/// Empty helper struct which only servers to give a concrete type when creating fields in rmc
|
||||
/// structs which have a version requirement. This is not meant to be used directly, use
|
||||
/// [`MinVersion`] instead.
|
||||
struct MinVersionElementHelper<T, REQUIRED: Version, VER: Version + ComparableVersion<REQUIRED>> {
|
||||
_phantom: PhantomData<(T, REQUIRED, VER)>,
|
||||
}
|
||||
|
||||
/// This should be used either with [`typenum::True`] or [`typenum::False`]. When `True` the [`Self::Output`]
|
||||
/// will be the same as the `T` you put into Output. When `False` it will always be `()`
|
||||
trait SameOrUnit {
|
||||
type Output<T>;
|
||||
}
|
||||
|
||||
impl SameOrUnit for typenum::True {
|
||||
type Output<T> = T;
|
||||
}
|
||||
|
||||
impl SameOrUnit for typenum::False {
|
||||
type Output<T> = ();
|
||||
}
|
||||
|
||||
impl<T, REQUIRED: Version, VER: Version + ComparableVersion<REQUIRED>> CondElemResult
|
||||
for MinVersionElementHelper<T, REQUIRED, VER>
|
||||
{
|
||||
type Output = <<VER as ComparableVersion<REQUIRED>>::IsAtLeast as SameOrUnit>::Output<T>;
|
||||
}
|
||||
|
||||
/// When the version condition is met the field will exist and will simply be `T` if not it will be
|
||||
/// replaced by `()`. Use this when you need to add versioning to rmc structs.
|
||||
type MinVersion<T, REQUIRED, VER> =
|
||||
<MinVersionElementHelper<T, REQUIRED, VER> as CondElemResult>::Output;
|
||||
16
rnex-protocols/auth-protos/Cargo.toml
Normal file
16
rnex-protocols/auth-protos/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "rnex-auth-protos"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "1.0.4"
|
||||
ctor = "1.0.8"
|
||||
rnex-rmc = { path = "../../rnex-rmc" }
|
||||
tokio = { version = "1.52.3", features = ["time", "sync"] }
|
||||
|
||||
[features]
|
||||
nx = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
@ -1,11 +1,31 @@
|
|||
use crate::rmc::structures::connection_data::{ConnectionData, ConnectionDataOld};
|
||||
use crate::rmc::structures::data::Data;
|
||||
use cfg_if::cfg_if;
|
||||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
use rnex_core::PID;
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_core::rmc::structures::any::Any;
|
||||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
use rnex_rmc::{
|
||||
RmcSerialize,
|
||||
any::Any,
|
||||
data::Data,
|
||||
method_id,
|
||||
qresult::QResult,
|
||||
response::ErrorCode,
|
||||
rmc_proto,
|
||||
util::{PID, date_time::DateTime},
|
||||
};
|
||||
|
||||
#[derive(Debug, RmcSerialize)]
|
||||
#[rmc_struct(1)]
|
||||
pub struct ConnectionData {
|
||||
pub station_url: String,
|
||||
pub special_protocols: Vec<u8>,
|
||||
pub special_station_url: String,
|
||||
pub date_time: DateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, RmcSerialize)]
|
||||
#[rmc_struct(1)]
|
||||
pub struct ConnectionDataOld {
|
||||
pub station_url: String,
|
||||
pub special_protocols: Vec<u8>,
|
||||
pub special_station_url: String,
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "nx")]{
|
||||
|
|
@ -34,6 +54,8 @@ pub trait Auth {
|
|||
#[method_id(2)]
|
||||
async fn login_ex(&self, name: String, extra_data: Any) -> Result<LoginExRet, ErrorCode>;
|
||||
|
||||
/// representation of the `RequestTicket` method(for details see the
|
||||
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||
#[method_id(3)]
|
||||
async fn request_ticket(
|
||||
&self,
|
||||
|
|
@ -41,9 +63,6 @@ pub trait Auth {
|
|||
destination_pid: PID,
|
||||
) -> Result<RequestTicketRet, ErrorCode>;
|
||||
|
||||
/// representation of the `RequestTicket` method(for details see the
|
||||
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||
|
||||
/// representation of the `GetPID` method(for details see the
|
||||
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||
#[method_id(4)]
|
||||
11
rnex-protocols/auth-protos/src/lib.rs
Normal file
11
rnex-protocols/auth-protos/src/lib.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#![allow(async_fn_in_trait)]
|
||||
|
||||
use rnex_rmc::define_rmc_proto;
|
||||
pub mod auth;
|
||||
use auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth};
|
||||
|
||||
define_rmc_proto!(
|
||||
proto AuthProtocol{
|
||||
Auth
|
||||
}
|
||||
);
|
||||
11
rnex-protocols/base-protos/Cargo.toml
Normal file
11
rnex-protocols/base-protos/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "rnex-base-protos"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
ctor = "1.0.8"
|
||||
rnex-rmc = { path = "../../rnex-rmc" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
@ -1,4 +1,10 @@
|
|||
use macros::RmcSerialize;
|
||||
#![allow(async_fn_in_trait)]
|
||||
|
||||
use rnex_rmc::{RmcSerialize, define_rmc_proto};
|
||||
pub mod secure;
|
||||
pub mod util;
|
||||
use secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||
use util::{RawUtility, RawUtilityInfo, RemoteUtility, Utility};
|
||||
|
||||
#[derive(RmcSerialize, Debug, Default, Clone)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -16,3 +22,10 @@ impl ResultsRange {
|
|||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
define_rmc_proto!(
|
||||
proto BaseProtocol{
|
||||
Secure,
|
||||
Utility,
|
||||
}
|
||||
);
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
use rnex_core::prudp::station_url::StationUrl;
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
|
||||
use crate::rmc::structures::any::Any;
|
||||
use crate::rmc::structures::data::Data;
|
||||
use rnex_rmc::{
|
||||
RmcSerialize, any::Any, data::Data, method_id, qresult::QResult, response::ErrorCode,
|
||||
rmc_proto, util::station_url::StationUrl,
|
||||
};
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -34,7 +31,7 @@ pub trait Secure {
|
|||
async fn register_ex(
|
||||
&self,
|
||||
station_urls: Vec<StationUrl>,
|
||||
data: Any<Data>,
|
||||
data: Any,
|
||||
) -> Result<(QResult, u32, StationUrl), ErrorCode>;
|
||||
#[method_id(7)]
|
||||
async fn replace_url(&self, target: StationUrl, dest: StationUrl) -> Result<(), ErrorCode>;
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
use macros::{method_id, rmc_proto};
|
||||
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_rmc::{method_id, response::ErrorCode, rmc_proto};
|
||||
|
||||
#[rmc_proto(110)]
|
||||
pub trait Utility {
|
||||
12
rnex-protocols/ds-protos/Cargo.toml
Normal file
12
rnex-protocols/ds-protos/Cargo.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "rnex-ds-protos"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
ctor = "1.0.8"
|
||||
rnex-rmc = { path = "../../rnex-rmc" }
|
||||
rnex-base-protos = { path = "../base-protos" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
use rnex_core::PID;
|
||||
use rnex_core::kerberos::KerberosDateTime;
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_core::rmc::structures::qbuffer::QBuffer;
|
||||
use rnex_core::rmc::structures::qresult::QResult;
|
||||
use rnex_core::rmc::structures::resultsrange::ResultsRange;
|
||||
use rnex_base_protos::ResultsRange;
|
||||
use rnex_rmc::{
|
||||
RmcSerialize, method_id,
|
||||
qbuffer::QBuffer,
|
||||
qresult::QResult,
|
||||
response::ErrorCode,
|
||||
rmc_proto,
|
||||
util::{PID, date_time::DateTime},
|
||||
};
|
||||
|
||||
#[derive(RmcSerialize, Clone, Debug, Default)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -55,15 +57,15 @@ pub struct GetMetaInfo {
|
|||
pub meta_binary: QBuffer,
|
||||
pub permission: Permission,
|
||||
pub del_permission: Permission,
|
||||
pub created_time: KerberosDateTime,
|
||||
pub updated_time: KerberosDateTime,
|
||||
pub created_time: DateTime,
|
||||
pub updated_time: DateTime,
|
||||
pub period: u16,
|
||||
pub status: u8,
|
||||
pub referred_count: u32,
|
||||
pub refer_dat_id: u32,
|
||||
pub flag: u32,
|
||||
pub referred_time: KerberosDateTime,
|
||||
pub expire_time: KerberosDateTime,
|
||||
pub referred_time: DateTime,
|
||||
pub expire_time: DateTime,
|
||||
pub tags: Vec<String>,
|
||||
pub ratings: Vec<RatingInfoWithSlot>,
|
||||
}
|
||||
|
|
@ -199,10 +201,10 @@ pub struct DataStoreSearchParam {
|
|||
pub owner_type: u8,
|
||||
pub destination_ids: Vec<i64>,
|
||||
pub data_type: u16,
|
||||
pub created_after: KerberosDateTime,
|
||||
pub created_before: KerberosDateTime,
|
||||
pub updated_after: KerberosDateTime,
|
||||
pub updated_before: KerberosDateTime,
|
||||
pub created_after: DateTime,
|
||||
pub created_before: DateTime,
|
||||
pub updated_after: DateTime,
|
||||
pub updated_before: DateTime,
|
||||
pub refer_dat_id: u32,
|
||||
pub tags: Vec<String>,
|
||||
pub result_order_column: u8,
|
||||
|
|
@ -291,8 +293,8 @@ pub struct DataStoreGetCourseRecordResult {
|
|||
pub first_pid: u32,
|
||||
pub best_pid: u32,
|
||||
pub best_score: i32,
|
||||
pub created_time: KerberosDateTime,
|
||||
pub updated_time: KerberosDateTime,
|
||||
pub created_time: DateTime,
|
||||
pub updated_time: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize, Clone)]
|
||||
11
rnex-protocols/ds-protos/src/lib.rs
Normal file
11
rnex-protocols/ds-protos/src/lib.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#![allow(async_fn_in_trait)]
|
||||
|
||||
pub mod datastore;
|
||||
use datastore::{DataStore, RawDataStore, RawDataStoreInfo, RemoteDataStore};
|
||||
use rnex_rmc::define_rmc_proto;
|
||||
|
||||
define_rmc_proto!(
|
||||
proto DatastoreProtocol{
|
||||
DataStore
|
||||
}
|
||||
);
|
||||
11
rnex-protocols/fpd-protos/Cargo.toml
Normal file
11
rnex-protocols/fpd-protos/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "rnex-fpd-protos"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
ctor = "1.0.8"
|
||||
rnex-rmc = { path = "../../rnex-rmc" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
|
||||
use rnex_core::{
|
||||
PID,
|
||||
rmc::{response::ErrorCode, structures::any::Any},
|
||||
use rnex_rmc::{
|
||||
RmcSerialize,
|
||||
any::Any,
|
||||
data::Data,
|
||||
method_id,
|
||||
response::ErrorCode,
|
||||
rmc_proto,
|
||||
util::{PID, date_time::DateTime},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
kerberos::KerberosDateTime,
|
||||
rmc::{protocols::friends_wiiu::NNAInfo, structures::data::Data},
|
||||
};
|
||||
use crate::friends_wiiu::NNAInfo;
|
||||
|
||||
#[derive(RmcSerialize, Debug, Clone)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -17,7 +17,7 @@ pub struct NintendoCreateAccountData {
|
|||
pub data: Data,
|
||||
pub nna_info: NNAInfo,
|
||||
pub nex_token: String,
|
||||
pub birthday: KerberosDateTime,
|
||||
pub birthday: DateTime,
|
||||
pub unk: u64,
|
||||
}
|
||||
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
|
||||
use rnex_core::rmc::{response::ErrorCode, structures::data::Data};
|
||||
|
||||
use crate::{PID, kerberos::KerberosDateTime};
|
||||
use rnex_rmc::{
|
||||
RmcSerialize,
|
||||
data::Data,
|
||||
list::Buffer,
|
||||
method_id,
|
||||
response::ErrorCode,
|
||||
rmc_proto,
|
||||
util::{PID, date_time::DateTime},
|
||||
};
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -38,7 +42,7 @@ pub struct MiiList {
|
|||
pub unk1: String,
|
||||
pub unk2: bool,
|
||||
pub unk3: u8,
|
||||
pub mii_data: Vec<Vec<u8>>,
|
||||
pub mii_data: Vec<Buffer>,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize, Debug)]
|
||||
|
|
@ -56,14 +60,14 @@ pub struct PlayedGame {
|
|||
#[extends]
|
||||
pub data: Data,
|
||||
pub game_key: GameKey,
|
||||
pub date_time: KerberosDateTime,
|
||||
pub date_time: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct FriendInfo {
|
||||
pub pid: u32,
|
||||
pub unk2: KerberosDateTime,
|
||||
pub unk2: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
|
|
@ -73,7 +77,7 @@ pub struct FriendMii {
|
|||
pub data: Data,
|
||||
pub pid: PID,
|
||||
pub mii: Mii,
|
||||
pub modified_at: KerberosDateTime,
|
||||
pub modified_at: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
|
|
@ -83,7 +87,7 @@ pub struct FriendMiiList {
|
|||
pub data: Data,
|
||||
pub unk1: u32,
|
||||
pub mii_list: MiiList,
|
||||
pub unk2: KerberosDateTime,
|
||||
pub unk2: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
|
|
@ -110,7 +114,7 @@ pub struct NintendoPresence {
|
|||
pub join_game_mode: u32,
|
||||
pub owner_pid: PID,
|
||||
pub join_group_id: u32,
|
||||
pub application_arg: Vec<u8>,
|
||||
pub application_arg: Buffer,
|
||||
}
|
||||
#[derive(RmcSerialize)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -127,7 +131,7 @@ pub struct FriendComment {
|
|||
pub data: Data,
|
||||
pub pid: PID,
|
||||
pub comment: String,
|
||||
pub modified_at: KerberosDateTime,
|
||||
pub modified_at: DateTime,
|
||||
}
|
||||
#[derive(RmcSerialize)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -136,7 +140,7 @@ pub struct FriendPicture {
|
|||
pub data: Data,
|
||||
pub unk1: u32,
|
||||
pub pic_data: Vec<u32>,
|
||||
pub date_time: KerberosDateTime,
|
||||
pub date_time: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
|
|
@ -152,9 +156,9 @@ pub struct FriendPersistentInfo {
|
|||
pub platform: u8,
|
||||
pub game_key: GameKey,
|
||||
pub message: String,
|
||||
pub msg_updated_at: KerberosDateTime,
|
||||
pub friended_at: KerberosDateTime,
|
||||
pub last_online: KerberosDateTime,
|
||||
pub msg_updated_at: DateTime,
|
||||
pub friended_at: DateTime,
|
||||
pub last_online: DateTime,
|
||||
}
|
||||
|
||||
#[rmc_proto(101)]
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
|
||||
use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode};
|
||||
|
||||
use rnex_core::rmc::structures::data::Data;
|
||||
|
||||
use rnex_core::PID;
|
||||
|
||||
use crate::rmc::structures::qbuffer::QBuffer;
|
||||
use rnex_rmc::{
|
||||
RmcSerialize,
|
||||
data::Data,
|
||||
method_id,
|
||||
qbuffer::QBuffer,
|
||||
response::ErrorCode,
|
||||
rmc_proto,
|
||||
util::{PID, date_time::DateTime},
|
||||
};
|
||||
|
||||
#[derive(RmcSerialize, Debug, Clone, Default)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -17,7 +17,7 @@ pub struct MiiV2 {
|
|||
pub unk: u8,
|
||||
pub unk2: u8,
|
||||
pub mii_data: Vec<u8>,
|
||||
pub date_time: KerberosDateTime,
|
||||
pub date_time: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize, Debug, Clone, Default)]
|
||||
|
|
@ -88,7 +88,7 @@ pub struct Comment {
|
|||
pub data: Data,
|
||||
pub unk: u8,
|
||||
pub message: String,
|
||||
pub last_changed: KerberosDateTime,
|
||||
pub last_changed: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize, Default, Debug)]
|
||||
|
|
@ -99,8 +99,8 @@ pub struct FriendInfo {
|
|||
pub nna_info: NNAInfo,
|
||||
pub presence: NintendoPresenceV2,
|
||||
pub comment: Comment,
|
||||
pub became_friends: KerberosDateTime,
|
||||
pub last_online: KerberosDateTime,
|
||||
pub became_friends: DateTime,
|
||||
pub last_online: DateTime,
|
||||
pub unk: u64,
|
||||
}
|
||||
|
||||
|
|
@ -116,8 +116,8 @@ pub struct FriendRequestMessage {
|
|||
pub unk2: u8,
|
||||
pub unk3: String,
|
||||
pub game_key: GameKey,
|
||||
pub unk4: KerberosDateTime,
|
||||
pub expires_on: KerberosDateTime,
|
||||
pub unk4: DateTime,
|
||||
pub expires_on: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize, Debug, Clone)]
|
||||
|
|
@ -127,7 +127,7 @@ pub struct FriendRequest {
|
|||
pub data: Data,
|
||||
pub basic_info: PrincipalBasicInfo,
|
||||
pub request_message: FriendRequestMessage,
|
||||
pub sent_on: KerberosDateTime,
|
||||
pub sent_on: DateTime,
|
||||
}
|
||||
|
||||
#[derive(RmcSerialize, Debug, Default)]
|
||||
|
|
@ -137,7 +137,7 @@ pub struct BlacklistedPrincipal {
|
|||
pub data: Data,
|
||||
pub basic_info: PrincipalBasicInfo,
|
||||
pub game_key: GameKey,
|
||||
pub since: KerberosDateTime,
|
||||
pub since: DateTime,
|
||||
}
|
||||
#[derive(RmcSerialize, Debug)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -167,7 +167,7 @@ pub trait FriendsWiiU {
|
|||
&self,
|
||||
info: NNAInfo,
|
||||
presence: NintendoPresenceV2,
|
||||
date_time: KerberosDateTime,
|
||||
date_time: DateTime,
|
||||
) -> Result<
|
||||
(
|
||||
PrincipalPreference,
|
||||
|
|
@ -200,7 +200,7 @@ pub trait FriendsWiiU {
|
|||
unk2: u8,
|
||||
unk3: String,
|
||||
game_key: GameKey,
|
||||
unk4: KerberosDateTime,
|
||||
unk4: DateTime,
|
||||
) -> Result<(FriendRequest, FriendInfo), ErrorCode>;
|
||||
#[method_id(6)]
|
||||
async fn cancel_friend_request(&self, id: u64) -> Result<(), ErrorCode>;
|
||||
|
|
@ -222,9 +222,9 @@ pub trait FriendsWiiU {
|
|||
#[method_id(13)]
|
||||
async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode>;
|
||||
#[method_id(14)]
|
||||
async fn update_mii(&self, presence: MiiV2) -> Result<KerberosDateTime, ErrorCode>;
|
||||
async fn update_mii(&self, presence: MiiV2) -> Result<DateTime, ErrorCode>;
|
||||
#[method_id(15)]
|
||||
async fn update_comment(&self, presence: Comment) -> Result<KerberosDateTime, ErrorCode>;
|
||||
async fn update_comment(&self, presence: Comment) -> Result<DateTime, ErrorCode>;
|
||||
#[method_id(16)]
|
||||
async fn update_preference(&self, preference: PrincipalPreference) -> Result<(), ErrorCode>;
|
||||
#[method_id(17)]
|
||||
33
rnex-protocols/fpd-protos/src/lib.rs
Normal file
33
rnex-protocols/fpd-protos/src/lib.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#![allow(async_fn_in_trait)]
|
||||
|
||||
use rnex_rmc::define_rmc_proto;
|
||||
pub mod account_management;
|
||||
pub mod friends_3ds;
|
||||
pub mod friends_wiiu;
|
||||
pub mod nintendo_notification;
|
||||
use account_management::{
|
||||
AccountManagement, RawAccountManagement, RawAccountManagementInfo, RemoteAccountManagement,
|
||||
};
|
||||
use friends_3ds::{Friends3DS, RawFriends3DS, RawFriends3DSInfo, RemoteFriends3DS};
|
||||
use friends_wiiu::{FriendsWiiU, RawFriendsWiiU, RawFriendsWiiUInfo, RemoteFriendsWiiU};
|
||||
use nintendo_notification::{
|
||||
NintendoNotification, RawNintendoNotification, RawNintendoNotificationInfo,
|
||||
RemoteNintendoNotification,
|
||||
};
|
||||
|
||||
define_rmc_proto!(
|
||||
proto FriendsUser{
|
||||
FriendsWiiU,
|
||||
Friends3DS
|
||||
}
|
||||
);
|
||||
define_rmc_proto!(
|
||||
proto FriendRemote{
|
||||
NintendoNotification
|
||||
}
|
||||
);
|
||||
define_rmc_proto!(
|
||||
proto FriendsGuest{
|
||||
AccountManagement
|
||||
}
|
||||
);
|
||||
|
|
@ -1,9 +1,4 @@
|
|||
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||
|
||||
use rnex_core::PID;
|
||||
use rnex_core::rmc::structures::any::Any;
|
||||
|
||||
use crate::rmc::structures::data::Data;
|
||||
use rnex_rmc::{RmcSerialize, any::Any, data::Data, method_id, rmc_proto, util::PID};
|
||||
|
||||
#[derive(RmcSerialize)]
|
||||
#[rmc_struct(0)]
|
||||
22
rnex-protocols/mm-protos/Cargo.toml
Normal file
22
rnex-protocols/mm-protos/Cargo.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
name = "rnex-mm-protos"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
ctor = "1.0.8"
|
||||
rnex-rmc = { path = "../../rnex-rmc" }
|
||||
cfg-if = "1.0.4"
|
||||
rnex-base-protos = { path = "../base-protos" }
|
||||
|
||||
[features]
|
||||
third-notif-param = []
|
||||
v3-3-2 = []
|
||||
v3-4-0 = ["v3-3-2", "third-notif-param"]
|
||||
v3-5-0 = ["v3-4-0"]
|
||||
v3-8-15 = ["v3-5-0"]
|
||||
v3-10-22 = ["v3-8-15"]
|
||||
v4-3-11 = ["v3-8-15"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue