TF-4145 Add generateWebLink and safeGenerateWebLink with FQDN validation

This commit is contained in:
dab246
2025-11-12 17:29:05 +07:00
committed by Dat H. Pham
parent 9483c98dd2
commit 8b5fb2f030
3 changed files with 223 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
import 'package:core/core.dart';
/// Utility class for generating web links in flat subdomain format.
class WebLinkGenerator {
const WebLinkGenerator();
/// Ensures that a path starts with `/`.
String ensureFirstSlash(String? path) {
if (path == null || path.isEmpty) return '/';
return path.startsWith('/') ? path : '/$path';
}
/// Validates if a given FQDN looks valid (has at least 2 parts and non-empty).
bool isValidFqdn(String fqdn) {
if (fqdn.trim().isEmpty || !fqdn.contains('.')) return false;
final parts = fqdn.split('.').where((p) => p.trim().isNotEmpty).toList();
return parts.length >= 2;
}
/// Generates a web link based on a workplace FQDN and app slug.
///
/// Throws [ArgumentError] when input is invalid.
String generateWebLink({
required String workplaceFqdn,
required String slug,
String? pathname,
String? hash,
List<List<String>>? searchParams,
}) {
if (!isValidFqdn(workplaceFqdn)) {
throw ArgumentError('Invalid workplace FQDN: $workplaceFqdn');
}
final hostParts = workplaceFqdn
.split('.')
.where((p) => p.trim().isNotEmpty)
.toList();
hostParts[0] = '${hostParts[0]}-$slug';
final newHost = hostParts.join('.');
final safePath = ensureFirstSlash(pathname);
final safeHash = (hash == null || hash.isEmpty) ? null : ensureFirstSlash(hash);
final queryParams = <String, String>{};
for (final param in searchParams ?? const []) {
if (param.length == 2) queryParams[param[0]] = param[1];
}
final uri = Uri(
scheme: 'https',
host: newHost,
path: safePath,
queryParameters: queryParams.isEmpty ? null : queryParams,
fragment: safeHash,
);
return uri.toString();
}
/// A safe version of [generateWebLink] that **never throws**.
///
/// Returns `''` (empty string) when an error occurs.
String safeGenerateWebLink({
required String workplaceFqdn,
required String slug,
String? pathname,
String? hash,
List<List<String>>? searchParams,
}) {
try {
if (slug.trim().isEmpty) return '';
return generateWebLink(
workplaceFqdn: workplaceFqdn,
slug: slug,
pathname: pathname,
hash: hash,
searchParams: searchParams,
);
} catch (e) {
logError('[WebLinkGenerator] Error: $e');
return '';
}
}
}