denylist and other things
All checks were successful
Build and Test / minecraft-wiiu (push) Successful in 7m33s
Build and Test / wii-sports-club (push) Successful in 7m36s
Build and Test / splatoon (push) Successful in 7m37s
Build and Test / super-mario-maker (push) Successful in 8m24s
Build and Test / wii-u-chat (push) Successful in 7m40s
Build and Test / friends (push) Successful in 8m7s
Build and Test / fast-racing-neo (push) Successful in 7m15s
Build and Test / mario-tennis (push) Successful in 7m19s
Build and Test / sonic-transformed (push) Successful in 7m31s
Build and Test / puyopuyo (push) Successful in 7m31s
Build and Test / splatoon-testfire (push) Successful in 7m32s

This commit is contained in:
Maple Nebel 2026-07-08 13:05:44 +02:00
commit 976643c8f4
2 changed files with 256 additions and 19 deletions

View file

@ -1,10 +1,10 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::env;
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
use std::ops::Deref; use std::ops::Deref;
use std::process::id; use std::process::id;
use std::sync::{Arc, atomic::AtomicU32}; use std::sync::{Arc, atomic::AtomicU32};
use std::sync::{LazyLock, Weak}; use std::sync::{LazyLock, Weak};
use std::{env, mem};
use base64::{Engine as _, engine::general_purpose}; use base64::{Engine as _, engine::general_purpose};
use bytemuck::{Pod, Zeroable, bytes_of}; use bytemuck::{Pod, Zeroable, bytes_of};
@ -67,6 +67,7 @@ use crate::rmc::protocols::friends_3ds::{
}; };
use crate::rmc::protocols::friends_wiiu::FriendRequestMessage; use crate::rmc::protocols::friends_wiiu::FriendRequestMessage;
use crate::rmc::protocols::nintendo_notification::NintendoNotificationEventGeneral; use crate::rmc::protocols::nintendo_notification::NintendoNotificationEventGeneral;
use crate::rmc::response::ErrorCode::FPD_InvalidArgument;
use nex_account::grpc::ActCreateInfo; use nex_account::grpc::ActCreateInfo;
use nex_account::grpc::nex_account_service_client::NexAccountServiceClient; use nex_account::grpc::nex_account_service_client::NexAccountServiceClient;
use nex_account::{derive_pid_hmac, grpc_client}; use nex_account::{derive_pid_hmac, grpc_client};
@ -413,6 +414,16 @@ macro_rules! nna_info_from_record {
}}; }};
} }
macro_rules! game_key_from_record {
($record:expr) => {
GameKey {
data: Data {},
tid: $record.game_key_tid,
version: $record.game_key_version,
}
};
}
macro_rules! friend_request_from_record { macro_rules! friend_request_from_record {
($record:expr) => {{ ($record:expr) => {{
let (unk, unk2) = unsmoosh_from_i16($record.unks_1); let (unk, unk2) = unsmoosh_from_i16($record.unks_1);
@ -427,11 +438,7 @@ macro_rules! friend_request_from_record {
.naive_utc(), .naive_utc(),
), ),
friend_request_id: $record.id, friend_request_id: $record.id,
game_key: GameKey { game_key: game_key_from_record!($record),
data: Data {},
tid: $record.game_key_tid,
version: $record.game_key_version,
},
is_recieved: $record.is_recieved, is_recieved: $record.is_recieved,
message: $record.message, message: $record.message,
unk, unk,
@ -625,6 +632,31 @@ impl FriendsWiiU for FriendsUser {
}); });
} }
let Ok(denylist) = query!(
"
select
*
from denylist
inner join nintendo_network_accounts on other = nintendo_network_accounts.pid
where initiator = $1
",
self.pid
)
.fetch_all(get_db())
.await
.map(|v| {
v.into_iter()
.map(|v| BlacklistedPrincipal {
basic_info: basic_principal_from_record!(v),
since: KerberosDateTime::from_naive(v.since),
..Default::default()
})
.collect::<Vec<_>>()
}) else {
println!("error whilest getting friend requests");
return Err(ErrorCode::Core_SystemError);
};
self.fm self.fm
.users .users
.write() .write()
@ -649,7 +681,7 @@ impl FriendsWiiU for FriendsUser {
outgoing_friend_requests, outgoing_friend_requests,
incoming_friend_requests, incoming_friend_requests,
// todo: blacklisted principals // todo: blacklisted principals
vec![], denylist,
false, false,
// todo: persistent notifications // todo: persistent notifications
vec![], vec![],
@ -755,6 +787,22 @@ impl FriendsWiiU for FriendsUser {
) -> Result<(FriendRequest, FriendInfo), ErrorCode> { ) -> Result<(FriendRequest, FriendInfo), ErrorCode> {
unk1 = 0; unk1 = 0;
unk2 = 1; unk2 = 1;
let Ok(q) = query!(
"select * from denylist where initiator = $1 and other = $2",
friend,
self.pid
)
.fetch_optional(get_db())
.await
else {
return Err(ErrorCode::Authentication_AccountLibraryError);
};
if q.is_some() {
return Err(ErrorCode::FPD_FriendRequestBlocked);
}
// check for too many friend requests both ways // check for too many friend requests both ways
let Ok(query) = query!( let Ok(query) = query!(
"select count(recipient) from friend_requests where sender = $1", "select count(recipient) from friend_requests where sender = $1",
@ -875,7 +923,7 @@ impl FriendsWiiU for FriendsUser {
async fn cancel_friend_request(&self, id: u64) -> Result<(), ErrorCode> { async fn cancel_friend_request(&self, id: u64) -> Result<(), ErrorCode> {
let Ok(query) = query!( let Ok(query) = query!(
"delete from friend_requests where id = $1 and recipient = $2 returning recipient, sender", "delete from friend_requests where id = $1 and sender = $2 returning recipient",
bytemuck::cast::<_, i64>(id), bytemuck::cast::<_, i64>(id),
self.pid self.pid
) )
@ -886,7 +934,7 @@ impl FriendsWiiU for FriendsUser {
}; };
let users = self.fm.users.read().await; let users = self.fm.users.read().await;
if let Some(user) = users.get(&query.sender).and_then(|v| v.upgrade()) { if let Some(user) = users.get(&query.recipient).and_then(|v| v.upgrade()) {
drop(users); drop(users);
user.remote user.remote
@ -895,6 +943,7 @@ impl FriendsWiiU for FriendsUser {
sender: self.pid, sender: self.pid,
data: Any::new(&NintendoNotificationEventGeneral { data: Any::new(&NintendoNotificationEventGeneral {
param1: bytemuck::cast(self.pid), param1: bytemuck::cast(self.pid),
param2: id,
..Default::default() ..Default::default()
}) })
.expect("type error"), .expect("type error"),
@ -1017,11 +1066,97 @@ impl FriendsWiiU for FriendsUser {
} }
async fn delete_friend_request(&self, id: u64) -> Result<(), ErrorCode> { async fn delete_friend_request(&self, id: u64) -> Result<(), ErrorCode> {
Err(ErrorCode::Core_NotImplemented) let Ok(query) = query!(
"delete from friend_requests where id = $1 and recipient = $2 returning sender",
bytemuck::cast::<_, i64>(id),
self.pid
)
.fetch_one(get_db())
.await
else {
return Err(ErrorCode::FPD_InvalidMessageID);
};
let users = self.fm.users.read().await;
if let Some(user) = users.get(&query.sender).and_then(|v| v.upgrade()) {
drop(users);
user.remote
.process_nintendo_notification_event_1(NintendoNotificationEvent {
event_type: 26,
sender: self.pid,
data: Any::new(&NintendoNotificationEventGeneral {
param1: bytemuck::cast(self.pid),
param2: id,
..Default::default()
})
.expect("type error"),
})
.await;
}
Ok(())
} }
async fn deny_friend_request(&self, id: u64) -> Result<BlacklistedPrincipal, ErrorCode> { async fn deny_friend_request(&self, id: u64) -> Result<BlacklistedPrincipal, ErrorCode> {
Err(ErrorCode::Core_NotImplemented) let Ok(query) = query!(
"delete from friend_requests where id = $1 and recipient = $2 returning sender",
bytemuck::cast::<_, i64>(id),
self.pid
)
.fetch_one(get_db())
.await
else {
return Err(ErrorCode::FPD_InvalidMessageID);
};
if let Err(e) = query!(
"insert into denylist(initiator, other) VALUES ($1, $2)",
self.pid,
query.sender
)
.execute(get_db())
.await
{
println!("{}", e);
return Err(ErrorCode::FPD_InvalidMessageID);
};
let users = self.fm.users.read().await;
if let Some(user) = users.get(&query.sender).and_then(|v| v.upgrade()) {
drop(users);
user.remote
.process_nintendo_notification_event_1(NintendoNotificationEvent {
event_type: 26,
sender: self.pid,
data: Any::new(&NintendoNotificationEventGeneral {
param1: bytemuck::cast(self.pid),
param2: id,
..Default::default()
})
.expect("type error"),
})
.await;
}
let Ok(user) = query!(
"select * from nintendo_network_accounts where pid = $1",
query.sender
)
.fetch_one(get_db())
.await
else {
println!("attempt to get invalid user which is in friend request");
return Err(FPD_InvalidArgument);
};
Ok(BlacklistedPrincipal {
data: Data {},
basic_info: basic_principal_from_record!(user),
game_key: GameKey::default(),
since: KerberosDateTime::now(),
})
} }
async fn mark_friend_requests_as_received(&self, ids: Vec<u64>) -> Result<(), ErrorCode> { async fn mark_friend_requests_as_received(&self, ids: Vec<u64>) -> Result<(), ErrorCode> {
@ -1031,7 +1166,8 @@ impl FriendsWiiU for FriendsUser {
bytemuck::cast::<_, i64>(id) bytemuck::cast::<_, i64>(id)
) )
.execute(get_db()) .execute(get_db())
.await; .await
.ok();
} }
Ok(()) Ok(())
} }
@ -1040,11 +1176,50 @@ impl FriendsWiiU for FriendsUser {
&self, &self,
principal: BlacklistedPrincipal, principal: BlacklistedPrincipal,
) -> Result<BlacklistedPrincipal, ErrorCode> { ) -> Result<BlacklistedPrincipal, ErrorCode> {
Err(ErrorCode::Core_NotImplemented) if let Err(e) = query!(
"insert into denylist(initiator, other) VALUES ($1, $2)",
self.pid,
principal.basic_info.pid
)
.execute(get_db())
.await
{
println!("{}", e);
return Err(ErrorCode::FPD_InvalidMessageID);
};
let Ok(user) = query!(
"select * from nintendo_network_accounts where pid = $1",
principal.basic_info.pid
)
.fetch_one(get_db())
.await
else {
println!("attempt to get invalid user which is in friend request");
return Err(FPD_InvalidArgument);
};
Ok(BlacklistedPrincipal {
data: Data {},
basic_info: basic_principal_from_record!(user),
game_key: GameKey::default(),
since: KerberosDateTime::now(),
})
} }
async fn remove_blacklist(&self, id: PID) -> Result<(), ErrorCode> { async fn remove_blacklist(&self, id: PID) -> Result<(), ErrorCode> {
Err(ErrorCode::Core_NotImplemented) if let Err(e) = query!(
"delete from denylist where initiator = $1 and other = $2",
self.pid,
id
)
.execute(get_db())
.await
{
println!("{}", e);
return Err(ErrorCode::FPD_InvalidMessageID);
};
Ok(())
} }
async fn update_presence(&self, mut presence: NintendoPresenceV2) -> Result<(), ErrorCode> { async fn update_presence(&self, mut presence: NintendoPresenceV2) -> Result<(), ErrorCode> {
@ -1223,9 +1398,44 @@ impl FriendsWiiU for FriendsUser {
async fn get_request_block_settings( async fn get_request_block_settings(
&self, &self,
unk: Vec<u32>, pids: Vec<PID>,
) -> Result<Vec<PrincipalRequestBlockSetting>, ErrorCode> { ) -> Result<Vec<PrincipalRequestBlockSetting>, ErrorCode> {
Ok(vec![]) let mut blocked: Vec<_> = Vec::with_capacity(pids.len());
for pid in pids {
let Ok(denylist) = query!(
"
select
since
from denylist
where initiator = $1 and other = $2
",
pid,
self.pid
)
.fetch_optional(get_db())
.await
else {
println!("error whilest getting friend requests");
return Err(ErrorCode::Core_SystemError);
};
if denylist.is_some() {
blocked.push(PrincipalRequestBlockSetting {
data: Data {},
pid,
blocked: true,
});
} else {
blocked.push(PrincipalRequestBlockSetting {
data: Data {},
pid,
blocked: false,
});
}
}
Ok(blocked)
} }
} }
@ -1281,6 +1491,33 @@ impl Secure for FriendsGuest {
} }
} }
impl Drop for FriendsUser {
fn drop(&mut self) {
let friends = mem::take(&mut self.maybe_remote_friend);
let users = friends.into_inner();
let pid = self.pid;
for user in users {
let Some(user) = user.1.upgrade() else {
continue;
};
tokio::spawn(async move {
user.remote
.process_nintendo_notification_event_2(NintendoNotificationEvent {
event_type: 10,
sender: pid,
data: Any::new(&NintendoNotificationEventGeneral {
param1: bytemuck::cast(pid),
..Default::default()
})
.expect("type error"),
})
.await;
});
}
}
}
impl AccountManagement for FriendsGuest { impl AccountManagement for FriendsGuest {
async fn nintendo_create_account( async fn nintendo_create_account(
&self, &self,

View file

@ -11,7 +11,7 @@ use rnex_core::PID;
pub struct MiiV2 { pub struct MiiV2 {
#[extends] #[extends]
pub data: Data, pub data: Data,
pub name: String, pub name: Vec<u8>,
pub unk: u8, pub unk: u8,
pub unk2: u8, pub unk2: u8,
pub mii_data: Vec<u8>, pub mii_data: Vec<u8>,
@ -128,7 +128,7 @@ pub struct FriendRequest {
pub sent_on: KerberosDateTime, pub sent_on: KerberosDateTime,
} }
#[derive(RmcSerialize, Debug)] #[derive(RmcSerialize, Debug, Default)]
#[rmc_struct(0)] #[rmc_struct(0)]
pub struct BlacklistedPrincipal { pub struct BlacklistedPrincipal {
#[extends] #[extends]
@ -237,6 +237,6 @@ pub trait FriendsWiiU {
#[method_id(20)] #[method_id(20)]
async fn get_request_block_settings( async fn get_request_block_settings(
&self, &self,
unk: Vec<u32>, pids: Vec<PID>,
) -> Result<Vec<PrincipalRequestBlockSetting>, ErrorCode>; ) -> Result<Vec<PrincipalRequestBlockSetting>, ErrorCode>;
} }