mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 10:11:52 +03:00
Allow multiple capabilities.
This commit is contained in:
parent
aee0824bf3
commit
81ac767036
@ -30,17 +30,23 @@ const _listEquality = ListEquality();
|
||||
enum Availability { enabled, disabled, unsupported }
|
||||
|
||||
enum Application {
|
||||
accounts,
|
||||
webauthn,
|
||||
fingerprints,
|
||||
passkeys,
|
||||
slots,
|
||||
certificates,
|
||||
openpgp,
|
||||
hsmauth,
|
||||
management;
|
||||
accounts([Capability.oath]),
|
||||
webauthn([Capability.u2f]),
|
||||
fingerprints([Capability.fido2]),
|
||||
passkeys([Capability.fido2]),
|
||||
slots([Capability.otp]),
|
||||
certificates([Capability.piv]),
|
||||
openpgp([Capability.openpgp]),
|
||||
hsmauth([Capability.hsmauth]),
|
||||
management();
|
||||
|
||||
const Application();
|
||||
final List<Capability> capabilities;
|
||||
|
||||
List<Capability> getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
const Application([this.capabilities = const []]);
|
||||
|
||||
bool _inCapabilities(int capabilities) => switch (this) {
|
||||
Application.accounts => Capability.oath.value & capabilities != 0,
|
||||
@ -65,18 +71,6 @@ enum Application {
|
||||
_ => name.substring(0, 1).toUpperCase() + name.substring(1),
|
||||
};
|
||||
|
||||
Capability? getCapability() => switch (this) {
|
||||
Application.accounts => Capability.oath,
|
||||
Application.webauthn => Capability.u2f,
|
||||
Application.passkeys => Capability.fido2,
|
||||
Application.fingerprints => Capability.fido2,
|
||||
Application.certificates => Capability.piv,
|
||||
Application.slots => Capability.otp,
|
||||
Application.hsmauth => Capability.hsmauth,
|
||||
Application.openpgp => Capability.openpgp,
|
||||
_ => null
|
||||
};
|
||||
|
||||
Availability getAvailability(YubiKeyData data) {
|
||||
if (this == Application.management) {
|
||||
final version = data.info.version;
|
||||
|
@ -44,7 +44,7 @@ class AppPage extends StatelessWidget {
|
||||
final Widget Function(BuildContext context)? actionButtonBuilder;
|
||||
final Widget? fileDropOverlay;
|
||||
final Function(File file)? onFileDropped;
|
||||
final Capability? capability;
|
||||
final List<Capability>? capabilities;
|
||||
const AppPage({
|
||||
super.key,
|
||||
this.title,
|
||||
@ -55,7 +55,7 @@ class AppPage extends StatelessWidget {
|
||||
this.detailViewBuilder,
|
||||
this.actionButtonBuilder,
|
||||
this.fileDropOverlay,
|
||||
this.capability,
|
||||
this.capabilities,
|
||||
this.onFileDropped,
|
||||
this.delayedContent = false,
|
||||
this.keyActionsBadge = false,
|
||||
@ -169,7 +169,12 @@ class AppPage extends StatelessWidget {
|
||||
.colorScheme
|
||||
.primary
|
||||
.withOpacity(0.9))),
|
||||
if (capability != null) _CapabilityBadge(capability!)
|
||||
if (capabilities != null)
|
||||
Wrap(
|
||||
spacing: 4.0,
|
||||
runSpacing: 8.0,
|
||||
children: [...capabilities!.map((c) => _CapabilityBadge(c))],
|
||||
)
|
||||
])
|
||||
],
|
||||
);
|
||||
|
@ -133,7 +133,7 @@ class MainPage extends ConsumerWidget {
|
||||
return ref.watch(currentDeviceDataProvider).when(
|
||||
data: (data) {
|
||||
final app = ref.watch(currentAppProvider);
|
||||
final capability = app.getCapability();
|
||||
final capabilities = app.getCapabilities();
|
||||
if (data.info.supportedCapabilities.isEmpty &&
|
||||
data.name == 'Unrecognized device') {
|
||||
return MessagePage(
|
||||
@ -149,18 +149,20 @@ class MainPage extends ConsumerWidget {
|
||||
Availability.unsupported) {
|
||||
return MessagePage(
|
||||
title: app.getDisplayName(l10n),
|
||||
capability: capability,
|
||||
capabilities: capabilities,
|
||||
header: l10n.s_app_not_supported,
|
||||
message: l10n.l_app_not_supported_on_yk(
|
||||
capability?.getDisplayName(l10n) ?? app.name),
|
||||
message: l10n.l_app_not_supported_on_yk(capabilities
|
||||
.map((c) => c.getDisplayName(l10n))
|
||||
.join(',')),
|
||||
);
|
||||
} else if (app.getAvailability(data) != Availability.enabled) {
|
||||
return MessagePage(
|
||||
title: app.getDisplayName(l10n),
|
||||
capability: capability,
|
||||
capabilities: capabilities,
|
||||
header: l10n.s_app_disabled,
|
||||
message: l10n.l_app_disabled_desc(
|
||||
capability?.getDisplayName(l10n) ?? app.name),
|
||||
message: l10n.l_app_disabled_desc(capabilities
|
||||
.map((c) => c.getDisplayName(l10n))
|
||||
.join(',')),
|
||||
actions: [
|
||||
ActionChip(
|
||||
label: Text(data.info.version.major > 4
|
||||
|
@ -32,7 +32,7 @@ class MessagePage extends StatelessWidget {
|
||||
final Widget Function(BuildContext context)? actionButtonBuilder;
|
||||
final Widget? fileDropOverlay;
|
||||
final Function(File file)? onFileDropped;
|
||||
final Capability? capability;
|
||||
final List<Capability>? capabilities;
|
||||
final bool keyActionsBadge;
|
||||
final bool centered;
|
||||
|
||||
@ -49,14 +49,14 @@ class MessagePage extends StatelessWidget {
|
||||
this.onFileDropped,
|
||||
this.delayedContent = false,
|
||||
this.keyActionsBadge = false,
|
||||
this.capability,
|
||||
this.capabilities,
|
||||
this.centered = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => AppPage(
|
||||
title: title,
|
||||
capability: capability,
|
||||
capabilities: capabilities,
|
||||
centered: centered,
|
||||
actions: actions,
|
||||
keyActionsBuilder: keyActionsBuilder,
|
||||
|
@ -61,7 +61,7 @@ class FingerprintsScreen extends ConsumerWidget {
|
||||
if (Capability.fido2.value & enabled == 0) {
|
||||
return MessagePage(
|
||||
title: l10n.s_fingerprints,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: l10n.s_fido_disabled,
|
||||
message: l10n.l_webauthn_req_fido2,
|
||||
);
|
||||
@ -105,7 +105,7 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
)
|
||||
],
|
||||
title: l10n.s_fingerprints,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: '${l10n.s_fingerprints_get_started} (1/2)',
|
||||
message: l10n.p_set_fingerprints_desc,
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
@ -116,7 +116,7 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
if (state.forcePinChange) {
|
||||
return MessagePage(
|
||||
title: l10n.s_fingerprints,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: l10n.s_pin_change_required,
|
||||
message: l10n.l_pin_change_required_desc,
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
@ -137,7 +137,7 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
|
||||
return AppPage(
|
||||
title: l10n.s_fingerprints,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
builder: (context, _) => Column(
|
||||
children: [
|
||||
@ -190,7 +190,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
)
|
||||
],
|
||||
title: l10n.s_fingerprints,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: '${l10n.s_fingerprints_get_started} (2/2)',
|
||||
message: l10n.l_add_one_or_more_fps,
|
||||
keyActionsBuilder: hasActions
|
||||
@ -250,7 +250,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
},
|
||||
builder: (context) => AppPage(
|
||||
title: l10n.s_fingerprints,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
detailViewBuilder: fingerprint != null
|
||||
? (context) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
@ -61,7 +61,7 @@ class PasskeysScreen extends ConsumerWidget {
|
||||
if (Capability.fido2.value & enabled == 0) {
|
||||
return MessagePage(
|
||||
title: l10n.s_passkeys,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: l10n.s_fido_disabled,
|
||||
message: l10n.l_webauthn_req_fido2,
|
||||
);
|
||||
@ -94,7 +94,7 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
if (!state.hasPin) {
|
||||
return MessagePage(
|
||||
title: l10n.s_passkeys,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: state.credMgmt
|
||||
? l10n.l_no_discoverable_accounts
|
||||
: l10n.l_ready_to_use,
|
||||
@ -107,7 +107,7 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
if (!state.credMgmt && state.bioEnroll == null) {
|
||||
return MessagePage(
|
||||
title: l10n.s_passkeys,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: l10n.l_ready_to_use,
|
||||
message: l10n.l_register_sk_on_websites,
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
@ -129,7 +129,7 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
)
|
||||
],
|
||||
title: l10n.s_passkeys,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: l10n.s_pin_change_required,
|
||||
message: l10n.l_pin_change_required_desc,
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
@ -139,7 +139,7 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
|
||||
return AppPage(
|
||||
title: l10n.s_passkeys,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
builder: (context, _) => Column(
|
||||
children: [
|
||||
@ -177,7 +177,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
// TODO: Special handling for credMgmt not supported
|
||||
return MessagePage(
|
||||
title: l10n.s_passkeys,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: l10n.l_no_discoverable_accounts,
|
||||
message: l10n.l_register_sk_on_websites,
|
||||
keyActionsBuilder: hasActions
|
||||
@ -197,7 +197,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
if (credentials.isEmpty) {
|
||||
return MessagePage(
|
||||
title: l10n.s_passkeys,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
header: l10n.l_no_discoverable_accounts,
|
||||
message: l10n.l_register_sk_on_websites,
|
||||
keyActionsBuilder: hasActions
|
||||
@ -246,7 +246,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
},
|
||||
builder: (context) => AppPage(
|
||||
title: l10n.s_passkeys,
|
||||
capability: Capability.fido2,
|
||||
capabilities: const [Capability.fido2],
|
||||
detailViewBuilder: credential != null
|
||||
? (context) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
@ -28,7 +28,7 @@ class WebAuthnScreen extends StatelessWidget {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return MessagePage(
|
||||
title: l10n.s_webauthn,
|
||||
capability: Capability.u2f,
|
||||
capabilities: const [Capability.u2f],
|
||||
header: l10n.l_ready_to_use,
|
||||
message: l10n.l_register_sk_on_websites,
|
||||
);
|
||||
|
@ -83,7 +83,7 @@ class _LockedView extends ConsumerWidget {
|
||||
final hasActions = ref.watch(featureProvider)(features.actions);
|
||||
return AppPage(
|
||||
title: AppLocalizations.of(context)!.s_accounts,
|
||||
capability: Capability.oath,
|
||||
capabilities: const [Capability.oath],
|
||||
keyActionsBuilder: hasActions
|
||||
? (context) => oathBuildActions(context, devicePath, oathState, ref)
|
||||
: null,
|
||||
@ -175,7 +175,7 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
|
||||
)
|
||||
],
|
||||
title: l10n.s_accounts,
|
||||
capability: Capability.oath,
|
||||
capabilities: const [Capability.oath],
|
||||
key: keys.noAccountsView,
|
||||
header: l10n.l_authenticator_get_started,
|
||||
message: l10n.p_no_accounts_desc,
|
||||
@ -249,7 +249,7 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
|
||||
},
|
||||
builder: (context) => AppPage(
|
||||
title: l10n.s_accounts,
|
||||
capability: Capability.oath,
|
||||
capabilities: const [Capability.oath],
|
||||
keyActionsBuilder: hasActions
|
||||
? (context) => oathBuildActions(
|
||||
context,
|
||||
|
@ -93,7 +93,7 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
|
||||
},
|
||||
child: AppPage(
|
||||
title: l10n.s_slots,
|
||||
capability: Capability.otp,
|
||||
capabilities: const [Capability.otp],
|
||||
detailViewBuilder: selected != null
|
||||
? (context) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
@ -106,7 +106,7 @@ class _PivScreenState extends ConsumerState<PivScreen> {
|
||||
},
|
||||
child: AppPage(
|
||||
title: l10n.s_certificates,
|
||||
capability: Capability.piv,
|
||||
capabilities: const [Capability.piv],
|
||||
detailViewBuilder: selected != null
|
||||
? (context) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
Loading…
Reference in New Issue
Block a user