Skip to content

Commit bbf9db0

Browse files
Mivikclaude
andcommitted
fix(hykb): tear down session on failed login callback
The standalone anti-addiction bridge is gone: the login SDK now reports anti-addiction as login failure codes 2001..=2005, so drop AA_TX, anti_addiction_action, antiAddictionCallback and the 500/1001/1030/1050/ 9002 handling. HykbCredential::ok_or_err now force-logs-out (SDK logout + clear tokens) on any non-zero code. This closes the bypass where cancelling the HYKB prompt (2003) during a silent re-verify only showed "login cancelled" but left the player signed in. hykbLoginCallback handles the async anti-addiction "exit game" code 2005 (delivered with no login in flight) by quitting the game. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 0d7c616 commit bbf9db0

3 files changed

Lines changed: 34 additions & 107 deletions

File tree

phira/src/client.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ mod model;
44
pub use model::*;
55
use tracing::debug;
66

7-
use crate::{anti_addiction_action, get_data, get_data_mut, save_data};
7+
use crate::{get_data, get_data_mut, save_data};
88
use anyhow::{anyhow, bail, Context, Result};
99
use arc_swap::ArcSwap;
1010
use once_cell::sync::Lazy;
@@ -243,10 +243,11 @@ impl Client {
243243
}
244244

245245
/// Persist a freshly minted token pair and wire it into the HTTP client.
246-
/// Shared by every login entry point (password, refresh, HYKB).
247-
async fn store_login(id: i32, token: String, refresh_token: String) -> Result<()> {
248-
anti_addiction_action("startup", Some(format!("phira-{id}")));
249-
246+
/// Shared by every login entry point (password, refresh, HYKB). `_id` is
247+
/// kept in the signature so callers can pass the account id even though it
248+
/// is no longer needed here (the native anti-addiction bridge that used it
249+
/// is gone).
250+
async fn store_login(_id: i32, token: String, refresh_token: String) -> Result<()> {
250251
set_access_token(&token).await?;
251252
get_data_mut().tokens = Some((token, refresh_token));
252253
save_data()?;

phira/src/lib.rs

Lines changed: 28 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,14 @@ mod threed;
2424
mod uml;
2525

2626
use anyhow::Result;
27-
use core::f64;
2827
use data::Data;
2928
use macroquad::prelude::*;
3029
use prpr::{
3130
build_conf,
3231
core::{init_assets, PGR_FONT},
3332
ext::SafeTexture,
3433
log,
35-
scene::{show_error, show_message},
34+
scene::show_error,
3635
time::TimeManager,
3736
ui::{FontArc, TextPainter},
3837
Main,
@@ -53,7 +52,6 @@ use jni::{
5352
};
5453

5554
static MESSAGES_TX: Mutex<Option<mpsc::Sender<bool>>> = Mutex::new(None);
56-
static AA_TX: Mutex<Option<mpsc::Sender<i32>>> = Mutex::new(None);
5755
static DATA_PATH: Mutex<Option<String>> = Mutex::new(None);
5856
static CACHE_DIR: Mutex<Option<String>> = Mutex::new(None);
5957
pub static mut DATA: Option<Data> = None;
@@ -211,23 +209,11 @@ async fn the_main() -> Result<()> {
211209
rx
212210
};
213211

214-
let aa_rx = {
215-
let (tx, rx) = mpsc::channel();
216-
*AA_TX.lock().unwrap() = Some(tx);
217-
rx
218-
};
219-
220212
unsafe { get_internal_gl() }
221213
.quad_context
222214
.display_mut()
223215
.set_pause_resume_listener(on_pause_resume);
224216

225-
if let Some(me) = &get_data().me {
226-
anti_addiction_action("startup", Some(format!("phira-{}", me.id)));
227-
// The native HYKB SDK is (re)entered and verified against the restored
228-
// session by the blocking startup check in `HomePage`, not here.
229-
}
230-
231217
let pgr_font = FontArc::try_from_vec(load_file("phigros.ttf").await?)?;
232218
PGR_FONT.with(move |it| *it.borrow_mut() = Some(TextPainter::new(pgr_font, None)));
233219

@@ -244,8 +230,6 @@ async fn the_main() -> Result<()> {
244230
let mut last_frame_start = f32::NAN;
245231
let mut fps_time_sum = 0.;
246232

247-
let mut exit_time = f64::INFINITY;
248-
249233
'app: loop {
250234
let frame_start = tm.real_time();
251235
if !last_frame_start.is_nan() {
@@ -277,48 +261,8 @@ async fn the_main() -> Result<()> {
277261
break 'app;
278262
}
279263

280-
if let Ok(code) = aa_rx.try_recv() {
281-
info!("anti addiction callback: {code}");
282-
match code {
283-
// login success
284-
500 => {
285-
anti_addiction_action("enterGame", None);
286-
}
287-
// switch account
288-
1001 => {
289-
anti_addiction_action("exit", None);
290-
get_data_mut().me = None;
291-
get_data_mut().tokens = None;
292-
let _ = save_data();
293-
sync_data();
294-
use crate::login::L10N_LOCAL;
295-
show_message(crate::login::tl!("logged-out")).ok();
296-
}
297-
// period restrict
298-
1030 => {
299-
show_and_exit("你当前为未成年账号,已被纳入防沉迷系统。根据国家相关规定,周五、周六、周日及法定节假日 20 点 - 21 点之外为健康保护时段。当前时间段无法游玩,请合理安排时间。");
300-
exit_time = frame_start;
301-
}
302-
// duration limit
303-
1050 => {
304-
show_and_exit("你当前为未成年账号,已被纳入防沉迷系统。根据国家相关规定,周五、周六、周日及法定节假日 20 点 - 21 点之外为健康保护时段。你已达时间限制,无法继续游戏。");
305-
exit_time = frame_start;
306-
}
307-
// stopped
308-
9002 => {
309-
show_and_exit("必须实名认证方可进行游戏。");
310-
exit_time = frame_start;
311-
}
312-
_ => {}
313-
}
314-
}
315-
316264
let t = tm.real_time();
317265

318-
if t > exit_time + 5. {
319-
break;
320-
}
321-
322266
let fps_now = t as i32;
323267
if fps_now != fps_time {
324268
fps_time = fps_now;
@@ -334,13 +278,6 @@ async fn the_main() -> Result<()> {
334278
Ok(())
335279
}
336280

337-
fn show_and_exit(msg: &str) {
338-
prpr::ui::Dialog::simple(msg)
339-
.buttons(vec!["确定".to_owned()])
340-
.listener(|_, _| std::process::exit(0))
341-
.show();
342-
}
343-
344281
fn build_global_window_conf() -> Conf {
345282
let mut conf = build_conf();
346283
conf.window_title = "Phira".to_owned();
@@ -388,7 +325,6 @@ pub extern "C" fn Java_quad_1native_QuadNative_initializeEnvironment(env: EnvUno
388325
#[cfg(target_os = "android")]
389326
#[no_mangle]
390327
pub extern "C" fn Java_quad_1native_QuadNative_prprActivityOnPause(_env: EnvUnowned, _class: JClass) {
391-
anti_addiction_action("leaveGame", None);
392328
if let Some(tx) = MESSAGES_TX.lock().unwrap().as_mut() {
393329
let _ = tx.send(true);
394330
}
@@ -397,7 +333,6 @@ pub extern "C" fn Java_quad_1native_QuadNative_prprActivityOnPause(_env: EnvUnow
397333
#[cfg(target_os = "android")]
398334
#[no_mangle]
399335
pub extern "C" fn Java_quad_1native_QuadNative_prprActivityOnResume(_env: EnvUnowned, _class: JClass) {
400-
anti_addiction_action("enterGame", None);
401336
if let Some(tx) = MESSAGES_TX.lock().unwrap().as_mut() {
402337
let _ = tx.send(false);
403338
}
@@ -459,40 +394,6 @@ pub extern "C" fn Java_quad_1native_QuadNative_setInputText(_env: EnvUnowned, _c
459394
INPUT_TEXT.lock().unwrap().1 = Some(text.to_string());
460395
}
461396

462-
#[cfg(not(all(target_os = "android", feature = "hykb")))]
463-
pub fn anti_addiction_action(_action: &str, _arg: Option<String>) {}
464-
465-
#[cfg(all(target_os = "android", feature = "hykb"))]
466-
pub fn anti_addiction_action(action: &str, arg: Option<String>) {
467-
use jni::{jni_sig, jni_str, objects::JObject, vm::JavaVM};
468-
469-
JavaVM::singleton()
470-
.unwrap()
471-
.attach_current_thread(|env| -> jni::errors::Result<()> {
472-
let ctx = unsafe { JObject::from_raw(env, ndk_context::android_context().context() as _) };
473-
let action = env.new_string(action)?;
474-
#[allow(clippy::redundant_closure)]
475-
let arg = arg
476-
.as_ref()
477-
.map(|it| env.new_string(it))
478-
.transpose()?
479-
.map_or_else(|| JObject::null(), |s| s.into());
480-
env.call_method(ctx, jni_str!("antiAddiction"), jni_sig!("(Ljava/lang/String;Ljava/lang/String;)V"), &[(&action).into(), (&arg).into()])?;
481-
Ok(())
482-
})
483-
.unwrap();
484-
}
485-
486-
#[cfg(target_os = "android")]
487-
#[no_mangle]
488-
pub extern "C" fn Java_quad_1native_QuadNative_antiAddictionCallback(_env: EnvUnowned, _class: JClass, #[allow(dead_code)] code: jint) {
489-
if cfg!(feature = "hykb") {
490-
if let Some(tx) = AA_TX.lock().unwrap().as_mut() {
491-
let _ = tx.send(code);
492-
}
493-
}
494-
}
495-
496397
/// Credentials obtained from the native HYKB (好游快爆) login SDK.
497398
pub struct HykbCredential {
498399
/// SDK result code: 0 on success, otherwise an error / user cancellation.
@@ -511,6 +412,14 @@ impl HykbCredential {
511412
if self.code == 0 {
512413
Ok(self)
513414
} else {
415+
// A non-zero code is any failure the HYKB SDK reports: 2001 auth
416+
// failed, 2002 login failed, 2003 cancelled, 2004 exception, 2005
417+
// developer-requested exit / account logout. A HYKB build mandates a
418+
// valid, matching HYKB session, so every one of these must tear the
419+
// in-game session down — otherwise cancelling the HYKB prompt during
420+
// a silent re-verify would leave the player signed in and bypass the
421+
// gate entirely.
422+
force_logout();
514423
anyhow::bail!("{}", crate::ttl!("hykb-login-cancelled"))
515424
}
516425
}
@@ -566,6 +475,18 @@ pub fn hykb_logout() {
566475
#[cfg(not(all(target_os = "android", feature = "hykb")))]
567476
pub fn hykb_logout() {}
568477

478+
/// Tear down the local session: sign out of the native HYKB SDK, clear the
479+
/// stored account and tokens, then re-sync. Shared by every path that must
480+
/// reject a login — a failed/cancelled HYKB verification, a uid mismatch, or
481+
/// the player logging out from their profile.
482+
pub fn force_logout() {
483+
hykb_logout();
484+
get_data_mut().me = None;
485+
get_data_mut().tokens = None;
486+
let _ = save_data();
487+
sync_data();
488+
}
489+
569490
/// Trigger the native HYKB login and await its credentials.
570491
#[allow(unused)]
571492
pub async fn obtain_hykb_credential() -> Result<HykbCredential> {
@@ -611,6 +532,13 @@ pub extern "C" fn Java_quad_1native_QuadNative_hykbLoginCallback(
611532
nick,
612533
access_token,
613534
});
535+
} else if code == 2005 {
536+
// No login is in flight, so this is the SDK's asynchronous
537+
// anti-addiction "exit game" action: the player hit a play-time limit
538+
// and chose to quit from the SDK's own dialog. Honor it by exiting.
539+
// Other async codes (e.g. 2008 "continue playing") are handled inside
540+
// the SDK and need no response here.
541+
std::process::exit(0);
614542
}
615543
}
616544

phira/src/scene/profile.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ prpr_l10n::tl_file!("profile");
44
use super::confirm_dialog;
55
use super::{confirm_delete, TEX_BACKGROUND, TEX_ICON_BACK};
66
use crate::{
7-
anti_addiction_action,
87
client::{recv_raw, Client, Record, User, UserManager},
98
get_data, get_data_mut, hykb_logout,
109
page::{Fader, Illustration, SFader},
@@ -374,7 +373,6 @@ impl Scene for ProfileScene {
374373
return Ok(true);
375374
}
376375
if self.btn_logout.touch(touch, t) {
377-
anti_addiction_action("exit", None);
378376
hykb_logout();
379377
get_data_mut().me = None;
380378
get_data_mut().tokens = None;

0 commit comments

Comments
 (0)