fix: follow undergraduate login links and capture live history URLs

This commit is contained in:
Codex
2026-10-15 17:17:54 +08:00
parent 79d268fd5e
commit defe7fd50e
14 changed files with 213 additions and 32 deletions
@@ -17,6 +17,23 @@ class UndergraduateNavigationPolicy {
uri.path.startsWith('/eams/');
static bool isLogout(Uri uri) =>
isDataPage(uri) && uri.path == '/eams/logout.action';
static Uri? secureIdentityRedirect(Uri uri) =>
SchoolNavigationPolicy.secureIdentityRedirect(uri);
static Uri? secureIdentityRedirect(Uri uri) {
final identity = SchoolNavigationPolicy.secureIdentityRedirect(uri);
if (identity != null) return identity;
// Legacy duplicate-login links use HTTP even within the HTTPS portal.
if (uri.scheme != 'http' ||
uri.host != 'eams.uestc.edu.cn' ||
uri.port != 80 ||
uri.userInfo.isNotEmpty ||
!(uri.path == '/eams' || uri.path.startsWith('/eams/'))) {
return null;
}
return Uri(
scheme: 'https',
host: uri.host,
path: uri.path,
query: uri.hasQuery ? uri.query : null,
fragment: uri.hasFragment ? uri.fragment : null,
);
}
}
@@ -67,9 +67,10 @@ class UndergraduateFragment {
}
class UndergraduatePageEvidence {
const UndergraduatePageEvidence(this.authenticated, this.pages);
const UndergraduatePageEvidence(this.authenticated, this.pages, this.url);
final bool authenticated;
final List<UndergraduateFragment> pages;
final Uri url;
static UndergraduatePageEvidence decode(Object raw, Uri current) {
try {
dynamic value = raw;
@@ -116,6 +117,7 @@ class UndergraduatePageEvidence {
return UndergraduatePageEvidence(
value['authenticated'] == true,
List.unmodifiable(result),
current,
);
} on FormatException {
rethrow;
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:webview_flutter/webview_flutter.dart';
@@ -318,13 +319,35 @@ class UndergraduateSession extends ChangeNotifier {
});
}
Future<UndergraduatePageEvidence> _evidence(Uri uri, bool capture) async =>
UndergraduatePageEvidence.decode(
await web.runJavaScriptReturningResult(
capture ? undergraduateCaptureScript : undergraduateStatusProbeScript,
),
uri,
Future<UndergraduatePageEvidence> _evidence(Uri uri, bool capture) async {
// loadDataWithBaseURL can leave native getUrl at the original address after
// the school's History API changes location. Bind capture to the live URL,
// still requiring the native and live documents to share the school origin.
dynamic location = await web.runJavaScriptReturningResult('location.href');
if (location is String && location.startsWith('"')) {
location = jsonDecode(location);
}
final live = location is String ? Uri.tryParse(location) : null;
if (live == null ||
!UndergraduateNavigationPolicy.isDataPage(uri) ||
!UndergraduateNavigationPolicy.isDataPage(live) ||
uri.origin != live.origin) {
throw const FormatException('页面来源无效,请重新打开学校课表。');
}
if (live != uri) {
DiagnosticLog.instance.add(
'school_document_url',
fields: {'school': 'undergraduate', 'code': 'history_state'},
);
}
return UndergraduatePageEvidence.decode(
await web.runJavaScriptReturningResult(
capture ? undergraduateCaptureScript : undergraduateStatusProbeScript,
),
live,
);
}
Future<void> _loaded(String url) async {
DiagnosticLog.instance.navigation('undergraduate', 'finished', url);
final g = _generation, d = _document, key = '$_generation:$_document';
@@ -361,18 +384,20 @@ class UndergraduateSession extends ChangeNotifier {
}
_connected = true;
awaitingAuthentication = false;
final recovery = await _pageRecovery.tryRestore(
web,
uri,
authenticated: true,
documentKey: '$g:$d',
isCurrent: () => _valid(g) && d == _document,
onStarted: () {
_recoveringPage = true;
message = '已登录,正在恢复完整教务页面…';
_emit();
},
);
final recovery = uri != status.url
? FullPageRecoveryResult.unchanged
: await _pageRecovery.tryRestore(
web,
uri,
authenticated: true,
documentKey: '$g:$d',
isCurrent: () => _valid(g) && d == _document,
onStarted: () {
_recoveringPage = true;
message = '已登录,正在恢复完整教务页面…';
_emit();
},
);
if (!_valid(g) || d != _document) return;
_recoveringPage = false;
if (recovery == FullPageRecoveryResult.restored) {
@@ -397,7 +422,7 @@ class UndergraduateSession extends ChangeNotifier {
_emit();
return;
}
if (_expected == null || uri.toString() != _expected.toString()) {
if (_expected == null || status.url.toString() != _expected.toString()) {
await _requestExam(g);
return;
}