mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 20:48:24 +00:00
Certificate mismatch and other small UX improvements
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
|
||||
+21
-4
@@ -75,6 +75,17 @@ class App extends BaseApp with DataModelMixin<App> {
|
||||
final notifier =
|
||||
adapter.ref.read(installationProgressProvider(id!).notifier);
|
||||
|
||||
if (canUpdate) {
|
||||
final match = await packageCertificateMatches();
|
||||
if (match == false) {
|
||||
notifier.state = ErrorInstallProgress(
|
||||
Exception('APK certificate mismatch'),
|
||||
info: 'Update is not possible',
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final installPermission = await Permission.requestInstallPackages.status;
|
||||
if (!installPermission.isGranted) {
|
||||
final newStatus = await Permission.requestInstallPackages.request();
|
||||
@@ -101,8 +112,8 @@ class App extends BaseApp with DataModelMixin<App> {
|
||||
notifier.state = ErrorInstallProgress(Exception(e));
|
||||
return;
|
||||
}
|
||||
notifier.state = RequestInstallProgress();
|
||||
|
||||
notifier.state = RequestInstallProgress();
|
||||
final result = await InstallPlugin.install(file.path);
|
||||
|
||||
if (result['isSuccess']) {
|
||||
@@ -110,7 +121,7 @@ class App extends BaseApp with DataModelMixin<App> {
|
||||
await adapter.ref.localApps.localAppAdapter
|
||||
.refreshUpdateStatus(appId: identifier);
|
||||
} else {
|
||||
const msg = 'Android installation failed';
|
||||
const msg = 'App has not been installed';
|
||||
notifier.state = ErrorInstallProgress(
|
||||
Exception(msg),
|
||||
info: result['errorMessage'],
|
||||
@@ -162,13 +173,15 @@ class App extends BaseApp with DataModelMixin<App> {
|
||||
}
|
||||
|
||||
Future<bool?> packageCertificateMatches() async {
|
||||
if (latestMetadata!.apkSignatureHash == null) return null;
|
||||
|
||||
final flags = PackageInfoFlags(
|
||||
{PMFlag.getPermissions, PMFlag.getSigningCertificates},
|
||||
);
|
||||
|
||||
final i = await packageManager.getPackageInfo(
|
||||
packageName: id!.toString(), flags: flags);
|
||||
if (i == null || latestMetadata!.apkSignatureHash == null) {
|
||||
packageName: identifier, flags: flags);
|
||||
if (i == null) {
|
||||
return null;
|
||||
}
|
||||
final bytes = i.signingInfo!.signingCertificateHistory!.first;
|
||||
@@ -425,6 +438,10 @@ class ErrorInstallProgress extends AppInstallProgress {
|
||||
ErrorInstallProgress(this.e, {this.info});
|
||||
}
|
||||
|
||||
extension ExceptionExt on Exception {
|
||||
String get message => (this as dynamic).message ?? toString();
|
||||
}
|
||||
|
||||
final installationProgressProvider =
|
||||
StateProvider.family<AppInstallProgress, Object>(
|
||||
(_, arg) => IdleInstallProgress());
|
||||
|
||||
@@ -231,18 +231,6 @@ class AppDetailScreen extends HookConsumerWidget {
|
||||
.apkSignatureHash!));
|
||||
context.showInfo(
|
||||
'Copied APK certificate SHA-256 to the clipboard');
|
||||
app
|
||||
.packageCertificateMatches()
|
||||
.then((match) {
|
||||
if (match != null && !match) {
|
||||
context.showError(
|
||||
title:
|
||||
'APK certificate mismatch!',
|
||||
description:
|
||||
'Please let us know',
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
||||
@@ -58,7 +58,7 @@ extension StringWidget on String {
|
||||
});
|
||||
}
|
||||
|
||||
String substringMin(int size) {
|
||||
String substringMax(int size) {
|
||||
return substring(0, min(length, 80));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class LoginContainer extends HookConsumerWidget {
|
||||
}).catchError((e, stack) {
|
||||
context.showError(
|
||||
title: e.message ?? e.toString(),
|
||||
description: stack?.toString().substringMin(200));
|
||||
description: stack?.toString().substringMax(200));
|
||||
});
|
||||
},
|
||||
builder: (context, child, callback, buttonState) {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:zapstore/main.dart';
|
||||
import 'package:zapstore/main.data.dart';
|
||||
import 'package:zapstore/models/app.dart';
|
||||
import 'package:zapstore/utils/system_info.dart';
|
||||
import 'package:zapstore/widgets/app_drawer.dart';
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class ErrorContainer extends HookConsumerWidget {
|
||||
),
|
||||
Gap(6),
|
||||
Text(
|
||||
stack?.toString().substringMin(80) ?? '',
|
||||
stack?.toString().substringMax(80) ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey,
|
||||
|
||||
@@ -54,8 +54,7 @@ class InstallButton extends ConsumerWidget {
|
||||
},
|
||||
ErrorInstallProgress(:final e, :final info) => () {
|
||||
// show error and reset state to idle
|
||||
context.showError(
|
||||
title: (e as dynamic).message, description: info);
|
||||
context.showError(title: e.message, description: info);
|
||||
ref.read(installationProgressProvider(app.id!).notifier).state =
|
||||
IdleInstallProgress();
|
||||
},
|
||||
@@ -109,7 +108,13 @@ class InstallButton extends ConsumerWidget {
|
||||
VerifyingHashProgress() => Text('Verifying file integrity'),
|
||||
RequestInstallProgress() =>
|
||||
Text('Requesting ${app.canUpdate ? 'update' : 'installation'}'),
|
||||
ErrorInstallProgress() => Text('Error, tap to see message'),
|
||||
ErrorInstallProgress(:final e) => Padding(
|
||||
padding: const EdgeInsets.only(left: 8, right: 8),
|
||||
child: Text(
|
||||
'${e.message.substringMax(64)} (tap for more)',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
}
|
||||
},
|
||||
),
|
||||
@@ -187,7 +192,7 @@ class InstallAlertDialog extends ConsumerWidget {
|
||||
child: user != null
|
||||
? Text('Install', style: TextStyle(fontWeight: FontWeight.bold))
|
||||
: Text(
|
||||
'I trust the signer, install anyway',
|
||||
'I trust the signer, install the app',
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -29,6 +29,10 @@ class WebOfTrustContainer extends HookConsumerWidget {
|
||||
trustedUsers.firstWhereOrNull((u) => u.npub == npub) != null;
|
||||
final trustedUsersWithoutUser =
|
||||
trustedUsers.where((u) => u.npub != npub).toList();
|
||||
if (trustedUsersWithoutUser.isEmpty) {
|
||||
return Text(
|
||||
'No trusted users. This may be a service error and you may want to try again later.');
|
||||
}
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
|
||||
Reference in New Issue
Block a user