mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-22 16:32:01 +03:00
Merge branch 'release/6.4.0' into merge/release/6.4.0
This commit is contained in:
commit
3d0af125fd
2
.github/workflows/env
vendored
2
.github/workflows/env
vendored
@ -1,2 +1,2 @@
|
||||
FLUTTER=3.16.9
|
||||
PYVER=3.12.1
|
||||
PYVER=3.12.2
|
||||
|
1
.github/workflows/linux.yml
vendored
1
.github/workflows/linux.yml
vendored
@ -21,6 +21,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
echo "PYVER=3.12.1" >> $GITHUB_ENV # Remove once 3.12.2 is available from PPA
|
||||
export PYVER_MINOR=${PYVER%.*}
|
||||
echo "PYVER_MINOR: $PYVER_MINOR"
|
||||
apt-get update
|
||||
|
15
NEWS
15
NEWS
@ -1,3 +1,18 @@
|
||||
* Version 6.4.0
|
||||
** UI: Major UI overhaul, with improvements including:
|
||||
*** Add new UI layouts for wider windows to better utilize screen space.
|
||||
*** Add YubiKey personalization through custom naming and theme color.
|
||||
*** Split FIDO/WebAuthn into multiple sections.
|
||||
*** Move factory reset functionality into a single dialog, from the individual sections.
|
||||
** Add support for Yubico OTP provisioning.
|
||||
** PIV: Display more information about keys and certificates.
|
||||
** PIV: Add output format for public key when generating keys.
|
||||
** Desktop: Window hidden/shown state no longer saved when closing the app,
|
||||
use --hidden to start the app in a hidden to systray state.
|
||||
** Desktop: Fix FIDO reset over NFC.
|
||||
** Windows: Add option to launch Windows Settings for FIDO management.
|
||||
** Android: Increase read timeout for NFC, improving compatibility with older YubiKeys.
|
||||
|
||||
* Version 6.3.1 (released 2023-12-12)
|
||||
** Add command line options: --hidden/--shown, --log-file FILE.
|
||||
** Disable autocorrect in text fields.
|
||||
|
@ -124,10 +124,12 @@ class Ctap2Node(RpcNode):
|
||||
removed = False
|
||||
while not event.wait(0.5):
|
||||
try:
|
||||
with dev.open_connection(FidoConnection):
|
||||
if removed:
|
||||
sleep(1.0) # Wait for the device to settle
|
||||
return dev.open_connection(FidoConnection)
|
||||
conn = dev.open_connection(FidoConnection)
|
||||
if removed:
|
||||
conn.close()
|
||||
sleep(1.0) # Wait for the device to settle
|
||||
return dev.open_connection(FidoConnection)
|
||||
conn.close()
|
||||
except CardConnectionException:
|
||||
pass # Expected, ignore
|
||||
except NoCardException:
|
||||
|
21
helper/poetry.lock
generated
21
helper/poetry.lock
generated
@ -235,21 +235,21 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "jaraco-classes"
|
||||
version = "3.3.0"
|
||||
version = "3.3.1"
|
||||
description = "Utility functions for Python class constructs"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "jaraco.classes-3.3.0-py3-none-any.whl", hash = "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb"},
|
||||
{file = "jaraco.classes-3.3.0.tar.gz", hash = "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621"},
|
||||
{file = "jaraco.classes-3.3.1-py3-none-any.whl", hash = "sha256:86b534de565381f6b3c1c830d13f931d7be1a75f0081c57dff615578676e2206"},
|
||||
{file = "jaraco.classes-3.3.1.tar.gz", hash = "sha256:cb28a5ebda8bc47d8c8015307d93163464f9f2b91ab4006e09ff0ce07e8bfb30"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
more-itertools = "*"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "jeepney"
|
||||
@ -575,11 +575,16 @@ description = "Smartcard module for Python."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pyscard-2.0.7-cp310-cp310-win32.whl", hash = "sha256:06666a597e1293421fa90e0d4fc2418add447b10b7dc85f49b3cafc23480f046"},
|
||||
{file = "pyscard-2.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:a2266345bd387854298153264bff8b74f494581880a76e3e8679460c1b090fab"},
|
||||
{file = "pyscard-2.0.7-cp311-cp311-win32.whl", hash = "sha256:beacdcdc3d1516e195f7a38ec3966c5d4df7390c8f036cb41f6fef72bc5cc646"},
|
||||
{file = "pyscard-2.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e37b697327e8dc4848c481428d1cbd10b7ae2ce037bc799e5b8bbd2fc3ab5ed"},
|
||||
{file = "pyscard-2.0.7-cp37-cp37m-win32.whl", hash = "sha256:a0c5edbedafba62c68160884f878d9f53996d7219a3fc11b1cea6bab59c7f34a"},
|
||||
{file = "pyscard-2.0.7-cp37-cp37m-win_amd64.whl", hash = "sha256:f704ad40dc40306e1c0981941789518ab16aa1f84443b1d52ec0264884092b3b"},
|
||||
{file = "pyscard-2.0.7-cp38-cp38-win32.whl", hash = "sha256:59a466ab7ae20188dd197664b9ca1ea9524d115a5aa5b16b575a6b772cdcb73c"},
|
||||
{file = "pyscard-2.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:da70aa5b7be5868b88cdb6d4a419d2791b6165beeb90cd01d2748033302a0f43"},
|
||||
{file = "pyscard-2.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2d4bdc1f4e0e6c46e417ac1bc9d5990f7cfb24a080e890d453781405f7bd29dc"},
|
||||
{file = "pyscard-2.0.7-cp39-cp39-win32.whl", hash = "sha256:39e030c47878b37ae08038a917959357be6468da52e8b144e84ffc659f50e6e2"},
|
||||
{file = "pyscard-2.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:5a5865675be294c8d91f22dc91e7d897c4138881e5295fb6b2cd821f7c0389d9"},
|
||||
{file = "pyscard-2.0.7.tar.gz", hash = "sha256:278054525fa75fbe8b10460d87edcd03a70ad94d688b11345e4739987f85c1bf"},
|
||||
]
|
||||
@ -688,13 +693,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "types-pillow"
|
||||
version = "10.2.0.20240125"
|
||||
version = "10.2.0.20240206"
|
||||
description = "Typing stubs for Pillow"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "types-Pillow-10.2.0.20240125.tar.gz", hash = "sha256:c449b2c43b9fdbe0494a7b950e6b39a4e50516091213fec24ef3f33c1d017717"},
|
||||
{file = "types_Pillow-10.2.0.20240125-py3-none-any.whl", hash = "sha256:322dbae32b4b7918da5e8a47c50ac0f24b0aa72a804a23857620f2722b03c858"},
|
||||
{file = "types-Pillow-10.2.0.20240206.tar.gz", hash = "sha256:f0de5107ff8362ffdbbd53ec896202ac905e6ab22ae784b46bcdad160ea143b9"},
|
||||
{file = "types_Pillow-10.2.0.20240206-py3-none-any.whl", hash = "sha256:abc339ae28af5916146a7729261480d68ac902cd4ff57e0bdd402eee7962644d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -31,11 +31,11 @@ VSVersionInfo(
|
||||
'040904b0',
|
||||
[StringStruct('CompanyName', 'Yubico'),
|
||||
StringStruct('FileDescription', 'Yubico Authenticator Helper'),
|
||||
StringStruct('FileVersion', '6.4.0-dev.0'),
|
||||
StringStruct('FileVersion', '6.4.0'),
|
||||
StringStruct('LegalCopyright', 'Copyright (c) Yubico'),
|
||||
StringStruct('OriginalFilename', 'authenticator-helper.exe'),
|
||||
StringStruct('ProductName', 'Yubico Authenticator'),
|
||||
StringStruct('ProductVersion', '6.4.0-dev.0')])
|
||||
StringStruct('ProductVersion', '6.4.0')])
|
||||
]),
|
||||
VarFileInfo([VarStruct('Translation', [1033, 1200])])
|
||||
]
|
||||
|
@ -43,7 +43,7 @@ class ElevateFidoButtons extends ConsumerWidget {
|
||||
duration: const Duration(seconds: 30));
|
||||
try {
|
||||
if (await ref.read(rpcProvider).requireValue.elevate()) {
|
||||
ref.invalidate(rpcProvider);
|
||||
ref.invalidate(rpcStateProvider);
|
||||
} else {
|
||||
await ref.read(withContextProvider)((context) async =>
|
||||
showMessage(context, l10n.s_permission_denied));
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
@ -25,6 +26,7 @@ import '../../app/logging.dart';
|
||||
import '../../core/models.dart';
|
||||
import '../../core/state.dart';
|
||||
import '../../desktop/models.dart';
|
||||
import '../../desktop/state.dart';
|
||||
import '../../fido/models.dart';
|
||||
import '../../fido/state.dart';
|
||||
import '../../management/models.dart';
|
||||
@ -36,6 +38,7 @@ import '../features.dart' as features;
|
||||
import '../message.dart';
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
import 'elevate_fido_buttons.dart';
|
||||
import 'keys.dart';
|
||||
|
||||
final _log = Logger('fido.views.reset_dialog');
|
||||
@ -68,12 +71,19 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
|
||||
StreamSubscription<InteractionEvent>? _subscription;
|
||||
InteractionEvent? _interaction;
|
||||
int _currentStep = -1;
|
||||
final _totalSteps = 3;
|
||||
late final int _totalSteps;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final nfc = widget.data.node.transport == Transport.nfc;
|
||||
_totalSteps = nfc ? 2 : 3;
|
||||
}
|
||||
|
||||
String _getMessage() {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final nfc = widget.data.node.transport == Transport.nfc;
|
||||
if (_currentStep == 3) {
|
||||
if (_currentStep == _totalSteps) {
|
||||
return l10n.l_fido_app_reset;
|
||||
}
|
||||
return switch (_interaction) {
|
||||
@ -99,20 +109,26 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
|
||||
.contains(widget.data.info.formFactor);
|
||||
final globalReset = isBio && (supported & Capability.piv.value) != 0;
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
double progress = _currentStep == -1 ? 0.0 : _currentStep / (_totalSteps);
|
||||
final needsElevation = Platform.isWindows &&
|
||||
_application == Capability.fido2 &&
|
||||
!ref.watch(rpcStateProvider.select((state) => state.isAdmin));
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.s_factory_reset),
|
||||
key: factoryResetCancel,
|
||||
onCancel: switch (_application) {
|
||||
Capability.fido2 => _currentStep < 3
|
||||
Capability.fido2 => _currentStep < _totalSteps
|
||||
? () {
|
||||
_currentStep = -1;
|
||||
_subscription?.cancel();
|
||||
}
|
||||
: null,
|
||||
_ => null,
|
||||
},
|
||||
actions: [
|
||||
if (_currentStep < 3)
|
||||
if (_currentStep < _totalSteps)
|
||||
TextButton(
|
||||
onPressed: switch (_application) {
|
||||
Capability.fido2 => _subscription == null
|
||||
@ -222,7 +238,8 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
|
||||
: null,
|
||||
tooltip:
|
||||
!showLabels ? c.getDisplayName(l10n) : null,
|
||||
enabled: enabled & c.value != 0,
|
||||
enabled:
|
||||
enabled & c.value != 0 && (_currentStep == -1),
|
||||
))
|
||||
.toList(),
|
||||
selected: _application != null ? {_application!} : {},
|
||||
@ -247,16 +264,21 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
|
||||
.bodyMedium
|
||||
?.copyWith(fontWeight: FontWeight.w700),
|
||||
),
|
||||
Text(
|
||||
switch (_application) {
|
||||
Capability.oath => l10n.p_warning_disable_credentials,
|
||||
Capability.piv => l10n.p_warning_piv_reset_desc,
|
||||
Capability.fido2 => l10n.p_warning_disable_accounts,
|
||||
_ => globalReset
|
||||
? l10n.p_warning_global_reset_desc
|
||||
: l10n.p_factory_reset_desc,
|
||||
},
|
||||
),
|
||||
if (needsElevation) ...[
|
||||
Text(l10n.p_elevated_permissions_required),
|
||||
const ElevateFidoButtons(),
|
||||
] else ...[
|
||||
Text(
|
||||
switch (_application) {
|
||||
Capability.oath => l10n.p_warning_disable_credentials,
|
||||
Capability.piv => l10n.p_warning_piv_reset_desc,
|
||||
Capability.fido2 => l10n.p_warning_disable_accounts,
|
||||
_ => globalReset
|
||||
? l10n.p_warning_global_reset_desc
|
||||
: l10n.p_factory_reset_desc,
|
||||
},
|
||||
),
|
||||
],
|
||||
if (_application == Capability.fido2 && _currentStep >= 0) ...[
|
||||
Text('${l10n.s_status}: ${_getMessage()}'),
|
||||
LinearProgressIndicator(value: progress)
|
||||
|
@ -479,6 +479,7 @@
|
||||
"l_import_nothing": null,
|
||||
"l_importing_file": null,
|
||||
"s_file_imported": null,
|
||||
"l_unsupported_key_type": null,
|
||||
"l_delete_certificate": null,
|
||||
"l_delete_certificate_desc": null,
|
||||
"s_issuer": null,
|
||||
|
@ -479,6 +479,7 @@
|
||||
"l_import_nothing": "Nothing to import",
|
||||
"l_importing_file": "Importing file\u2026",
|
||||
"s_file_imported": "File imported",
|
||||
"l_unsupported_key_type": "Unsupported key type",
|
||||
"l_delete_certificate": "Delete certificate",
|
||||
"l_delete_certificate_desc": "Remove the certificate from your YubiKey",
|
||||
"s_issuer": "Issuer",
|
||||
|
@ -479,6 +479,7 @@
|
||||
"l_import_nothing": null,
|
||||
"l_importing_file": "Importation d'un fichier\u2026",
|
||||
"s_file_imported": "Fichier importé",
|
||||
"l_unsupported_key_type": null,
|
||||
"l_delete_certificate": "Supprimer un certificat",
|
||||
"l_delete_certificate_desc": "Supprimer un certificat de votre YubiKey",
|
||||
"s_issuer": "Émetteur",
|
||||
|
@ -479,6 +479,7 @@
|
||||
"l_import_nothing": null,
|
||||
"l_importing_file": "ファイルのインポート中\u2026",
|
||||
"s_file_imported": "ファイル をインポートしました",
|
||||
"l_unsupported_key_type": null,
|
||||
"l_delete_certificate": "証明書を削除",
|
||||
"l_delete_certificate_desc": "YubiKeyか証明書の削除",
|
||||
"s_issuer": "発行者",
|
||||
|
@ -479,6 +479,7 @@
|
||||
"l_import_nothing": null,
|
||||
"l_importing_file": "Importowanie pliku\u2026",
|
||||
"s_file_imported": "Plik został zaimportowany",
|
||||
"l_unsupported_key_type": null,
|
||||
"l_delete_certificate": "Usuń certyfikat",
|
||||
"l_delete_certificate_desc": "Usuń certyfikat z klucza YubiKey",
|
||||
"s_issuer": "Wydawca",
|
||||
|
@ -83,7 +83,7 @@ class _ConfigureStaticDialogState extends ConsumerState<ConfigureStaticDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
final password = _passwordController.text.replaceAll(' ', '');
|
||||
final password = _passwordController.text;
|
||||
final passwordLengthValid =
|
||||
password.isNotEmpty && password.length <= passwordMaxLength;
|
||||
final passwordFormatValid =
|
||||
|
@ -77,7 +77,11 @@ enum PinPolicy {
|
||||
@JsonValue(0x02)
|
||||
once,
|
||||
@JsonValue(0x03)
|
||||
always;
|
||||
always,
|
||||
@JsonValue(0x04)
|
||||
matchOnce,
|
||||
@JsonValue(0x05)
|
||||
matchAlways;
|
||||
|
||||
const PinPolicy();
|
||||
|
||||
|
@ -84,6 +84,8 @@ const _$PinPolicyEnumMap = {
|
||||
PinPolicy.never: 1,
|
||||
PinPolicy.once: 2,
|
||||
PinPolicy.always: 3,
|
||||
PinPolicy.matchOnce: 4,
|
||||
PinPolicy.matchAlways: 5,
|
||||
};
|
||||
|
||||
_$PivStateMetadataImpl _$$PivStateMetadataImplFromJson(
|
||||
|
@ -30,6 +30,7 @@ import '../keys.dart' as keys;
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
import 'overwrite_confirm_dialog.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
class GenerateKeyDialog extends ConsumerStatefulWidget {
|
||||
final DevicePath devicePath;
|
||||
@ -65,19 +66,6 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
_validToMax = DateTime.utc(now.year + 10, now.month, now.day);
|
||||
}
|
||||
|
||||
List<KeyType> _getSupportedKeyTypes(bool isFips) => [
|
||||
if (!isFips) KeyType.rsa1024,
|
||||
KeyType.rsa2048,
|
||||
if (widget.pivState.version.isAtLeast(5, 7)) ...[
|
||||
KeyType.rsa3072,
|
||||
KeyType.rsa4096,
|
||||
KeyType.ed25519,
|
||||
if (!isFips) KeyType.x25519,
|
||||
],
|
||||
KeyType.eccp256,
|
||||
KeyType.eccp384,
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
@ -202,7 +190,8 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
runSpacing: 8.0,
|
||||
children: [
|
||||
ChoiceFilterChip<KeyType>(
|
||||
items: _getSupportedKeyTypes(isFips),
|
||||
items:
|
||||
getSupportedKeyTypes(widget.pivState.version, isFips),
|
||||
value: _keyType,
|
||||
selected: _keyType != defaultKeyType,
|
||||
itemBuilder: (value) => Text(value.getDisplayName(l10n)),
|
||||
|
@ -31,6 +31,7 @@ import '../models.dart';
|
||||
import '../state.dart';
|
||||
import 'cert_info_view.dart';
|
||||
import 'overwrite_confirm_dialog.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
class ImportFileDialog extends ConsumerStatefulWidget {
|
||||
final DevicePath devicePath;
|
||||
@ -86,10 +87,13 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
// This is what ListTile uses for subtitle
|
||||
final subtitleStyle = textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
);
|
||||
// This is what TextInput errors look like
|
||||
final errorStyle = textTheme.labelLarge!.copyWith(color: colorScheme.error);
|
||||
final state = _state;
|
||||
if (state == null) {
|
||||
return ResponsiveDialog(
|
||||
@ -166,116 +170,142 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
),
|
||||
),
|
||||
),
|
||||
result: (_, keyType, certInfo) => ResponsiveDialog(
|
||||
title: Text(l10n.l_import_file),
|
||||
actions: [
|
||||
TextButton(
|
||||
key: keys.unlockButton,
|
||||
onPressed: (keyType == null && certInfo == null) || _importing
|
||||
? null
|
||||
: () async {
|
||||
final withContext = ref.read(withContextProvider);
|
||||
result: (_, keyType, certInfo) {
|
||||
final isFips =
|
||||
ref.watch(currentDeviceDataProvider).valueOrNull?.info.isFips ??
|
||||
false;
|
||||
final unsupportedKey = keyType != null &&
|
||||
!getSupportedKeyTypes(widget.pivState.version, isFips)
|
||||
.contains(keyType);
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_import_file),
|
||||
actions: [
|
||||
TextButton(
|
||||
key: keys.unlockButton,
|
||||
onPressed: (keyType == null && certInfo == null) ||
|
||||
_importing ||
|
||||
unsupportedKey
|
||||
? null
|
||||
: () async {
|
||||
final withContext = ref.read(withContextProvider);
|
||||
|
||||
if (!await confirmOverwrite(
|
||||
context,
|
||||
widget.pivSlot,
|
||||
writeKey: keyType != null,
|
||||
writeCert: certInfo != null,
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
if (!await confirmOverwrite(
|
||||
context,
|
||||
widget.pivSlot,
|
||||
writeKey: keyType != null,
|
||||
writeCert: certInfo != null,
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_importing = true;
|
||||
});
|
||||
|
||||
void Function()? close;
|
||||
try {
|
||||
close = await withContext<void Function()>(
|
||||
(context) async => showMessage(
|
||||
context,
|
||||
l10n.l_importing_file,
|
||||
duration: const Duration(seconds: 30),
|
||||
));
|
||||
await ref
|
||||
.read(pivSlotsProvider(widget.devicePath).notifier)
|
||||
.import(widget.pivSlot.slot, _data,
|
||||
password:
|
||||
_password.isNotEmpty ? _password : null);
|
||||
await withContext(
|
||||
(context) async {
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, l10n.s_file_imported);
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
// TODO: More error cases
|
||||
setState(() {
|
||||
_passwordIsWrong = true;
|
||||
_importing = false;
|
||||
_importing = true;
|
||||
});
|
||||
} finally {
|
||||
close?.call();
|
||||
}
|
||||
},
|
||||
child: Text(l10n.s_import),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l10n.p_import_items_desc(
|
||||
widget.pivSlot.slot.getDisplayName(l10n))),
|
||||
if (keyType == null && certInfo == null) ...[
|
||||
Text(
|
||||
l10n.l_import_nothing,
|
||||
style: subtitleStyle,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
if (keyType != null) ...[
|
||||
Text(
|
||||
l10n.s_private_key,
|
||||
style: textTheme.bodyLarge,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(l10n.s_algorithm),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
keyType.name.toUpperCase(),
|
||||
style: subtitleStyle,
|
||||
|
||||
void Function()? close;
|
||||
try {
|
||||
close = await withContext<void Function()>(
|
||||
(context) async => showMessage(
|
||||
context,
|
||||
l10n.l_importing_file,
|
||||
duration: const Duration(seconds: 30),
|
||||
));
|
||||
await ref
|
||||
.read(pivSlotsProvider(widget.devicePath).notifier)
|
||||
.import(widget.pivSlot.slot, _data,
|
||||
password:
|
||||
_password.isNotEmpty ? _password : null);
|
||||
await withContext(
|
||||
(context) async {
|
||||
Navigator.of(context).pop(true);
|
||||
showMessage(context, l10n.s_file_imported);
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
// TODO: More error cases
|
||||
setState(() {
|
||||
_passwordIsWrong = true;
|
||||
_importing = false;
|
||||
});
|
||||
} finally {
|
||||
close?.call();
|
||||
}
|
||||
},
|
||||
child: Text(l10n.s_import),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l10n.p_import_items_desc(
|
||||
widget.pivSlot.slot.getDisplayName(l10n))),
|
||||
if (keyType == null && certInfo == null) ...[
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.error, color: colorScheme.error),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.l_import_nothing,
|
||||
style: errorStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
if (keyType != null) ...[
|
||||
Text(
|
||||
l10n.s_private_key,
|
||||
style: textTheme.bodyLarge,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(l10n.s_algorithm),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
keyType.name.toUpperCase(),
|
||||
style: subtitleStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (unsupportedKey)
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.error, color: colorScheme.error),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
l10n.l_unsupported_key_type,
|
||||
style: errorStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
if (certInfo != null) ...[
|
||||
Text(
|
||||
l10n.s_certificate,
|
||||
style: textTheme.bodyLarge,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(
|
||||
height: 140, // Needed for layout, adapt if text sizes changes
|
||||
child: CertInfoTable(certInfo, null),
|
||||
),
|
||||
],
|
||||
if (certInfo != null) ...[
|
||||
Text(
|
||||
l10n.s_certificate,
|
||||
style: textTheme.bodyLarge,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(
|
||||
height:
|
||||
140, // Needed for layout, adapt if text sizes changes
|
||||
child: CertInfoTable(certInfo, null),
|
||||
),
|
||||
]
|
||||
]
|
||||
]
|
||||
.map((e) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: e,
|
||||
))
|
||||
.toList(),
|
||||
.map((e) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: e,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
31
lib/piv/views/utils.dart
Normal file
31
lib/piv/views/utils.dart
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Yubico.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import '../../core/models.dart';
|
||||
import '../models.dart';
|
||||
|
||||
List<KeyType> getSupportedKeyTypes(Version version, bool isFips) => [
|
||||
if (!isFips) KeyType.rsa1024,
|
||||
KeyType.rsa2048,
|
||||
if (version.isAtLeast(5, 7)) ...[
|
||||
KeyType.rsa3072,
|
||||
KeyType.rsa4096,
|
||||
KeyType.ed25519,
|
||||
if (!isFips) KeyType.x25519,
|
||||
],
|
||||
KeyType.eccp256,
|
||||
KeyType.eccp384,
|
||||
];
|
@ -1,5 +1,5 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// This file is generated by running ./set-version.py <version> <build>
|
||||
|
||||
const String version = '6.4.0-dev.0';
|
||||
const int build = 60400;
|
||||
const String version = '6.4.0';
|
||||
const int build = 60401;
|
||||
|
@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
|
||||
# This field is updated by running ./set-version.py <version>
|
||||
# DO NOT MANUALLY EDIT THIS!
|
||||
version: 6.4.0-dev.0+60400
|
||||
version: 6.4.0+60401
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
|
@ -1,4 +1,4 @@
|
||||
$version="6.4.0-dev.0"
|
||||
$version="6.4.0"
|
||||
|
||||
echo "Clean-up of old files"
|
||||
rm *.msi
|
||||
|
Loading…
Reference in New Issue
Block a user