added JSON structure check for repos

This commit is contained in:
Schnitzel5 2025-05-13 16:03:21 +02:00
parent b57683f1a1
commit 49914c5a53
16 changed files with 89 additions and 29 deletions

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:app_links/app_links.dart';
import 'package:bot_toast/bot_toast.dart';
@ -12,6 +13,7 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/eval/model/m_bridge.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/more/data_and_storage/providers/storage_usage.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
@ -19,6 +21,7 @@ import 'package:mangayomi/providers/storage_provider.dart';
import 'package:mangayomi/router/router.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
import 'package:mangayomi/l10n/generated/app_localizations.dart';
import 'package:mangayomi/services/http/m_client.dart';
import 'package:mangayomi/src/rust/frb_generated.dart';
import 'package:mangayomi/utils/url_protocol/api.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_provider.dart';
@ -160,8 +163,21 @@ class _MyAppState extends ConsumerState<MyApp> {
),
FilledButton(
child: Text(l10n.add),
onPressed: () {
Navigator.of(context).pop();
onPressed: () async {
if (context.mounted) Navigator.of(context).pop();
final validUrls = await _checkValidUrls([
...mangaRepoUrls ?? [],
...animeRepoUrls ?? [],
...novelRepoUrls ?? [],
]);
if (!validUrls) {
botToast(
"You've tried to add an unsupported repository. Please check the discord server for support!",
);
return;
}
void addRepos(ItemType type, List<String>? urls) {
if (urls == null) return;
@ -198,4 +214,22 @@ class _MyAppState extends ConsumerState<MyApp> {
}
});
}
Future<bool> _checkValidUrls(List<String> urls) async {
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
for (final url in urls) {
final req = await http.get(Uri.parse("$url/repo.json"));
try {
final sourceList = (jsonDecode(req.body) as List).map(
(e) => Source.fromJson(e),
);
if (sourceList.firstOrNull?.name == null) {
return false;
}
} catch (err) {
return false;
}
}
return true;
}
}

View file

@ -6,7 +6,7 @@ part of 'file_scanner.dart';
// RiverpodGenerator
// **************************************************************************
String _$scanLocalLibraryHash() => r'8a80e2582c4abda500034c9e139cdb8be58942e7';
String _$scanLocalLibraryHash() => r'7e028c45097e5802ee974d9f0c5a2bc540bba91c';
/// Scans `Mangayomi/local` folder (if exists) for Mangas/Animes and imports in library.
///
@ -29,10 +29,9 @@ String _$scanLocalLibraryHash() => r'8a80e2582c4abda500034c9e139cdb8be58942e7';
final scanLocalLibraryProvider = AutoDisposeFutureProvider<void>.internal(
scanLocalLibrary,
name: r'scanLocalLibraryProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$scanLocalLibraryHash,
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$scanLocalLibraryHash,
dependencies: null,
allTransitiveDependencies: null,
);

View file

@ -6,7 +6,7 @@ part of 'track_state_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$trackStateHash() => r'1aecb0459141daa3e44fe3bbf6b49c0992b5f8bc';
String _$trackStateHash() => r'4d31a8a939412cabd800f9747bff7a1ac0ef1996';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'update_manga_detail_providers.dart';
// RiverpodGenerator
// **************************************************************************
String _$updateMangaDetailHash() => r'47fb1d79d48c4832fa7027ea76020044eb1fa2b4';
String _$updateMangaDetailHash() => r'98557168ef42d117f52ac5d92810dd5ae562cb53';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -158,7 +158,7 @@ class _AddDownloadToQueueProviderElement
Chapter get chapter => (origin as AddDownloadToQueueProvider).chapter;
}
String _$downloadChapterHash() => r'd20136bb2b86f930c3c48bc0dd07b16eaf1de133';
String _$downloadChapterHash() => r'ee2f93aaa7fd64b46d5ce729d1e58ba20a6fa0fc';
/// See also [downloadChapter].
@ProviderFor(downloadChapter)

View file

@ -6,7 +6,7 @@ part of 'restore.dart';
// RiverpodGenerator
// **************************************************************************
String _$doRestoreHash() => r'd60314f193636cc87fecc8d21d1a83d735cd75e1';
String _$doRestoreHash() => r'196cb936fe7bfcb6535f5e6b4d86e0c77064f45e';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -7,7 +7,7 @@ part of 'storage_usage.dart';
// **************************************************************************
String _$totalChapterCacheSizeStateHash() =>
r'83bf78de5ef674d61d3a9311061ef0933e59109b';
r'bb403516c1d94652146d0a38101b51ffe8ea72f8';
/// See also [TotalChapterCacheSizeState].
@ProviderFor(TotalChapterCacheSizeState)

View file

@ -1,8 +1,10 @@
import 'dart:convert';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/services/fetch_anime_sources.dart';
import 'package:mangayomi/services/fetch_manga_sources.dart';
import 'package:mangayomi/services/fetch_novel_sources.dart';
@ -104,20 +106,39 @@ class CheckForExtensionsUpdateState extends _$CheckForExtensionsUpdateState {
}
@riverpod
Future<Repo> getRepoInfos(Ref ref, {required String jsonUrl}) async {
Future<Repo?> getRepoInfos(Ref ref, {required String jsonUrl}) async {
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
Map<String, dynamic> infos = {};
final match = RegExp(r'^(.*)/[^/]+\.json$').firstMatch(jsonUrl);
final res = await http.get(Uri.parse(jsonUrl));
if (!_checkValidUrl(res)) {
return null;
}
if (match != null) {
String url = match.group(1)!;
final req = await http.get(Uri.parse("$url/repo.json"));
if (req.statusCode == 200) {
infos.addAll(jsonDecode(req.body));
final res = await http.get(Uri.parse("$url/repo.json"));
if (res.statusCode == 200) {
infos.addAll(jsonDecode(res.body));
}
}
infos["jsonUrl"] = jsonUrl;
return Repo.fromJson(infos);
}
bool _checkValidUrl(Response res) {
try {
final sourceList = (jsonDecode(res.body) as List).map(
(e) => Source.fromJson(e),
);
if (sourceList.firstOrNull?.name == null) {
return false;
}
} catch (err) {
return false;
}
return true;
}

View file

@ -6,7 +6,7 @@ part of 'browse_state_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$getRepoInfosHash() => r'250bc0082ac2841114d6f1815303955b8798240e';
String _$getRepoInfosHash() => r'1919123e3f6d6aad1b7fb2d74058073e2f968a29';
/// Copied from Dart SDK
class _SystemHash {
@ -34,7 +34,7 @@ class _SystemHash {
const getRepoInfosProvider = GetRepoInfosFamily();
/// See also [getRepoInfos].
class GetRepoInfosFamily extends Family<AsyncValue<Repo>> {
class GetRepoInfosFamily extends Family<AsyncValue<Repo?>> {
/// See also [getRepoInfos].
const GetRepoInfosFamily();
@ -72,7 +72,7 @@ class GetRepoInfosFamily extends Family<AsyncValue<Repo>> {
}
/// See also [getRepoInfos].
class GetRepoInfosProvider extends AutoDisposeFutureProvider<Repo> {
class GetRepoInfosProvider extends AutoDisposeFutureProvider<Repo?> {
/// See also [getRepoInfos].
GetRepoInfosProvider({
required String jsonUrl,
@ -107,7 +107,7 @@ class GetRepoInfosProvider extends AutoDisposeFutureProvider<Repo> {
@override
Override overrideWith(
FutureOr<Repo> Function(GetRepoInfosRef provider) create,
FutureOr<Repo?> Function(GetRepoInfosRef provider) create,
) {
return ProviderOverride(
origin: this,
@ -124,7 +124,7 @@ class GetRepoInfosProvider extends AutoDisposeFutureProvider<Repo> {
}
@override
AutoDisposeFutureProviderElement<Repo> createElement() {
AutoDisposeFutureProviderElement<Repo?> createElement() {
return _GetRepoInfosProviderElement(this);
}
@ -144,13 +144,13 @@ class GetRepoInfosProvider extends AutoDisposeFutureProvider<Repo> {
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin GetRepoInfosRef on AutoDisposeFutureProviderRef<Repo> {
mixin GetRepoInfosRef on AutoDisposeFutureProviderRef<Repo?> {
/// The parameter `jsonUrl` of this provider.
String get jsonUrl;
}
class _GetRepoInfosProviderElement
extends AutoDisposeFutureProviderElement<Repo> with GetRepoInfosRef {
extends AutoDisposeFutureProviderElement<Repo?> with GetRepoInfosRef {
_GetRepoInfosProviderElement(super.provider);
@override

View file

@ -290,6 +290,12 @@ class _SourceRepositoriesState extends ConsumerState<SourceRepositories> {
jsonUrl: controller.text,
).future,
);
if (repo == null) {
botToast(
"You've tried to add an unsupported repository. Please check the discord server for support!",
);
return;
}
mangaRepos.add(repo);
ref
.read(

View file

@ -6,7 +6,7 @@ part of 'aniskip.dart';
// RiverpodGenerator
// **************************************************************************
String _$aniSkipHash() => r'2e5d19b025a2207ff64da7bf7908450ea9e5ff8c';
String _$aniSkipHash() => r'887869b54e2e151633efd46da83bde845e14f421';
/// See also [AniSkip].
@ProviderFor(AniSkip)

View file

@ -6,7 +6,7 @@ part of 'get_chapter_pages.dart';
// RiverpodGenerator
// **************************************************************************
String _$getChapterPagesHash() => r'5b18b20360abecf1125f27c32b10977dd18f1831';
String _$getChapterPagesHash() => r'7ec8b6adb94e33df9b5374bd423f7864a4c2f8ef';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'get_html_content.dart';
// RiverpodGenerator
// **************************************************************************
String _$getHtmlContentHash() => r'c88d61e16b50cef52da04efc5c53de7390f4910d';
String _$getHtmlContentHash() => r'6bdc17222f959cb5f91b56027d4f98e26571175d';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'anilist.dart';
// RiverpodGenerator
// **************************************************************************
String _$anilistHash() => r'ddd07acc8d28d2aa95c942566109e9393ca9e5ed';
String _$anilistHash() => r'80c9c6e9028e8a8180795366729acbe6c248d9ce';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'kitsu.dart';
// RiverpodGenerator
// **************************************************************************
String _$kitsuHash() => r'09e9b9599bd536b94ca24bc087c8e9310d2b9ef9';
String _$kitsuHash() => r'40d57c539caed9208081f3330472a75dbf9ff8f9';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'myanimelist.dart';
// RiverpodGenerator
// **************************************************************************
String _$myAnimeListHash() => r'6cdb81f9bff9bd510d822e81408f36894a517f1b';
String _$myAnimeListHash() => r'a7d644ee61119350613a9cff2fbe87dbd2f98912';
/// Copied from Dart SDK
class _SystemHash {