Files
umbrix/lib/utils/link_parsers.dart

103 lines
3.0 KiB
Dart
Raw Normal View History

2023-10-02 18:51:14 +03:30
import 'dart:convert';
2023-10-05 21:28:52 +03:30
import 'package:hiddify/domain/singbox/singbox.dart';
2023-07-06 17:18:41 +03:30
import 'package:hiddify/utils/validators.dart';
typedef ProfileLink = ({String url, String name});
// TODO: test and improve
abstract class LinkParser {
2023-11-12 22:22:20 +03:30
static String generateSubShareLink(String url, [String? name]) {
final uri = Uri.tryParse(url);
if (uri == null) return '';
return Uri(
scheme: 'hiddify',
host: 'install-sub',
queryParameters: {
"url": uri.toString(),
if (name != null) "name": name,
},
).toString();
}
2023-10-02 18:51:14 +03:30
// protocols schemas
static const protocols = {'clash', 'clashmeta', 'sing-box', 'hiddify'};
2023-10-05 21:28:52 +03:30
static const rawProtocols = {
'ss',
'vmess',
'vless',
'trojan',
'tuic',
'hysteria2',
'ssh',
};
2023-08-27 10:49:34 +03:30
static ProfileLink? parse(String link) {
return simple(link) ?? deep(link);
}
2023-07-06 17:18:41 +03:30
static ProfileLink? simple(String link) {
if (!isUrl(link)) return null;
2023-08-26 16:26:32 +03:30
final uri = Uri.parse(link.trim());
2023-07-06 17:18:41 +03:30
return (
url: uri.toString(),
2023-10-02 18:51:14 +03:30
name: uri.queryParameters['name'] ?? '',
2023-07-06 17:18:41 +03:30
);
}
2023-10-02 18:51:14 +03:30
static ({String content, String name})? protocol(String content) {
final lines = safeDecodeBase64(content).split('\n');
for (final line in lines) {
final uri = Uri.tryParse(line);
if (uri == null) continue;
final fragment =
uri.hasFragment ? Uri.decodeComponent(uri.fragment) : null;
final name = switch (uri.scheme) {
2023-10-05 21:28:52 +03:30
'ss' => fragment ?? ProxyType.shadowsocks.label,
'vmess' => ProxyType.vmess.label,
2023-10-02 18:51:14 +03:30
'vless' => fragment ?? ProxyType.vless.label,
2023-10-05 21:28:52 +03:30
'trojan' => fragment ?? ProxyType.trojan.label,
2023-10-02 18:51:14 +03:30
'tuic' => fragment ?? ProxyType.tuic.label,
2023-10-05 21:28:52 +03:30
'hy2' || 'hysteria2' => fragment ?? ProxyType.hysteria.label,
'ssh' => fragment ?? ProxyType.ssh.label,
2023-10-02 18:51:14 +03:30
_ => null,
};
if (name != null) {
return (content: content, name: name);
}
}
return null;
}
2023-07-06 17:18:41 +03:30
static ProfileLink? deep(String link) {
2023-08-26 23:35:17 +03:30
final uri = Uri.tryParse(link.trim());
if (uri == null || !uri.hasScheme || !uri.hasAuthority) return null;
final queryParams = uri.queryParameters;
switch (uri.scheme) {
2023-10-02 18:51:14 +03:30
case 'clash' || 'clashmeta' when uri.authority == 'install-config':
2023-08-26 23:35:17 +03:30
if (uri.authority != 'install-config' ||
!queryParams.containsKey('url')) return null;
return (url: queryParams['url']!, name: queryParams['name'] ?? '');
case 'sing-box':
if (uri.authority != 'import-remote-profile' ||
!queryParams.containsKey('url')) return null;
return (url: queryParams['url']!, name: queryParams['name'] ?? '');
2023-08-27 10:49:34 +03:30
case 'hiddify':
if ((uri.authority != 'install-config' &&
uri.authority != 'install-sub') ||
!queryParams.containsKey('url')) return null;
return (url: queryParams['url']!, name: queryParams['name'] ?? '');
2023-08-26 23:35:17 +03:30
default:
return null;
}
2023-07-06 17:18:41 +03:30
}
}
2023-10-02 18:51:14 +03:30
String safeDecodeBase64(String str) {
try {
return utf8.decode(base64Decode(str));
} catch (e) {
return str;
}
}