Don't trust content-length header from sites w/o accept-ranges support (#1542) + bugfixes

This commit is contained in:
Imran Remtulla
2024-04-15 18:39:21 -04:00
parent b042050ea3
commit 0657f832e1

View File

@@ -235,8 +235,9 @@ Future<File> downloadFile(
var fullContentLength = response.contentLength; var fullContentLength = response.contentLength;
if (useExisting && downloadedFile.existsSync()) { if (useExisting && downloadedFile.existsSync()) {
var length = downloadedFile.lengthSync(); var length = downloadedFile.lengthSync();
if (fullContentLength == null) { if (fullContentLength == null || !rangeFeatureEnabled) {
// Assume full // If there is no content length reported, assume it the existing file is fully downloaded
// Also if the range feature is not supported, don't trust the content length if any (#1542)
client.close(); client.close();
return downloadedFile; return downloadedFile;
} else { } else {
@@ -291,14 +292,11 @@ Future<File> downloadFile(
return s; return s;
}).pipe(sink); }).pipe(sink);
await sink.close(); await sink.close();
bool likelyCorruptFile = (progress ?? 0) > 101;
progress = null; progress = null;
if (onProgress != null) { if (onProgress != null) {
onProgress(progress); onProgress(progress);
} }
if (response.statusCode < 200 || if (response.statusCode < 200 || response.statusCode > 299) {
response.statusCode > 299 ||
likelyCorruptFile) {
tempDownloadedFile.deleteSync(recursive: true); tempDownloadedFile.deleteSync(recursive: true);
throw response.reasonPhrase ?? tr('unexpectedError'); throw response.reasonPhrase ?? tr('unexpectedError');
} }
@@ -392,30 +390,26 @@ class AppsProvider with ChangeNotifier {
}(); }();
} }
Future<File> handleAPKIDChange(App app, PackageInfo? newInfo, Future<File> handleAPKIDChange(App app, PackageInfo newInfo,
File downloadedFile, String downloadUrl) async { File downloadedFile, String downloadUrl) async {
// If the APK package ID is different from the App ID, it is either new (using a placeholder ID) or the ID has changed // If the APK package ID is different from the App ID, it is either new (using a placeholder ID) or the ID has changed
// The former case should be handled (give the App its real ID), the latter is a security issue // The former case should be handled (give the App its real ID), the latter is a security issue
var isTempIdBool = isTempId(app); var isTempIdBool = isTempId(app);
if (newInfo != null) { if (app.id != newInfo.packageName) {
if (app.id != newInfo.packageName) { if (apps[app.id] != null && !isTempIdBool && !app.allowIdChange) {
if (apps[app.id] != null && !isTempIdBool && !app.allowIdChange) { throw IDChangedError(newInfo.packageName!);
throw IDChangedError(newInfo.packageName!); }
} var idChangeWasAllowed = app.allowIdChange;
var idChangeWasAllowed = app.allowIdChange; app.allowIdChange = false;
app.allowIdChange = false; var originalAppId = app.id;
var originalAppId = app.id; app.id = newInfo.packageName!;
app.id = newInfo.packageName!; downloadedFile = downloadedFile.renameSync(
downloadedFile = downloadedFile.renameSync( '${downloadedFile.parent.path}/${app.id}-${downloadUrl.hashCode}.${downloadedFile.path.split('.').last}');
'${downloadedFile.parent.path}/${app.id}-${downloadUrl.hashCode}.${downloadedFile.path.split('.').last}'); if (apps[originalAppId] != null) {
if (apps[originalAppId] != null) { await removeApps([originalAppId]);
await removeApps([originalAppId]); await saveApps([app],
await saveApps([app], onlyIfExists: !isTempIdBool && !idChangeWasAllowed);
onlyIfExists: !isTempIdBool && !idChangeWasAllowed);
}
} }
} else if (isTempIdBool) {
throw ObtainiumError('Could not get ID from APK');
} }
return downloadedFile; return downloadedFile;
} }
@@ -479,6 +473,10 @@ class AppsProvider with ChangeNotifier {
newInfo = newInfo =
await pm.getPackageArchiveInfo(archiveFilePath: apks.first.path); await pm.getPackageArchiveInfo(archiveFilePath: apks.first.path);
} }
if (newInfo == null) {
downloadedFile.delete();
throw ObtainiumError('Could not get ID from APK');
}
downloadedFile = downloadedFile =
await handleAPKIDChange(app, newInfo, downloadedFile, downloadUrl); await handleAPKIDChange(app, newInfo, downloadedFile, downloadUrl);
// Delete older versions of the file if any // Delete older versions of the file if any