Trying to use header-based HTTP auth (not working)

This commit is contained in:
Imran Remtulla
2023-09-06 21:30:45 -04:00
parent 8ba0a0a776
commit c08e05bd6c
20 changed files with 81 additions and 66 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -12,8 +12,6 @@
"ok": "باشه",
"and": "و",
"githubPATLabel": "توکن دسترسی شخصی گیت هاب(محدودیت نرخ را افزایش میدهد)",
"githubPATHint": "PAT باید در این قالب باشد: username:token",
"githubPATFormat": "username:token",
"includePrereleases": "شامل نسخه های اولیه",
"fallbackToOlderReleases": "بازگشت به نسخه های قدیمی تر",
"filterReleaseTitlesByRegEx": "عناوین انتشار را با بیان منظم فیلتر کنید",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -12,8 +12,6 @@
"ok": "OK",
"and": "と",
"githubPATLabel": "GitHub パーソナルアクセストークン (レート制限の引き上げ)",
"githubPATHint": "PATは次の形式でなければなりません: ユーザー名:トークン",
"githubPATFormat": "ユーザー名:トークン",
"includePrereleases": "プレリリースを含む",
"fallbackToOlderReleases": "旧リリースへのフォールバック",
"filterReleaseTitlesByRegEx": "正規表現でリリースタイトルをフィルタリングする",

View File

@ -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",

View File

@ -12,8 +12,6 @@
"ok": "Окей",
"and": "и",
"githubPATLabel": "Персональный токен доступа GitHub (увеличивает лимит запросов)",
"githubPATHint": "Токен доступа должен быть в формате: имя_пользователя:токен",
"githubPATFormat": "имя_пользователя:токен",
"includePrereleases": "Включить предварительные релизы",
"fallbackToOlderReleases": "Откатиться к более старым версиям",
"filterReleaseTitlesByRegEx": "Фильтровать заголовки релизов\nс помощью регулярного выражения",

View File

@ -12,8 +12,6 @@
"ok": "好的",
"and": "和",
"githubPATLabel": "GitHub 个人访问令牌(提升 API 请求限额)",
"githubPATHint": "个人访问令牌必须为“username:token”的格式",
"githubPATFormat": "username:token",
"includePrereleases": "包含预发行版",
"fallbackToOlderReleases": "将旧发行版作为备选",
"filterReleaseTitlesByRegEx": "使用正则表达式筛选发行标题",

View File

@ -25,12 +25,16 @@ class APKCombo extends AppSource {
}
@override
Map<String, String> get requestHeaders => {
"User-Agent": "curl/8.0.1",
"Accept": "*/*",
"Connection": "keep-alive",
"Host": "$host"
};
Future<Map<String, String>?> getRequestHeaders(
{Map<String, dynamic> additionalSettings = const <String, dynamic>{},
bool forAPKDownload = false}) async {
return {
"User-Agent": "curl/8.0.1",
"Accept": "*/*",
"Connection": "keep-alive",
"Host": "$host"
};
}
Future<List<MapEntry<String, String>>> getApkUrls(String standardUrl) async {
var res = await sourceRequest('$standardUrl/download/apk');

View File

@ -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<String> getCredentialPrefixIfAny(
Map<String, dynamic> additionalSettings) async {
@override
Future<Map<String, String>?> getRequestHeaders(
{Map<String, dynamic> additionalSettings = const <String, dynamic>{},
bool forAPKDownload = false}) async {
var token = await getTokenIfAny(additionalSettings);
var headers = <String, String>{};
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<String?> getTokenIfAny(Map<String, dynamic> 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<String?> getSourceNote() async {
if (!hostChanged && (await getCredentialPrefixIfAny({})).isEmpty) {
if (!hostChanged && (await getTokenIfAny({})) == null) {
return '${tr('githubSourceNote')} ${hostChanged ? tr('addInfoBelow') : tr('addInfoInSettings')}';
}
return null;
}
Future<String> getAPIHost(Map<String, dynamic> additionalSettings) async =>
'https://${await getCredentialPrefixIfAny(additionalSettings)}api.$host';
'https://api.$host';
Future<String> convertStandardUrlToAPIUrl(
String standardUrl, Map<String, dynamic> additionalSettings) async =>
@ -238,7 +252,9 @@ class GitHub extends AppSource {
List<MapEntry<String, String>> getReleaseAPKUrls(dynamic release) =>
(release['assets'] as List<dynamic>?)
?.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('', '');

View File

@ -116,11 +116,14 @@ class HTML extends AppSource {
}
@override
// TODO: implement requestHeaders choice, hardcoded for now
Map<String, String>? 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<Map<String, String>?> getRequestHeaders(
{Map<String, dynamic> additionalSettings = const <String, dynamic>{},
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) {

View File

@ -12,7 +12,12 @@ class VLC extends AppSource {
get dwUrlBase => 'https://get.$host/vlc-android/';
@override
Map<String, String>? get requestHeaders => HTML().requestHeaders;
Future<Map<String, String>?> getRequestHeaders(
{Map<String, dynamic> additionalSettings = const <String, dynamic>{},
bool forAPKDownload = false}) =>
HTML().getRequestHeaders(
additionalSettings: additionalSettings,
forAPKDownload: forAPKDownload);
@override
String sourceSpecificStandardizeURL(String url) {

View File

@ -15,8 +15,10 @@ class GitHubStars implements MassAppUrlSource {
Future<Map<String, List<String>>> 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<String, List<String>> urlsWithDescriptions = {};
for (var e in (jsonDecode(res.body) as List<dynamic>)) {

View File

@ -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;

View File

@ -363,15 +363,23 @@ abstract class AppSource {
return url;
}
Map<String, String>? get requestHeaders => null;
Future<Map<String, String>?> getRequestHeaders(
{Map<String, dynamic> additionalSettings = const <String, dynamic>{},
bool forAPKDownload = false}) async {
return null;
}
Future<Response> sourceRequest(String url,
{bool followRedirects = true}) async {
{bool followRedirects = true,
Map<String, dynamic> additionalSettings =
const <String, dynamic>{}}) 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 {