kopia lustrzana https://gitlab.com/mysocialportal/relatica
137 wiersze
3.6 KiB
Dart
137 wiersze
3.6 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:result_monad/result_monad.dart';
|
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
|
|
import '../models/exec_error.dart';
|
|
import '../models/server_data.dart';
|
|
import 'networking/network_services.dart';
|
|
|
|
part 'fediverse_server_validator_services.g.dart';
|
|
|
|
final _blueSkyData = ServerData(
|
|
domainName: 'bsky.app',
|
|
isFediverse: true,
|
|
protocols: [
|
|
'ATProto',
|
|
],
|
|
);
|
|
|
|
final _threadsData = ServerData(
|
|
domainName: 'threads.net',
|
|
isFediverse: true,
|
|
protocols: [
|
|
'activitypub',
|
|
],
|
|
);
|
|
|
|
final _threadsWwwData = ServerData(
|
|
domainName: 'www.threads.net',
|
|
isFediverse: true,
|
|
protocols: [
|
|
'activitypub',
|
|
],
|
|
);
|
|
|
|
final _knownServers = <String, ServerData>{
|
|
threadsDomain: _threadsData,
|
|
threadsWwwDomain: _threadsData,
|
|
blueskyDomain: _blueSkyData,
|
|
};
|
|
|
|
const blueskyDomain = 'bsky.app';
|
|
const threadsDomain = 'threads.net';
|
|
const threadsWwwDomain = 'www.threads.net';
|
|
|
|
const softwareTypeDiaspora = 'diaspora';
|
|
|
|
@riverpod
|
|
Future<Result<bool, ExecError>> checkIfFromFediverse(
|
|
Ref ref,
|
|
String url,
|
|
) async {
|
|
final dataResult = await ref.watch(serverDataProvider(url).future);
|
|
return dataResult.mapValue((d) => d.isFediverse);
|
|
}
|
|
|
|
@riverpod
|
|
Future<Result<ServerData, ExecError>> serverData(Ref ref, String url) async {
|
|
final uri = Uri.tryParse(url);
|
|
if (uri == null || uri.scheme != 'https') {
|
|
return buildErrorResult(
|
|
type: ErrorType.parsingError,
|
|
message: 'Invalid URL: $url',
|
|
);
|
|
}
|
|
|
|
final domain = uri.host;
|
|
ServerData? data = _knownServers[domain];
|
|
if (data != null) {
|
|
return Result.ok(data);
|
|
}
|
|
|
|
final serverData =
|
|
await ref.read(serverDataFromServerProvider(domain).future);
|
|
return Result.ok(serverData);
|
|
}
|
|
|
|
@riverpod
|
|
Future<ServerData> serverDataFromServer(Ref ref, String domainName) async {
|
|
if (domainName == threadsDomain) {
|
|
return _threadsData;
|
|
}
|
|
|
|
if (domainName == threadsWwwDomain) {
|
|
return _threadsWwwData;
|
|
}
|
|
|
|
final uri = Uri.https(
|
|
domainName,
|
|
'/.well-known/nodeinfo',
|
|
);
|
|
final result = await ref
|
|
.read(httpGetProvider(NetworkRequest(uri)).future)
|
|
.transform((page) => jsonDecode(page.data))
|
|
.andThen(
|
|
(json) =>
|
|
json is Map<String, dynamic> ? Result.ok(json) : Result.error(''),
|
|
)
|
|
.transform((json) => json['links'] ?? [])
|
|
.andThen(
|
|
(nodeInfos) =>
|
|
nodeInfos.isNotEmpty ? Result.ok(nodeInfos.last) : Result.error(''),
|
|
)
|
|
.andThenAsync((nodeInfo) async {
|
|
final rel = nodeInfo['rel']?.toString() ?? '';
|
|
if (!rel.startsWith('http://nodeinfo.diaspora.software/ns/schema/')) {
|
|
return Result.error('');
|
|
}
|
|
|
|
final nodeInfoUrl = Uri.tryParse(nodeInfo['href'] ?? '');
|
|
if (nodeInfoUrl == null) {
|
|
return Result.error('');
|
|
}
|
|
return await ref
|
|
.read(httpGetProvider(NetworkRequest(nodeInfoUrl)).future);
|
|
})
|
|
.transform((nodeInfoData) => jsonDecode(nodeInfoData.data))
|
|
.transform((nodeInfoJson) {
|
|
final softwareName =
|
|
nodeInfoJson['software']?['name']?.toString() ?? '';
|
|
final softwareVersion =
|
|
nodeInfoJson['software']?['version']?.toString() ?? '';
|
|
final isFediverse =
|
|
softwareName.isNotEmpty && softwareVersion.isNotEmpty;
|
|
return ServerData(
|
|
domainName: domainName,
|
|
isFediverse: isFediverse,
|
|
softwareName: softwareName,
|
|
softwareVersion: softwareVersion,
|
|
);
|
|
});
|
|
|
|
return result.getValueOrElse(
|
|
() => ServerData(domainName: domainName, isFediverse: false));
|
|
}
|