forked from baron/baron-sso
196 lines
5.4 KiB
Dart
196 lines
5.4 KiB
Dart
enum LoginChallengeSource { widget, uriQuery, rawSearch, rawHref, missing }
|
|
|
|
class LoginChallengeResolution {
|
|
final String? value;
|
|
final LoginChallengeSource source;
|
|
final bool uriHasLoginChallenge;
|
|
final bool rawSearchHasLoginChallenge;
|
|
final bool rawHrefHasLoginChallenge;
|
|
|
|
const LoginChallengeResolution({
|
|
required this.value,
|
|
required this.source,
|
|
required this.uriHasLoginChallenge,
|
|
required this.rawSearchHasLoginChallenge,
|
|
required this.rawHrefHasLoginChallenge,
|
|
});
|
|
|
|
Map<String, Object?> toDiagnostics() {
|
|
return {
|
|
'resolved_value_len': value?.length ?? 0,
|
|
'resolved_source': source.name,
|
|
'uri_has_login_challenge': uriHasLoginChallenge,
|
|
'raw_search_has_login_challenge': rawSearchHasLoginChallenge,
|
|
'raw_href_has_login_challenge': rawHrefHasLoginChallenge,
|
|
};
|
|
}
|
|
}
|
|
|
|
LoginChallengeResolution resolveLoginChallenge({
|
|
String? widgetLoginChallenge,
|
|
required Uri uri,
|
|
String? rawSearch,
|
|
String? rawHref,
|
|
}) {
|
|
final widgetValue = _normalizeChallenge(widgetLoginChallenge);
|
|
if (widgetValue != null) {
|
|
return const LoginChallengeResolution(
|
|
value: null,
|
|
source: LoginChallengeSource.widget,
|
|
uriHasLoginChallenge: false,
|
|
rawSearchHasLoginChallenge: false,
|
|
rawHrefHasLoginChallenge: false,
|
|
).copyWith(value: widgetValue);
|
|
}
|
|
|
|
final uriValue = _normalizeChallenge(uri.queryParameters['login_challenge']);
|
|
if (uriValue != null) {
|
|
return const LoginChallengeResolution(
|
|
value: null,
|
|
source: LoginChallengeSource.uriQuery,
|
|
uriHasLoginChallenge: true,
|
|
rawSearchHasLoginChallenge: false,
|
|
rawHrefHasLoginChallenge: false,
|
|
).copyWith(value: uriValue);
|
|
}
|
|
|
|
final rawSearchValue = _normalizeChallenge(
|
|
_extractQueryParamFromRawQuery(rawSearch, 'login_challenge'),
|
|
);
|
|
if (rawSearchValue != null) {
|
|
return const LoginChallengeResolution(
|
|
value: null,
|
|
source: LoginChallengeSource.rawSearch,
|
|
uriHasLoginChallenge: false,
|
|
rawSearchHasLoginChallenge: true,
|
|
rawHrefHasLoginChallenge: false,
|
|
).copyWith(value: rawSearchValue);
|
|
}
|
|
|
|
final rawHrefValue = _normalizeChallenge(
|
|
_extractQueryParamFromRawHref(rawHref, 'login_challenge'),
|
|
);
|
|
if (rawHrefValue != null) {
|
|
return const LoginChallengeResolution(
|
|
value: null,
|
|
source: LoginChallengeSource.rawHref,
|
|
uriHasLoginChallenge: false,
|
|
rawSearchHasLoginChallenge: false,
|
|
rawHrefHasLoginChallenge: true,
|
|
).copyWith(value: rawHrefValue);
|
|
}
|
|
|
|
return const LoginChallengeResolution(
|
|
value: null,
|
|
source: LoginChallengeSource.missing,
|
|
uriHasLoginChallenge: false,
|
|
rawSearchHasLoginChallenge: false,
|
|
rawHrefHasLoginChallenge: false,
|
|
);
|
|
}
|
|
|
|
String? _normalizeChallenge(String? value) {
|
|
final trimmed = value?.trim();
|
|
if (trimmed == null || trimmed.isEmpty) {
|
|
return null;
|
|
}
|
|
return trimmed;
|
|
}
|
|
|
|
String? _extractQueryParamFromRawHref(String? rawHref, String key) {
|
|
final href = rawHref?.trim();
|
|
if (href == null || href.isEmpty) {
|
|
return null;
|
|
}
|
|
|
|
final parsed = Uri.tryParse(href);
|
|
final fromParsed = parsed?.queryParameters[key];
|
|
final normalizedParsed = _normalizeChallenge(fromParsed);
|
|
if (normalizedParsed != null) {
|
|
return normalizedParsed;
|
|
}
|
|
|
|
final question = href.indexOf('?');
|
|
if (question < 0) {
|
|
return null;
|
|
}
|
|
final hash = href.indexOf('#', question + 1);
|
|
final rawQuery = hash < 0
|
|
? href.substring(question + 1)
|
|
: href.substring(question + 1, hash);
|
|
return _extractQueryParamFromRawQuery(rawQuery, key);
|
|
}
|
|
|
|
String? _extractQueryParamFromRawQuery(String? rawQuery, String key) {
|
|
final query = rawQuery?.trim();
|
|
if (query == null || query.isEmpty) {
|
|
return null;
|
|
}
|
|
|
|
final normalizedQuery = query.startsWith('?') ? query.substring(1) : query;
|
|
if (normalizedQuery.isEmpty) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
final parsed = Uri.splitQueryString(normalizedQuery);
|
|
final value = _normalizeChallenge(parsed[key]);
|
|
if (value != null) {
|
|
return value;
|
|
}
|
|
} catch (_) {
|
|
// URI 파싱이 실패하면 수동 파싱으로 보완합니다.
|
|
}
|
|
|
|
for (final pair in normalizedQuery.split('&')) {
|
|
if (pair.isEmpty) {
|
|
continue;
|
|
}
|
|
final equalIndex = pair.indexOf('=');
|
|
final rawKey = equalIndex < 0 ? pair : pair.substring(0, equalIndex);
|
|
final decodedKey = _decodeQueryComponentSafe(rawKey);
|
|
if (decodedKey != key) {
|
|
continue;
|
|
}
|
|
if (equalIndex < 0) {
|
|
return null;
|
|
}
|
|
final rawValue = pair.substring(equalIndex + 1);
|
|
final decodedValue = _normalizeChallenge(
|
|
_decodeQueryComponentSafe(rawValue),
|
|
);
|
|
if (decodedValue != null) {
|
|
return decodedValue;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
String _decodeQueryComponentSafe(String value) {
|
|
try {
|
|
return Uri.decodeQueryComponent(value);
|
|
} catch (_) {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
extension on LoginChallengeResolution {
|
|
LoginChallengeResolution copyWith({
|
|
String? value,
|
|
LoginChallengeSource? source,
|
|
bool? uriHasLoginChallenge,
|
|
bool? rawSearchHasLoginChallenge,
|
|
bool? rawHrefHasLoginChallenge,
|
|
}) {
|
|
return LoginChallengeResolution(
|
|
value: value ?? this.value,
|
|
source: source ?? this.source,
|
|
uriHasLoginChallenge: uriHasLoginChallenge ?? this.uriHasLoginChallenge,
|
|
rawSearchHasLoginChallenge:
|
|
rawSearchHasLoginChallenge ?? this.rawSearchHasLoginChallenge,
|
|
rawHrefHasLoginChallenge:
|
|
rawHrefHasLoginChallenge ?? this.rawHrefHasLoginChallenge,
|
|
);
|
|
}
|
|
}
|