fix: follow undergraduate login links and capture live history URLs
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user