diff --git a/assets/translations/br.json b/assets/translations/br.json index 7a23ea5..efe9093 100644 --- a/assets/translations/br.json +++ b/assets/translations/br.json @@ -12,8 +12,6 @@ "ok": "Ok", "and": "e", "githubPATLabel": "Token de Acceso Pessoal do GitHub (Reduz tempos de espera)", - "githubPATHint": "O TAP deve estar nesse formato: usuario:token", - "githubPATFormat": "usuario:token", "includePrereleases": "Incluir pré-lançamentos", "fallbackToOlderReleases": "Retornar para versões anteriores", "filterReleaseTitlesByRegEx": "Filtrar Titulos de Versões por Expressão Regular", diff --git a/assets/translations/bs.json b/assets/translations/bs.json index 9813cd4..e3a4ef6 100644 --- a/assets/translations/bs.json +++ b/assets/translations/bs.json @@ -12,8 +12,6 @@ "ok": "Dobro", "and": "i", "githubPATLabel": "GitHub token za lični pristup (eng. PAT, povećava ograničenje stope)", - "githubPATHint": "PAT mora biti u ovom formatu: korisničko_ime:token", - "githubPATFormat": "korisničko_ime:token", "includePrereleases": "Uključi preliminarna izdanja", "fallbackToOlderReleases": "Povratak na starija izdanja", "filterReleaseTitlesByRegEx": "Filtrirajte naslove izdanja prema regularnom izrazu", diff --git a/assets/translations/de.json b/assets/translations/de.json index 9d0de6a..2e9857e 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -12,8 +12,6 @@ "ok": "Okay", "and": "und", "githubPATLabel": "GitHub Personal Access Token (Erhöht das Ratenlimit)", - "githubPATHint": "PAT muss in diesem Format sein: Benutzername:Token", - "githubPATFormat": "Benutzername:Token", "includePrereleases": "Vorabversionen einbeziehen", "fallbackToOlderReleases": "Fallback auf ältere Versionen", "filterReleaseTitlesByRegEx": "Release-Titel nach regulärem Ausdruck\nfiltern", diff --git a/assets/translations/en.json b/assets/translations/en.json index c157509..bba3367 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -12,8 +12,6 @@ "ok": "Okay", "and": "and", "githubPATLabel": "GitHub Personal Access Token (Increases Rate Limit)", - "githubPATHint": "PAT must be in this format: username:token", - "githubPATFormat": "username:token", "includePrereleases": "Include prereleases", "fallbackToOlderReleases": "Fallback to older releases", "filterReleaseTitlesByRegEx": "Filter Release Titles by Regular Expression", diff --git a/assets/translations/es.json b/assets/translations/es.json index bf83959..e4ffaa0 100644 --- a/assets/translations/es.json +++ b/assets/translations/es.json @@ -12,8 +12,6 @@ "ok": "Correcto", "and": "y", "githubPATLabel": "Token de Acceso Personal de GitHub (Reduce tiempos de espera)", - "githubPATHint": "El TAP debe tener este formato: nombre_de_usuario:token", - "githubPATFormat": "nombre_de_usuario:token", "includePrereleases": "Incluir versiones preliminares", "fallbackToOlderReleases": "Retorceder a versiones previas", "filterReleaseTitlesByRegEx": "Filtra Títulos de Versiones mediantes Expresiones Regulares", diff --git a/assets/translations/fa.json b/assets/translations/fa.json index 1866dd6..041ce19 100644 --- a/assets/translations/fa.json +++ b/assets/translations/fa.json @@ -12,8 +12,6 @@ "ok": "باشه", "and": "و", "githubPATLabel": "توکن دسترسی شخصی گیت هاب(محدودیت نرخ را افزایش میدهد)", - "githubPATHint": "PAT باید در این قالب باشد: username:token", - "githubPATFormat": "username:token", "includePrereleases": "شامل نسخه های اولیه", "fallbackToOlderReleases": "بازگشت به نسخه های قدیمی تر", "filterReleaseTitlesByRegEx": "عناوین انتشار را با بیان منظم فیلتر کنید", diff --git a/assets/translations/fr.json b/assets/translations/fr.json index e55ba3b..8b5adfc 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -12,8 +12,6 @@ "ok": "Okay", "and": "et", "githubPATLabel": "Jeton d'Accès Personnel GitHub (Augmente la limite de débit)", - "githubPATHint": "Le JAP doit être dans ce format : username:token", - "githubPATFormat": "username:token", "includePrereleases": "Inclure les avant-premières", "fallbackToOlderReleases": "Retour aux anciennes versions", "filterReleaseTitlesByRegEx": "Filtrer les titres de version par expression régulière", diff --git a/assets/translations/hu.json b/assets/translations/hu.json index b7a75d9..7c7d912 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -12,8 +12,6 @@ "ok": "Oké", "and": "és", "githubPATLabel": "GitHub Personal Access Token (megnöveli a díjkorlátot)", - "githubPATHint": "A PAT-nak a következő formátumban kell lennie: felhasználónév:token", - "githubPATFormat": "felhasználónév:token", "includePrereleases": "Tartalmazza az előzetes kiadásokat", "fallbackToOlderReleases": "Visszatérés a régebbi kiadásokhoz", "filterReleaseTitlesByRegEx": "A kiadás címeinek szűrése reguláris kifejezéssel", diff --git a/assets/translations/it.json b/assets/translations/it.json index 5d43a36..eadf90b 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -12,8 +12,6 @@ "ok": "Va bene", "and": "e", "githubPATLabel": "GitHub Personal Access Token (diminuisce limite di traffico)", - "githubPATHint": "PAT deve seguire questo formato: nomeutente:token", - "githubPATFormat": "nomeutente:token", "includePrereleases": "Includi prerelease", "fallbackToOlderReleases": "Ripiega su release precedenti", "filterReleaseTitlesByRegEx": "Filtra release con espressioni regolari", diff --git a/assets/translations/ja.json b/assets/translations/ja.json index 0119f5d..1fa24d6 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -12,8 +12,6 @@ "ok": "OK", "and": "と", "githubPATLabel": "GitHub パーソナルアクセストークン (レート制限の引き上げ)", - "githubPATHint": "PATは次の形式でなければなりません: ユーザー名:トークン", - "githubPATFormat": "ユーザー名:トークン", "includePrereleases": "プレリリースを含む", "fallbackToOlderReleases": "旧リリースへのフォールバック", "filterReleaseTitlesByRegEx": "正規表現でリリースタイトルをフィルタリングする", diff --git a/assets/translations/pl.json b/assets/translations/pl.json index f2495bf..f56121c 100644 --- a/assets/translations/pl.json +++ b/assets/translations/pl.json @@ -22,8 +22,6 @@ "ok": "Okej", "and": "i", "githubPATLabel": "Osobisty token dostępu GitHub (zwiększa limit zapytań)", - "githubPATHint": "Wymagany format: użytkownik:token", - "githubPATFormat": "użytkownik:token", "includePrereleases": "Uwzględnij wersje wstępne", "fallbackToOlderReleases": "Powracaj do starszych wersji", "filterReleaseTitlesByRegEx": "Filtruj tytuły wydań wg. wyrażeń regularnych", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index e53644f..dfaeb93 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -12,8 +12,6 @@ "ok": "Окей", "and": "и", "githubPATLabel": "Персональный токен доступа GitHub (увеличивает лимит запросов)", - "githubPATHint": "Токен доступа должен быть в формате: имя_пользователя:токен", - "githubPATFormat": "имя_пользователя:токен", "includePrereleases": "Включить предварительные релизы", "fallbackToOlderReleases": "Откатиться к более старым версиям", "filterReleaseTitlesByRegEx": "Фильтровать заголовки релизов\nс помощью регулярного выражения", diff --git a/assets/translations/zh.json b/assets/translations/zh.json index 0837f74..6f4e7a2 100644 --- a/assets/translations/zh.json +++ b/assets/translations/zh.json @@ -12,8 +12,6 @@ "ok": "好的", "and": "和", "githubPATLabel": "GitHub 个人访问令牌(提升 API 请求限额)", - "githubPATHint": "个人访问令牌必须为“username:token”的格式", - "githubPATFormat": "username:token", "includePrereleases": "包含预发行版", "fallbackToOlderReleases": "将旧发行版作为备选", "filterReleaseTitlesByRegEx": "使用正则表达式筛选发行标题", diff --git a/lib/app_sources/apkcombo.dart b/lib/app_sources/apkcombo.dart index c90b0cb..73c144b 100644 --- a/lib/app_sources/apkcombo.dart +++ b/lib/app_sources/apkcombo.dart @@ -25,12 +25,16 @@ class APKCombo extends AppSource { } @override - Map get requestHeaders => { - "User-Agent": "curl/8.0.1", - "Accept": "*/*", - "Connection": "keep-alive", - "Host": "$host" - }; + Future?> getRequestHeaders( + {Map additionalSettings = const {}, + bool forAPKDownload = false}) async { + return { + "User-Agent": "curl/8.0.1", + "Accept": "*/*", + "Connection": "keep-alive", + "Host": "$host" + }; + } Future>> getApkUrls(String standardUrl) async { var res = await sourceRequest('$standardUrl/download/apk'); diff --git a/lib/app_sources/github.dart b/lib/app_sources/github.dart index 0b2f2c9..a2722b7 100644 --- a/lib/app_sources/github.dart +++ b/lib/app_sources/github.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; @@ -21,20 +22,6 @@ class GitHub extends AppSource { label: tr('githubPATLabel'), password: true, required: false, - additionalValidators: [ - (value) { - if (value != null && value.trim().isNotEmpty) { - if (value - .split(':') - .where((element) => element.trim().isNotEmpty) - .length != - 2) { - return tr('githubPATHint'); - } - } - return null; - } - ], hint: tr('githubPATFormat'), belowWidgets: [ const SizedBox( @@ -169,26 +156,53 @@ class GitHub extends AppSource { return url.substring(0, match.end); } - Future getCredentialPrefixIfAny( - Map additionalSettings) async { + @override + Future?> getRequestHeaders( + {Map additionalSettings = const {}, + bool forAPKDownload = false}) async { + var token = await getTokenIfAny(additionalSettings); + var headers = {}; + if (token != null) { + headers[HttpHeaders.authorizationHeader] = 'Token $token'; + } + if (forAPKDownload == true) { + headers[HttpHeaders.acceptHeader] = 'octet-stream'; + } + if (headers.isNotEmpty) { + return headers; + } else { + return null; + } + } + + Future getTokenIfAny(Map additionalSettings) async { SettingsProvider settingsProvider = SettingsProvider(); await settingsProvider.initializeSettings(); var sourceConfig = await getSourceConfigValues(additionalSettings, settingsProvider); String? creds = sourceConfig['github-creds']; - return creds != null && creds.isNotEmpty ? '$creds@' : ''; + if (creds != null) { + var userNameEndIndex = creds.indexOf(':'); + if (userNameEndIndex > 0) { + creds = creds.substring( + userNameEndIndex + 1); // For old username-included token inputs + } + return creds; + } else { + return null; + } } @override Future getSourceNote() async { - if (!hostChanged && (await getCredentialPrefixIfAny({})).isEmpty) { + if (!hostChanged && (await getTokenIfAny({})) == null) { return '${tr('githubSourceNote')} ${hostChanged ? tr('addInfoBelow') : tr('addInfoInSettings')}'; } return null; } Future getAPIHost(Map additionalSettings) async => - 'https://${await getCredentialPrefixIfAny(additionalSettings)}api.$host'; + 'https://api.$host'; Future convertStandardUrlToAPIUrl( String standardUrl, Map additionalSettings) async => @@ -238,7 +252,9 @@ class GitHub extends AppSource { List> getReleaseAPKUrls(dynamic release) => (release['assets'] as List?) ?.map((e) { - return e['name'] != null && e['browser_download_url'] != null + return e['name'] != null && + e['browser_download_url'] != + null // TODO: Figure out how to use 'url' here to enable private repos ? MapEntry(e['name'] as String, e['browser_download_url'] as String) : const MapEntry('', ''); diff --git a/lib/app_sources/html.dart b/lib/app_sources/html.dart index 47dc5ff..bce8f34 100644 --- a/lib/app_sources/html.dart +++ b/lib/app_sources/html.dart @@ -116,11 +116,14 @@ class HTML extends AppSource { } @override - // TODO: implement requestHeaders choice, hardcoded for now - Map? get requestHeaders => { - "User-Agent": - "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36" - }; + Future?> getRequestHeaders( + {Map additionalSettings = const {}, + bool forAPKDownload = false}) async { + return { + "User-Agent": + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36" + }; + } @override String sourceSpecificStandardizeURL(String url) { diff --git a/lib/app_sources/vlc.dart b/lib/app_sources/vlc.dart index 1c1adb8..091411a 100644 --- a/lib/app_sources/vlc.dart +++ b/lib/app_sources/vlc.dart @@ -12,7 +12,12 @@ class VLC extends AppSource { get dwUrlBase => 'https://get.$host/vlc-android/'; @override - Map? get requestHeaders => HTML().requestHeaders; + Future?> getRequestHeaders( + {Map additionalSettings = const {}, + bool forAPKDownload = false}) => + HTML().getRequestHeaders( + additionalSettings: additionalSettings, + forAPKDownload: forAPKDownload); @override String sourceSpecificStandardizeURL(String url) { diff --git a/lib/mass_app_sources/githubstars.dart b/lib/mass_app_sources/githubstars.dart index db8495b..b32cc77 100644 --- a/lib/mass_app_sources/githubstars.dart +++ b/lib/mass_app_sources/githubstars.dart @@ -15,8 +15,10 @@ class GitHubStars implements MassAppUrlSource { Future>> getOnePageOfUserStarredUrlsWithDescriptions( String username, int page) async { - Response res = await get(Uri.parse( - 'https://${await GitHub().getCredentialPrefixIfAny({})}api.github.com/users/$username/starred?per_page=100&page=$page')); + Response res = await get( + Uri.parse( + 'https://api.github.com/users/$username/starred?per_page=100&page=$page'), + headers: await GitHub().getRequestHeaders()); if (res.statusCode == 200) { Map> urlsWithDescriptions = {}; for (var e in (jsonDecode(res.body) as List)) { diff --git a/lib/providers/apps_provider.dart b/lib/providers/apps_provider.dart index cad3b2f..208b222 100644 --- a/lib/providers/apps_provider.dart +++ b/lib/providers/apps_provider.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:math'; +import 'package:http/http.dart' as http; import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart'; import 'package:android_intent_plus/flag.dart'; @@ -215,7 +216,7 @@ class AppsProvider with ChangeNotifier { if (headers != null) { req.headers.addAll(headers); } - var client = Client(); + var client = http.Client(); StreamedResponse response = await client.send(req); String ext = response.headers['content-disposition']?.split('.').last ?? 'apk'; @@ -298,9 +299,11 @@ class AppsProvider with ChangeNotifier { notificationsProvider?.cancel(notif.id); int? prevProg; var fileNameNoExt = '${app.id}-${downloadUrl.hashCode}'; + var headers = await source.getRequestHeaders( + additionalSettings: app.additionalSettings, forAPKDownload: true); var downloadedFile = await downloadFileWithRetry( - downloadUrl, fileNameNoExt, headers: source.requestHeaders, - (double? progress) { + downloadUrl, fileNameNoExt, + headers: headers, (double? progress) { int? prog = progress?.ceil(); if (apps[app.id] != null) { apps[app.id]!.downloadProgress = progress; diff --git a/lib/providers/source_provider.dart b/lib/providers/source_provider.dart index c9433b7..df21e57 100644 --- a/lib/providers/source_provider.dart +++ b/lib/providers/source_provider.dart @@ -363,15 +363,23 @@ abstract class AppSource { return url; } - Map? get requestHeaders => null; + Future?> getRequestHeaders( + {Map additionalSettings = const {}, + bool forAPKDownload = false}) async { + return null; + } Future sourceRequest(String url, - {bool followRedirects = true}) async { + {bool followRedirects = true, + Map additionalSettings = + const {}}) async { + var requestHeaders = + await getRequestHeaders(additionalSettings: additionalSettings); if (requestHeaders != null || followRedirects == false) { var req = Request('GET', Uri.parse(url)); req.followRedirects = followRedirects; if (requestHeaders != null) { - req.headers.addAll(requestHeaders!); + req.headers.addAll(requestHeaders); } return Response.fromStream(await Client().send(req)); } else {