Add basic NFC support.

This commit is contained in:
Dain Nilsson 2022-01-12 12:49:04 +01:00
parent 9136a4505d
commit 7d88c5c6a5
No known key found for this signature in database
GPG Key ID: F04367096FBA95E8
18 changed files with 977 additions and 348 deletions

View File

@ -3,10 +3,25 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import '../../management/models.dart'; import '../../management/models.dart';
part 'models.freezed.dart'; part 'models.freezed.dart';
part 'models.g.dart'; //part 'models.g.dart';
enum SubPage { authenticator, yubikey } enum SubPage { authenticator, yubikey }
@freezed
class YubiKeyData with _$YubiKeyData {
factory YubiKeyData(DeviceNode node, String name, DeviceInfo info) =
_YubiKeyData;
}
@freezed
class DeviceNode with _$DeviceNode {
factory DeviceNode.usbYubiKey(
List<String> path, String name, int pid, DeviceInfo info) =
UsbYubiKeyNode;
factory DeviceNode.nfcReader(List<String> path, String name) = NfcReaderNode;
}
/*
@freezed @freezed
class DeviceNode with _$DeviceNode { class DeviceNode with _$DeviceNode {
factory DeviceNode( factory DeviceNode(
@ -16,10 +31,8 @@ class DeviceNode with _$DeviceNode {
String name, String name,
DeviceInfo info, DeviceInfo info,
) = _DeviceNode; ) = _DeviceNode;
factory DeviceNode.fromJson(Map<String, dynamic> json) =>
_$DeviceNodeFromJson(json);
} }
*/
@freezed @freezed
class MenuAction with _$MenuAction { class MenuAction with _$MenuAction {

View File

@ -1,5 +1,6 @@
// coverage:ignore-file // coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'models.dart'; part of 'models.dart';
@ -13,27 +14,212 @@ T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError( final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
DeviceNode _$DeviceNodeFromJson(Map<String, dynamic> json) { /// @nodoc
return _DeviceNode.fromJson(json); class _$YubiKeyDataTearOff {
const _$YubiKeyDataTearOff();
_YubiKeyData call(DeviceNode node, String name, DeviceInfo info) {
return _YubiKeyData(
node,
name,
info,
);
}
}
/// @nodoc
const $YubiKeyData = _$YubiKeyDataTearOff();
/// @nodoc
mixin _$YubiKeyData {
DeviceNode get node => throw _privateConstructorUsedError;
String get name => throw _privateConstructorUsedError;
DeviceInfo get info => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$YubiKeyDataCopyWith<YubiKeyData> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $YubiKeyDataCopyWith<$Res> {
factory $YubiKeyDataCopyWith(
YubiKeyData value, $Res Function(YubiKeyData) then) =
_$YubiKeyDataCopyWithImpl<$Res>;
$Res call({DeviceNode node, String name, DeviceInfo info});
$DeviceNodeCopyWith<$Res> get node;
$DeviceInfoCopyWith<$Res> get info;
}
/// @nodoc
class _$YubiKeyDataCopyWithImpl<$Res> implements $YubiKeyDataCopyWith<$Res> {
_$YubiKeyDataCopyWithImpl(this._value, this._then);
final YubiKeyData _value;
// ignore: unused_field
final $Res Function(YubiKeyData) _then;
@override
$Res call({
Object? node = freezed,
Object? name = freezed,
Object? info = freezed,
}) {
return _then(_value.copyWith(
node: node == freezed
? _value.node
: node // ignore: cast_nullable_to_non_nullable
as DeviceNode,
name: name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
info: info == freezed
? _value.info
: info // ignore: cast_nullable_to_non_nullable
as DeviceInfo,
));
}
@override
$DeviceNodeCopyWith<$Res> get node {
return $DeviceNodeCopyWith<$Res>(_value.node, (value) {
return _then(_value.copyWith(node: value));
});
}
@override
$DeviceInfoCopyWith<$Res> get info {
return $DeviceInfoCopyWith<$Res>(_value.info, (value) {
return _then(_value.copyWith(info: value));
});
}
}
/// @nodoc
abstract class _$YubiKeyDataCopyWith<$Res>
implements $YubiKeyDataCopyWith<$Res> {
factory _$YubiKeyDataCopyWith(
_YubiKeyData value, $Res Function(_YubiKeyData) then) =
__$YubiKeyDataCopyWithImpl<$Res>;
@override
$Res call({DeviceNode node, String name, DeviceInfo info});
@override
$DeviceNodeCopyWith<$Res> get node;
@override
$DeviceInfoCopyWith<$Res> get info;
}
/// @nodoc
class __$YubiKeyDataCopyWithImpl<$Res> extends _$YubiKeyDataCopyWithImpl<$Res>
implements _$YubiKeyDataCopyWith<$Res> {
__$YubiKeyDataCopyWithImpl(
_YubiKeyData _value, $Res Function(_YubiKeyData) _then)
: super(_value, (v) => _then(v as _YubiKeyData));
@override
_YubiKeyData get _value => super._value as _YubiKeyData;
@override
$Res call({
Object? node = freezed,
Object? name = freezed,
Object? info = freezed,
}) {
return _then(_YubiKeyData(
node == freezed
? _value.node
: node // ignore: cast_nullable_to_non_nullable
as DeviceNode,
name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
info == freezed
? _value.info
: info // ignore: cast_nullable_to_non_nullable
as DeviceInfo,
));
}
}
/// @nodoc
class _$_YubiKeyData implements _YubiKeyData {
_$_YubiKeyData(this.node, this.name, this.info);
@override
final DeviceNode node;
@override
final String name;
@override
final DeviceInfo info;
@override
String toString() {
return 'YubiKeyData(node: $node, name: $name, info: $info)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _YubiKeyData &&
const DeepCollectionEquality().equals(other.node, node) &&
const DeepCollectionEquality().equals(other.name, name) &&
const DeepCollectionEquality().equals(other.info, info));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(node),
const DeepCollectionEquality().hash(name),
const DeepCollectionEquality().hash(info));
@JsonKey(ignore: true)
@override
_$YubiKeyDataCopyWith<_YubiKeyData> get copyWith =>
__$YubiKeyDataCopyWithImpl<_YubiKeyData>(this, _$identity);
}
abstract class _YubiKeyData implements YubiKeyData {
factory _YubiKeyData(DeviceNode node, String name, DeviceInfo info) =
_$_YubiKeyData;
@override
DeviceNode get node;
@override
String get name;
@override
DeviceInfo get info;
@override
@JsonKey(ignore: true)
_$YubiKeyDataCopyWith<_YubiKeyData> get copyWith =>
throw _privateConstructorUsedError;
} }
/// @nodoc /// @nodoc
class _$DeviceNodeTearOff { class _$DeviceNodeTearOff {
const _$DeviceNodeTearOff(); const _$DeviceNodeTearOff();
_DeviceNode call(List<String> path, int pid, Transport transport, String name, UsbYubiKeyNode usbYubiKey(
DeviceInfo info) { List<String> path, String name, int pid, DeviceInfo info) {
return _DeviceNode( return UsbYubiKeyNode(
path, path,
pid,
transport,
name, name,
pid,
info, info,
); );
} }
DeviceNode fromJson(Map<String, Object?> json) { NfcReaderNode nfcReader(List<String> path, String name) {
return DeviceNode.fromJson(json); return NfcReaderNode(
path,
name,
);
} }
} }
@ -43,12 +229,51 @@ const $DeviceNode = _$DeviceNodeTearOff();
/// @nodoc /// @nodoc
mixin _$DeviceNode { mixin _$DeviceNode {
List<String> get path => throw _privateConstructorUsedError; List<String> get path => throw _privateConstructorUsedError;
int get pid => throw _privateConstructorUsedError;
Transport get transport => throw _privateConstructorUsedError;
String get name => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError;
DeviceInfo get info => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError; @optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(
List<String> path, String name, int pid, DeviceInfo info)
usbYubiKey,
required TResult Function(List<String> path, String name) nfcReader,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(UsbYubiKeyNode value) usbYubiKey,
required TResult Function(NfcReaderNode value) nfcReader,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true) @JsonKey(ignore: true)
$DeviceNodeCopyWith<DeviceNode> get copyWith => $DeviceNodeCopyWith<DeviceNode> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@ -59,14 +284,7 @@ abstract class $DeviceNodeCopyWith<$Res> {
factory $DeviceNodeCopyWith( factory $DeviceNodeCopyWith(
DeviceNode value, $Res Function(DeviceNode) then) = DeviceNode value, $Res Function(DeviceNode) then) =
_$DeviceNodeCopyWithImpl<$Res>; _$DeviceNodeCopyWithImpl<$Res>;
$Res call( $Res call({List<String> path, String name});
{List<String> path,
int pid,
Transport transport,
String name,
DeviceInfo info});
$DeviceInfoCopyWith<$Res> get info;
} }
/// @nodoc /// @nodoc
@ -80,29 +298,64 @@ class _$DeviceNodeCopyWithImpl<$Res> implements $DeviceNodeCopyWith<$Res> {
@override @override
$Res call({ $Res call({
Object? path = freezed, Object? path = freezed,
Object? pid = freezed,
Object? transport = freezed,
Object? name = freezed, Object? name = freezed,
Object? info = freezed,
}) { }) {
return _then(_value.copyWith( return _then(_value.copyWith(
path: path == freezed path: path == freezed
? _value.path ? _value.path
: path // ignore: cast_nullable_to_non_nullable : path // ignore: cast_nullable_to_non_nullable
as List<String>, as List<String>,
pid: pid == freezed
? _value.pid
: pid // ignore: cast_nullable_to_non_nullable
as int,
transport: transport == freezed
? _value.transport
: transport // ignore: cast_nullable_to_non_nullable
as Transport,
name: name == freezed name: name == freezed
? _value.name ? _value.name
: name // ignore: cast_nullable_to_non_nullable : name // ignore: cast_nullable_to_non_nullable
as String, as String,
info: info == freezed ));
}
}
/// @nodoc
abstract class $UsbYubiKeyNodeCopyWith<$Res>
implements $DeviceNodeCopyWith<$Res> {
factory $UsbYubiKeyNodeCopyWith(
UsbYubiKeyNode value, $Res Function(UsbYubiKeyNode) then) =
_$UsbYubiKeyNodeCopyWithImpl<$Res>;
@override
$Res call({List<String> path, String name, int pid, DeviceInfo info});
$DeviceInfoCopyWith<$Res> get info;
}
/// @nodoc
class _$UsbYubiKeyNodeCopyWithImpl<$Res> extends _$DeviceNodeCopyWithImpl<$Res>
implements $UsbYubiKeyNodeCopyWith<$Res> {
_$UsbYubiKeyNodeCopyWithImpl(
UsbYubiKeyNode _value, $Res Function(UsbYubiKeyNode) _then)
: super(_value, (v) => _then(v as UsbYubiKeyNode));
@override
UsbYubiKeyNode get _value => super._value as UsbYubiKeyNode;
@override
$Res call({
Object? path = freezed,
Object? name = freezed,
Object? pid = freezed,
Object? info = freezed,
}) {
return _then(UsbYubiKeyNode(
path == freezed
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as List<String>,
name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
pid == freezed
? _value.pid
: pid // ignore: cast_nullable_to_non_nullable
as int,
info == freezed
? _value.info ? _value.info
: info // ignore: cast_nullable_to_non_nullable : info // ignore: cast_nullable_to_non_nullable
as DeviceInfo, as DeviceInfo,
@ -118,137 +371,282 @@ class _$DeviceNodeCopyWithImpl<$Res> implements $DeviceNodeCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
abstract class _$DeviceNodeCopyWith<$Res> implements $DeviceNodeCopyWith<$Res> {
factory _$DeviceNodeCopyWith(
_DeviceNode value, $Res Function(_DeviceNode) then) =
__$DeviceNodeCopyWithImpl<$Res>;
@override
$Res call(
{List<String> path,
int pid,
Transport transport,
String name,
DeviceInfo info});
@override class _$UsbYubiKeyNode implements UsbYubiKeyNode {
$DeviceInfoCopyWith<$Res> get info; _$UsbYubiKeyNode(this.path, this.name, this.pid, this.info);
}
/// @nodoc
class __$DeviceNodeCopyWithImpl<$Res> extends _$DeviceNodeCopyWithImpl<$Res>
implements _$DeviceNodeCopyWith<$Res> {
__$DeviceNodeCopyWithImpl(
_DeviceNode _value, $Res Function(_DeviceNode) _then)
: super(_value, (v) => _then(v as _DeviceNode));
@override
_DeviceNode get _value => super._value as _DeviceNode;
@override
$Res call({
Object? path = freezed,
Object? pid = freezed,
Object? transport = freezed,
Object? name = freezed,
Object? info = freezed,
}) {
return _then(_DeviceNode(
path == freezed
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as List<String>,
pid == freezed
? _value.pid
: pid // ignore: cast_nullable_to_non_nullable
as int,
transport == freezed
? _value.transport
: transport // ignore: cast_nullable_to_non_nullable
as Transport,
name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
info == freezed
? _value.info
: info // ignore: cast_nullable_to_non_nullable
as DeviceInfo,
));
}
}
/// @nodoc
@JsonSerializable()
class _$_DeviceNode implements _DeviceNode {
_$_DeviceNode(this.path, this.pid, this.transport, this.name, this.info);
factory _$_DeviceNode.fromJson(Map<String, dynamic> json) =>
_$$_DeviceNodeFromJson(json);
@override @override
final List<String> path; final List<String> path;
@override @override
final int pid;
@override
final Transport transport;
@override
final String name; final String name;
@override @override
final int pid;
@override
final DeviceInfo info; final DeviceInfo info;
@override @override
String toString() { String toString() {
return 'DeviceNode(path: $path, pid: $pid, transport: $transport, name: $name, info: $info)'; return 'DeviceNode.usbYubiKey(path: $path, name: $name, pid: $pid, info: $info)';
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(dynamic other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _DeviceNode && other is UsbYubiKeyNode &&
const DeepCollectionEquality().equals(other.path, path) && const DeepCollectionEquality().equals(other.path, path) &&
(identical(other.pid, pid) || other.pid == pid) && const DeepCollectionEquality().equals(other.name, name) &&
(identical(other.transport, transport) || const DeepCollectionEquality().equals(other.pid, pid) &&
other.transport == transport) && const DeepCollectionEquality().equals(other.info, info));
(identical(other.name, name) || other.name == name) &&
(identical(other.info, info) || other.info == info));
} }
@override @override
int get hashCode => Object.hash(runtimeType, int get hashCode => Object.hash(
const DeepCollectionEquality().hash(path), pid, transport, name, info); runtimeType,
const DeepCollectionEquality().hash(path),
const DeepCollectionEquality().hash(name),
const DeepCollectionEquality().hash(pid),
const DeepCollectionEquality().hash(info));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
_$DeviceNodeCopyWith<_DeviceNode> get copyWith => $UsbYubiKeyNodeCopyWith<UsbYubiKeyNode> get copyWith =>
__$DeviceNodeCopyWithImpl<_DeviceNode>(this, _$identity); _$UsbYubiKeyNodeCopyWithImpl<UsbYubiKeyNode>(this, _$identity);
@override @override
Map<String, dynamic> toJson() { @optionalTypeArgs
return _$$_DeviceNodeToJson(this); TResult when<TResult extends Object?>({
required TResult Function(
List<String> path, String name, int pid, DeviceInfo info)
usbYubiKey,
required TResult Function(List<String> path, String name) nfcReader,
}) {
return usbYubiKey(path, name, pid, info);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
}) {
return usbYubiKey?.call(path, name, pid, info);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
required TResult orElse(),
}) {
if (usbYubiKey != null) {
return usbYubiKey(path, name, pid, info);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(UsbYubiKeyNode value) usbYubiKey,
required TResult Function(NfcReaderNode value) nfcReader,
}) {
return usbYubiKey(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
}) {
return usbYubiKey?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
required TResult orElse(),
}) {
if (usbYubiKey != null) {
return usbYubiKey(this);
}
return orElse();
} }
} }
abstract class _DeviceNode implements DeviceNode { abstract class UsbYubiKeyNode implements DeviceNode {
factory _DeviceNode(List<String> path, int pid, Transport transport, factory UsbYubiKeyNode(
String name, DeviceInfo info) = _$_DeviceNode; List<String> path, String name, int pid, DeviceInfo info) =
_$UsbYubiKeyNode;
factory _DeviceNode.fromJson(Map<String, dynamic> json) =
_$_DeviceNode.fromJson;
@override @override
List<String> get path; List<String> get path;
@override @override
int get pid;
@override
Transport get transport;
@override
String get name; String get name;
@override int get pid;
DeviceInfo get info; DeviceInfo get info;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$DeviceNodeCopyWith<_DeviceNode> get copyWith => $UsbYubiKeyNodeCopyWith<UsbYubiKeyNode> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $NfcReaderNodeCopyWith<$Res>
implements $DeviceNodeCopyWith<$Res> {
factory $NfcReaderNodeCopyWith(
NfcReaderNode value, $Res Function(NfcReaderNode) then) =
_$NfcReaderNodeCopyWithImpl<$Res>;
@override
$Res call({List<String> path, String name});
}
/// @nodoc
class _$NfcReaderNodeCopyWithImpl<$Res> extends _$DeviceNodeCopyWithImpl<$Res>
implements $NfcReaderNodeCopyWith<$Res> {
_$NfcReaderNodeCopyWithImpl(
NfcReaderNode _value, $Res Function(NfcReaderNode) _then)
: super(_value, (v) => _then(v as NfcReaderNode));
@override
NfcReaderNode get _value => super._value as NfcReaderNode;
@override
$Res call({
Object? path = freezed,
Object? name = freezed,
}) {
return _then(NfcReaderNode(
path == freezed
? _value.path
: path // ignore: cast_nullable_to_non_nullable
as List<String>,
name == freezed
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$NfcReaderNode implements NfcReaderNode {
_$NfcReaderNode(this.path, this.name);
@override
final List<String> path;
@override
final String name;
@override
String toString() {
return 'DeviceNode.nfcReader(path: $path, name: $name)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is NfcReaderNode &&
const DeepCollectionEquality().equals(other.path, path) &&
const DeepCollectionEquality().equals(other.name, name));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(path),
const DeepCollectionEquality().hash(name));
@JsonKey(ignore: true)
@override
$NfcReaderNodeCopyWith<NfcReaderNode> get copyWith =>
_$NfcReaderNodeCopyWithImpl<NfcReaderNode>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(
List<String> path, String name, int pid, DeviceInfo info)
usbYubiKey,
required TResult Function(List<String> path, String name) nfcReader,
}) {
return nfcReader(path, name);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
}) {
return nfcReader?.call(path, name);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(List<String> path, String name, int pid, DeviceInfo info)?
usbYubiKey,
TResult Function(List<String> path, String name)? nfcReader,
required TResult orElse(),
}) {
if (nfcReader != null) {
return nfcReader(path, name);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(UsbYubiKeyNode value) usbYubiKey,
required TResult Function(NfcReaderNode value) nfcReader,
}) {
return nfcReader(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
}) {
return nfcReader?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(UsbYubiKeyNode value)? usbYubiKey,
TResult Function(NfcReaderNode value)? nfcReader,
required TResult orElse(),
}) {
if (nfcReader != null) {
return nfcReader(this);
}
return orElse();
}
}
abstract class NfcReaderNode implements DeviceNode {
factory NfcReaderNode(List<String> path, String name) = _$NfcReaderNode;
@override
List<String> get path;
@override
String get name;
@override
@JsonKey(ignore: true)
$NfcReaderNodeCopyWith<NfcReaderNode> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@ -383,13 +781,17 @@ class _$_MenuAction implements _MenuAction {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _MenuAction && other is _MenuAction &&
(identical(other.text, text) || other.text == text) && const DeepCollectionEquality().equals(other.text, text) &&
(identical(other.icon, icon) || other.icon == icon) && const DeepCollectionEquality().equals(other.icon, icon) &&
(identical(other.action, action) || other.action == action)); (identical(other.action, action) || other.action == action));
} }
@override @override
int get hashCode => Object.hash(runtimeType, text, icon, action); int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(text),
const DeepCollectionEquality().hash(icon),
action);
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -548,13 +950,17 @@ class _$_WindowState implements _WindowState {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _WindowState && other is _WindowState &&
(identical(other.focused, focused) || other.focused == focused) && const DeepCollectionEquality().equals(other.focused, focused) &&
(identical(other.visible, visible) || other.visible == visible) && const DeepCollectionEquality().equals(other.visible, visible) &&
(identical(other.active, active) || other.active == active)); const DeepCollectionEquality().equals(other.active, active));
} }
@override @override
int get hashCode => Object.hash(runtimeType, focused, visible, active); int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(focused),
const DeepCollectionEquality().hash(visible),
const DeepCollectionEquality().hash(active));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override

View File

@ -1,30 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'models.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_DeviceNode _$$_DeviceNodeFromJson(Map<String, dynamic> json) =>
_$_DeviceNode(
(json['path'] as List<dynamic>).map((e) => e as String).toList(),
json['pid'] as int,
$enumDecode(_$TransportEnumMap, json['transport']),
json['name'] as String,
DeviceInfo.fromJson(json['info'] as Map<String, dynamic>),
);
Map<String, dynamic> _$$_DeviceNodeToJson(_$_DeviceNode instance) =>
<String, dynamic>{
'path': instance.path,
'pid': instance.pid,
'transport': _$TransportEnumMap[instance.transport],
'name': instance.name,
'info': instance.info,
};
const _$TransportEnumMap = {
Transport.usb: 'usb',
Transport.nfc: 'nfc',
};

View File

@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
import 'package:yubico_authenticator/management/models.dart';
import '../core/models.dart'; import '../core/models.dart';
import '../core/state.dart'; import '../core/state.dart';
@ -118,24 +119,24 @@ class SearchNotifier extends StateNotifier<String> {
} }
} }
final attachedDevicesProvider = final _usbDevicesProvider =
StateNotifierProvider<AttachedDeviceNotifier, List<DeviceNode>>((ref) { StateNotifierProvider<UsbDeviceNotifier, List<UsbYubiKeyNode>>((ref) {
final notifier = AttachedDeviceNotifier(ref.watch(rpcProvider)); final notifier = UsbDeviceNotifier(ref.watch(rpcProvider));
ref.listen<WindowState>(windowStateProvider, (_, windowState) { ref.listen<WindowState>(windowStateProvider, (_, windowState) {
notifier._notifyWindowState(windowState); notifier._notifyWindowState(windowState);
}, fireImmediately: true); }, fireImmediately: true);
return notifier; return notifier;
}); });
class AttachedDeviceNotifier extends StateNotifier<List<DeviceNode>> { class UsbDeviceNotifier extends StateNotifier<List<UsbYubiKeyNode>> {
final RpcSession _rpc; final RpcSession _rpc;
Timer? _pollTimer; Timer? _pollTimer;
int _usbState = -1; int _usbState = -1;
AttachedDeviceNotifier(this._rpc) : super([]); UsbDeviceNotifier(this._rpc) : super([]);
void _notifyWindowState(WindowState windowState) { void _notifyWindowState(WindowState windowState) {
if (windowState.active) { if (windowState.active) {
_pollUsb(); _pollDevices();
} else { } else {
_pollTimer?.cancel(); _pollTimer?.cancel();
// Release any held device // Release any held device
@ -149,37 +150,110 @@ class AttachedDeviceNotifier extends StateNotifier<List<DeviceNode>> {
super.dispose(); super.dispose();
} }
void _pollUsb() async { void _pollDevices() async {
_pollTimer?.cancel(); _pollTimer?.cancel();
try { try {
var scan = await _rpc.command('scan', ['usb']); var scan = await _rpc.command('scan', ['usb']);
if (_usbState != scan['state'] || state.length != scan['pids'].length) { if (_usbState != scan['state'] || state.length != scan['pids'].length) {
var usbResult = await _rpc.command('get', ['usb']); var usbResult = await _rpc.command('get', ['usb']);
log.info('USB state change', jsonEncode(usbResult)); log.info('USB state change', jsonEncode(usbResult));
_usbState = usbResult['data']['state'];
List<UsbYubiKeyNode> usbDevices = [];
List<DeviceNode> devices = [];
for (String id in (usbResult['children'] as Map).keys) { for (String id in (usbResult['children'] as Map).keys) {
var path = ['usb', id]; var path = ['usb', id];
var deviceResult = await _rpc.command('get', path); var deviceResult = await _rpc.command('get', path);
devices.add( var deviceData = deviceResult['data'];
DeviceNode.fromJson({'path': path, ...deviceResult['data']})); usbDevices.add(DeviceNode.usbYubiKey(
path,
deviceData['name'],
deviceData['pid'],
DeviceInfo.fromJson(deviceData['info']),
) as UsbYubiKeyNode);
} }
_usbState = usbResult['data']['state'];
log.info('USB state updated'); log.info('USB state updated');
if (mounted) { if (mounted) {
state = devices; state = usbDevices;
} }
} }
} on RpcError catch (e) { } on RpcError catch (e) {
log.severe('Error polling USB', jsonEncode(e)); log.severe('Error polling USB', jsonEncode(e));
} }
if (mounted) { if (mounted) {
_pollTimer = Timer(const Duration(milliseconds: 500), _pollUsb); _pollTimer = Timer(const Duration(milliseconds: 500), _pollDevices);
} }
} }
} }
final _nfcDevicesProvider =
StateNotifierProvider<NfcDeviceNotifier, List<NfcReaderNode>>((ref) {
final notifier = NfcDeviceNotifier(ref.watch(rpcProvider));
ref.listen<WindowState>(windowStateProvider, (_, windowState) {
notifier._notifyWindowState(windowState);
}, fireImmediately: true);
return notifier;
});
class NfcDeviceNotifier extends StateNotifier<List<NfcReaderNode>> {
final RpcSession _rpc;
Timer? _pollTimer;
String _nfcState = '';
NfcDeviceNotifier(this._rpc) : super([]);
void _notifyWindowState(WindowState windowState) {
if (windowState.active) {
_pollReaders();
} else {
_pollTimer?.cancel();
// Release any held device
_rpc.command('get', ['nfc']);
}
}
@override
void dispose() {
_pollTimer?.cancel();
super.dispose();
}
void _pollReaders() async {
_pollTimer?.cancel();
try {
var children = await _rpc.command('scan', ['nfc']);
var newState = children.keys.join(':');
if (mounted && newState != _nfcState) {
log.info('NFC state change', jsonEncode(children));
_nfcState = newState;
state = children.entries
.map((e) =>
DeviceNode.nfcReader(['nfc', e.key], e.value['name'] as String)
as NfcReaderNode)
.toList();
}
} on RpcError catch (e) {
log.severe('Error polling NFC', jsonEncode(e));
}
if (mounted) {
_pollTimer = Timer(const Duration(milliseconds: 2500), _pollReaders);
}
}
}
final attachedDevicesProvider = Provider<List<DeviceNode>>((ref) {
final usbDevices = ref.watch(_usbDevicesProvider).toList();
final nfcDevices = ref.watch(_nfcDevicesProvider).toList();
usbDevices.sort((a, b) => a.name.compareTo(b.name));
nfcDevices.sort((a, b) => a.name.compareTo(b.name));
return [...usbDevices, ...nfcDevices];
});
final currentDeviceProvider = final currentDeviceProvider =
StateNotifierProvider<CurrentDeviceNotifier, DeviceNode?>((ref) { StateNotifierProvider<CurrentDeviceNotifier, DeviceNode?>((ref) {
final provider = CurrentDeviceNotifier(ref.watch(prefProvider)); final provider = CurrentDeviceNotifier(ref.watch(prefProvider));
@ -188,42 +262,110 @@ final currentDeviceProvider =
}); });
class CurrentDeviceNotifier extends StateNotifier<DeviceNode?> { class CurrentDeviceNotifier extends StateNotifier<DeviceNode?> {
static const String _lastDeviceSerial = 'APP_STATE_LAST_SERIAL'; static const String _lastDevice = 'APP_STATE_LAST_DEVICE';
final SharedPreferences _prefs; final SharedPreferences _prefs;
CurrentDeviceNotifier(this._prefs) : super(null); CurrentDeviceNotifier(this._prefs) : super(null);
_updateAttachedDevices(List<DeviceNode>? previous, List<DeviceNode> devices) { _updateAttachedDevices(List<DeviceNode>? previous, List<DeviceNode> devices) {
if (devices.isEmpty) { if (!devices.contains(state)) {
state = null; final lastDevice = _prefs.getString(_lastDevice) ?? '';
} else if (!devices.contains(state)) { try {
// Prefer last selected device state = devices.firstWhere(
final serial = _prefs.getInt(_lastDeviceSerial) ?? -1; (dev) => dev.when(
state = devices.firstWhere( usbYubiKey: (path, name, pid, info) =>
(element) => element.info.serial == serial, lastDevice == 'serial:${info.serial}',
orElse: () => devices.first, nfcReader: (path, name) => lastDevice == 'name:$name',
); ),
orElse: () => devices.whereType<UsbYubiKeyNode>().first);
} on StateError {
state = null;
}
} }
} }
setCurrentDevice(DeviceNode device) { setCurrentDevice(DeviceNode device) {
state = device; state = device;
final serial = device.info.serial; device.when(
if (serial != null) { usbYubiKey: (path, name, pid, info) {
_prefs.setInt(_lastDeviceSerial, serial); final serial = info.serial;
} if (serial != null) {
_prefs.setString(_lastDevice, 'serial:$serial');
}
},
nfcReader: (path, name) {
_prefs.setString(_lastDevice, 'name:$name');
},
);
} }
} }
final sortedDevicesProvider = Provider<List<DeviceNode>>((ref) { final currentDeviceDataProvider =
final devices = ref.watch(attachedDevicesProvider).toList(); StateNotifierProvider<CurrentDeviceDataNotifier, YubiKeyData?>((ref) {
devices.sort((a, b) => a.name.compareTo(b.name)); final notifier = CurrentDeviceDataNotifier(
final device = ref.watch(currentDeviceProvider); ref.watch(rpcProvider),
if (device != null) { ref.watch(currentDeviceProvider),
return [device, ...devices.where((e) => e != device)]; );
if (notifier._deviceNode is NfcReaderNode) {
// If this is an NFC reader, listen on WindowState.
ref.listen<WindowState>(windowStateProvider, (_, windowState) {
notifier._notifyWindowState(windowState);
}, fireImmediately: true);
} }
return devices; return notifier;
}); });
class CurrentDeviceDataNotifier extends StateNotifier<YubiKeyData?> {
final RpcSession _rpc;
final DeviceNode? _deviceNode;
Timer? _pollTimer;
CurrentDeviceDataNotifier(this._rpc, this._deviceNode) : super(null) {
final dev = _deviceNode;
if (dev is UsbYubiKeyNode) {
state = YubiKeyData(dev, dev.name, dev.info);
}
}
void _notifyWindowState(WindowState windowState) {
if (windowState.active) {
_pollReader();
} else {
_pollTimer?.cancel();
// TODO: Should we clear the key here?
/*if (mounted) {
state = null;
}*/
}
}
@override
void dispose() {
_pollTimer?.cancel();
super.dispose();
}
void _pollReader() async {
_pollTimer?.cancel();
final node = _deviceNode!;
try {
var result = await _rpc.command('get', node.path);
if (mounted) {
if (result['data']['present']) {
state = YubiKeyData(node, result['data']['name'],
DeviceInfo.fromJson(result['data']['info']));
} else {
state = null;
}
}
} on RpcError catch (e) {
log.severe('Error polling NFC', jsonEncode(e));
}
if (mounted) {
_pollTimer = Timer(Duration(seconds: state == null ? 1 : 5), _pollReader);
}
}
}
final subPageProvider = StateNotifierProvider<SubPageNotifier, SubPage>( final subPageProvider = StateNotifierProvider<SubPageNotifier, SubPage>(
(ref) => SubPageNotifier(SubPage.authenticator)); (ref) => SubPageNotifier(SubPage.authenticator));

View File

@ -1,20 +1,25 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:yubico_authenticator/management/models.dart';
import '../models.dart'; import '../models.dart';
import 'device_images.dart'; import 'device_images.dart';
class DeviceAvatar extends StatelessWidget { class DeviceAvatar extends StatelessWidget {
final DeviceNode device; final DeviceNode node;
final String name;
final DeviceInfo? info;
final bool selected; final bool selected;
const DeviceAvatar(this.device, {this.selected = false, Key? key}) const DeviceAvatar(this.node, this.name, this.info,
{this.selected = false, Key? key})
: super(key: key); : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CircleAvatar( return CircleAvatar(
child: CircleAvatar( child: CircleAvatar(
child: getProductImage(device), child:
info != null ? getProductImage(info!, name) : const Icon(Icons.nfc),
backgroundColor: Theme.of(context).colorScheme.background, backgroundColor: Theme.of(context).colorScheme.background,
), ),
radius: 22, radius: 22,

View File

@ -30,11 +30,11 @@ const _imagesForFormFactorNfc = {
FormFactor.usbCKeychain: 'yk5cnfc', FormFactor.usbCKeychain: 'yk5cnfc',
}; };
Image getProductImage(DeviceNode device) { Image getProductImage(DeviceInfo info, String name) {
var image = _imagesForName[device.name]; var image = _imagesForName[name];
image ??= device.info.supportedCapabilities.containsKey(Transport.nfc) image ??= info.supportedCapabilities.containsKey(Transport.nfc)
? _imagesForFormFactorNfc[device.info.formFactor] ? _imagesForFormFactorNfc[info.formFactor]
: _imagesForFormFactor[device.info.formFactor]; : _imagesForFormFactor[info.formFactor];
image ??= 'yk5series'; image ??= 'yk5series';
return Image.asset('assets/product-images/$image.png'); return Image.asset('assets/product-images/$image.png');

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import '../models.dart'; import '../models.dart';
class DeviceInfoScreen extends StatelessWidget { class DeviceInfoScreen extends StatelessWidget {
final DeviceNode device; final YubiKeyData device;
const DeviceInfoScreen(this.device, {Key? key}) : super(key: key); const DeviceInfoScreen(this.device, {Key? key}) : super(key: key);
@override @override

View File

@ -1,32 +1,56 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:yubico_authenticator/management/models.dart';
import 'package:collection/collection.dart';
import '../models.dart'; import '../models.dart';
import '../state.dart'; import '../state.dart';
import 'device_avatar.dart'; import 'device_avatar.dart';
Function _listEquals = const ListEquality().equals;
class MainActionsDialog extends ConsumerWidget { class MainActionsDialog extends ConsumerWidget {
const MainActionsDialog({Key? key}) : super(key: key); const MainActionsDialog({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final devices = ref.watch(sortedDevicesProvider); final devices = ref.watch(attachedDevicesProvider).toList();
final device = ref.watch(currentDeviceProvider); final currentNode = ref.watch(currentDeviceProvider);
final data = ref.watch(currentDeviceDataProvider);
final actions = ref.watch(menuActionsProvider)(context); final actions = ref.watch(menuActionsProvider)(context);
//final nfcReaders = ref.watch(nfcDevicesProvider);
//final allDevices = devices + nfcReaders;
if (currentNode != null) {
devices.removeWhere((e) => _listEquals(e.path, currentNode.path));
}
return SimpleDialog( return SimpleDialog(
children: [ children: [
...devices.map((e) => Padding( if (currentNode != null)
padding: const EdgeInsets.all(8.0), CurrentDeviceRow(
child: DeviceRow( currentNode,
e, data?.name,
selected: e == device, info: data?.info,
onPressed: () { onTap: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
ref.read(currentDeviceProvider.notifier).setCurrentDevice(e); },
}, ),
), ...devices.map(
)), (e) => DeviceRow(
e,
e.name,
info: e.when(
usbYubiKey: (path, name, pid, info) => info,
nfcReader: (path, name) => null,
),
selected: false,
onTap: () {
Navigator.of(context).pop();
ref.read(currentDeviceProvider.notifier).setCurrentDevice(e);
},
),
),
if (actions.isNotEmpty) const Divider(), if (actions.isNotEmpty) const Divider(),
...actions.map((a) => ListTile( ...actions.map((a) => ListTile(
dense: true, dense: true,
@ -42,43 +66,74 @@ class MainActionsDialog extends ConsumerWidget {
} }
} }
class DeviceRow extends StatelessWidget { class CurrentDeviceRow extends StatelessWidget {
final DeviceNode device; final DeviceNode node;
final bool selected; final String? name;
final Function() onPressed; final DeviceInfo? info;
const DeviceRow( final Function() onTap;
this.device, {
this.selected = false, const CurrentDeviceRow(
required this.onPressed, this.node,
this.name, {
required this.info,
required this.onTap,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return TextButton( final subtitle = node is NfcReaderNode
onPressed: onPressed, ? info != null
child: Row( ? '${node.name}\nS/N: ${info!.serial} F/W: ${info!.version}'
children: [ : node.name
DeviceAvatar( : 'S/N: ${info!.serial} F/W: ${info!.version}';
device, return ListTile(
selected: selected, leading: DeviceAvatar(
), node,
const SizedBox(width: 16.0), name ?? '',
Column( info,
crossAxisAlignment: CrossAxisAlignment.start, selected: true,
children: [
Text(
device.name,
style: Theme.of(context).textTheme.headline6,
),
Text(
'S/N: ${device.info.serial} F/W: ${device.info.version}',
style: Theme.of(context).textTheme.bodyText1,
),
],
),
],
), ),
title: Text(name ?? 'No YubiKey present'),
isThreeLine: subtitle.contains('\n'),
subtitle: Text(subtitle),
onTap: onTap,
);
}
}
class DeviceRow extends StatelessWidget {
final DeviceNode node;
final String name;
final DeviceInfo? info;
final bool selected;
final Function() onTap;
const DeviceRow(
this.node,
this.name, {
required this.info,
required this.onTap,
this.selected = false,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
leading: DeviceAvatar(
node,
name,
info,
selected: selected,
),
title: Text(name),
subtitle: Text(
info == null
? (selected ? 'No YubiKey present' : 'Select to scan')
: 'S/N: ${info!.serial} F/W: ${info!.version}',
),
onTap: onTap,
); );
} }
} }

View File

@ -13,7 +13,7 @@ import '../../oath/views/oath_screen.dart';
class MainPage extends ConsumerWidget { class MainPage extends ConsumerWidget {
const MainPage({Key? key}) : super(key: key); const MainPage({Key? key}) : super(key: key);
Widget _buildSubPage(SubPage subPage, DeviceNode? device) { Widget _buildSubPage(SubPage subPage, YubiKeyData? device) {
if (device == null) { if (device == null) {
return const NoDeviceScreen(); return const NoDeviceScreen();
} }
@ -28,7 +28,7 @@ class MainPage extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final currentDevice = ref.watch(currentDeviceProvider); final currentDevice = ref.watch(currentDeviceDataProvider);
final subPage = ref.watch(subPageProvider); final subPage = ref.watch(subPageProvider);
return Scaffold( return Scaffold(
@ -67,7 +67,12 @@ class MainPage extends ConsumerWidget {
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.background,
), ),
) )
: DeviceAvatar(currentDevice, selected: true), : DeviceAvatar(
currentDevice.node,
currentDevice.name,
currentDevice.info,
selected: true,
),
), ),
onTap: () { onTap: () {
showDialog( showDialog(

View File

@ -1,5 +1,6 @@
// coverage:ignore-file // coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'models.dart'; part of 'models.dart';
@ -134,13 +135,17 @@ class _$_Version extends _Version {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _Version && other is _Version &&
(identical(other.major, major) || other.major == major) && const DeepCollectionEquality().equals(other.major, major) &&
(identical(other.minor, minor) || other.minor == minor) && const DeepCollectionEquality().equals(other.minor, minor) &&
(identical(other.patch, patch) || other.patch == patch)); const DeepCollectionEquality().equals(other.patch, patch));
} }
@override @override
int get hashCode => Object.hash(runtimeType, major, minor, patch); int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(major),
const DeepCollectionEquality().hash(minor),
const DeepCollectionEquality().hash(patch));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -516,13 +521,15 @@ class _$Signal implements Signal {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is Signal && other is Signal &&
(identical(other.status, status) || other.status == status) && const DeepCollectionEquality().equals(other.status, status) &&
const DeepCollectionEquality().equals(other.body, body)); const DeepCollectionEquality().equals(other.body, body));
} }
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, status, const DeepCollectionEquality().hash(body)); runtimeType,
const DeepCollectionEquality().hash(status),
const DeepCollectionEquality().hash(body));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -689,14 +696,17 @@ class _$RpcError implements RpcError {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is RpcError && other is RpcError &&
(identical(other.status, status) || other.status == status) && const DeepCollectionEquality().equals(other.status, status) &&
(identical(other.message, message) || other.message == message) && const DeepCollectionEquality().equals(other.message, message) &&
const DeepCollectionEquality().equals(other.body, body)); const DeepCollectionEquality().equals(other.body, body));
} }
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, status, message, const DeepCollectionEquality().hash(body)); runtimeType,
const DeepCollectionEquality().hash(status),
const DeepCollectionEquality().hash(message),
const DeepCollectionEquality().hash(body));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -896,11 +906,12 @@ class _$_RpcState implements _RpcState {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _RpcState && other is _RpcState &&
(identical(other.version, version) || other.version == version)); const DeepCollectionEquality().equals(other.version, version));
} }
@override @override
int get hashCode => Object.hash(runtimeType, version); int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(version));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override

View File

@ -1,5 +1,6 @@
// coverage:ignore-file // coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'models.dart'; part of 'models.dart';
@ -183,22 +184,21 @@ class _$_DeviceConfig implements _DeviceConfig {
other is _DeviceConfig && other is _DeviceConfig &&
const DeepCollectionEquality() const DeepCollectionEquality()
.equals(other.enabledCapabilities, enabledCapabilities) && .equals(other.enabledCapabilities, enabledCapabilities) &&
(identical(other.autoEjectTimeout, autoEjectTimeout) || const DeepCollectionEquality()
other.autoEjectTimeout == autoEjectTimeout) && .equals(other.autoEjectTimeout, autoEjectTimeout) &&
(identical( const DeepCollectionEquality().equals(
other.challengeResponseTimeout, challengeResponseTimeout) || other.challengeResponseTimeout, challengeResponseTimeout) &&
other.challengeResponseTimeout == challengeResponseTimeout) && const DeepCollectionEquality()
(identical(other.deviceFlags, deviceFlags) || .equals(other.deviceFlags, deviceFlags));
other.deviceFlags == deviceFlags));
} }
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, runtimeType,
const DeepCollectionEquality().hash(enabledCapabilities), const DeepCollectionEquality().hash(enabledCapabilities),
autoEjectTimeout, const DeepCollectionEquality().hash(autoEjectTimeout),
challengeResponseTimeout, const DeepCollectionEquality().hash(challengeResponseTimeout),
deviceFlags); const DeepCollectionEquality().hash(deviceFlags));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -495,30 +495,29 @@ class _$_DeviceInfo implements _DeviceInfo {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _DeviceInfo && other is _DeviceInfo &&
(identical(other.config, config) || other.config == config) && const DeepCollectionEquality().equals(other.config, config) &&
(identical(other.serial, serial) || other.serial == serial) && const DeepCollectionEquality().equals(other.serial, serial) &&
(identical(other.version, version) || other.version == version) && const DeepCollectionEquality().equals(other.version, version) &&
(identical(other.formFactor, formFactor) || const DeepCollectionEquality()
other.formFactor == formFactor) && .equals(other.formFactor, formFactor) &&
const DeepCollectionEquality() const DeepCollectionEquality()
.equals(other.supportedCapabilities, supportedCapabilities) && .equals(other.supportedCapabilities, supportedCapabilities) &&
(identical(other.isLocked, isLocked) || const DeepCollectionEquality().equals(other.isLocked, isLocked) &&
other.isLocked == isLocked) && const DeepCollectionEquality().equals(other.isFips, isFips) &&
(identical(other.isFips, isFips) || other.isFips == isFips) && const DeepCollectionEquality().equals(other.isSky, isSky));
(identical(other.isSky, isSky) || other.isSky == isSky));
} }
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, runtimeType,
config, const DeepCollectionEquality().hash(config),
serial, const DeepCollectionEquality().hash(serial),
version, const DeepCollectionEquality().hash(version),
formFactor, const DeepCollectionEquality().hash(formFactor),
const DeepCollectionEquality().hash(supportedCapabilities), const DeepCollectionEquality().hash(supportedCapabilities),
isLocked, const DeepCollectionEquality().hash(isLocked),
isFips, const DeepCollectionEquality().hash(isFips),
isSky); const DeepCollectionEquality().hash(isSky));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override

View File

@ -1,5 +1,6 @@
// coverage:ignore-file // coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'models.dart'; part of 'models.dart';
@ -230,21 +231,26 @@ class _$_OathCredential implements _OathCredential {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _OathCredential && other is _OathCredential &&
(identical(other.deviceId, deviceId) || const DeepCollectionEquality().equals(other.deviceId, deviceId) &&
other.deviceId == deviceId) && const DeepCollectionEquality().equals(other.id, id) &&
(identical(other.id, id) || other.id == id) && const DeepCollectionEquality().equals(other.issuer, issuer) &&
(identical(other.issuer, issuer) || other.issuer == issuer) && const DeepCollectionEquality().equals(other.name, name) &&
(identical(other.name, name) || other.name == name) && const DeepCollectionEquality().equals(other.oathType, oathType) &&
(identical(other.oathType, oathType) || const DeepCollectionEquality().equals(other.period, period) &&
other.oathType == oathType) && const DeepCollectionEquality()
(identical(other.period, period) || other.period == period) && .equals(other.touchRequired, touchRequired));
(identical(other.touchRequired, touchRequired) ||
other.touchRequired == touchRequired));
} }
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, deviceId, id, issuer, name, oathType, period, touchRequired); runtimeType,
const DeepCollectionEquality().hash(deviceId),
const DeepCollectionEquality().hash(id),
const DeepCollectionEquality().hash(issuer),
const DeepCollectionEquality().hash(name),
const DeepCollectionEquality().hash(oathType),
const DeepCollectionEquality().hash(period),
const DeepCollectionEquality().hash(touchRequired));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -429,14 +435,17 @@ class _$_OathCode implements _OathCode {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _OathCode && other is _OathCode &&
(identical(other.value, value) || other.value == value) && const DeepCollectionEquality().equals(other.value, value) &&
(identical(other.validFrom, validFrom) || const DeepCollectionEquality().equals(other.validFrom, validFrom) &&
other.validFrom == validFrom) && const DeepCollectionEquality().equals(other.validTo, validTo));
(identical(other.validTo, validTo) || other.validTo == validTo));
} }
@override @override
int get hashCode => Object.hash(runtimeType, value, validFrom, validTo); int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(value),
const DeepCollectionEquality().hash(validFrom),
const DeepCollectionEquality().hash(validTo));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -605,13 +614,16 @@ class _$_OathPair implements _OathPair {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _OathPair && other is _OathPair &&
(identical(other.credential, credential) || const DeepCollectionEquality()
other.credential == credential) && .equals(other.credential, credential) &&
(identical(other.code, code) || other.code == code)); const DeepCollectionEquality().equals(other.code, code));
} }
@override @override
int get hashCode => Object.hash(runtimeType, credential, code); int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(credential),
const DeepCollectionEquality().hash(code));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -772,14 +784,17 @@ class _$_OathState implements _OathState {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _OathState && other is _OathState &&
(identical(other.deviceId, deviceId) || const DeepCollectionEquality().equals(other.deviceId, deviceId) &&
other.deviceId == deviceId) && const DeepCollectionEquality().equals(other.hasKey, hasKey) &&
(identical(other.hasKey, hasKey) || other.hasKey == hasKey) && const DeepCollectionEquality().equals(other.locked, locked));
(identical(other.locked, locked) || other.locked == locked));
} }
@override @override
int get hashCode => Object.hash(runtimeType, deviceId, hasKey, locked); int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(deviceId),
const DeepCollectionEquality().hash(hasKey),
const DeepCollectionEquality().hash(locked));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@ -1037,19 +1052,19 @@ class _$_CredentialData extends _CredentialData {
final String name; final String name;
@override @override
final String secret; final String secret;
@JsonKey(defaultValue: OathType.totp) @JsonKey()
@override @override
final OathType oathType; final OathType oathType;
@JsonKey(defaultValue: HashAlgorithm.sha1) @JsonKey()
@override @override
final HashAlgorithm hashAlgorithm; final HashAlgorithm hashAlgorithm;
@JsonKey(defaultValue: 6) @JsonKey()
@override @override
final int digits; final int digits;
@JsonKey(defaultValue: 30) @JsonKey()
@override @override
final int period; final int period;
@JsonKey(defaultValue: 0) @JsonKey()
@override @override
final int counter; final int counter;
@ -1063,21 +1078,28 @@ class _$_CredentialData extends _CredentialData {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _CredentialData && other is _CredentialData &&
(identical(other.issuer, issuer) || other.issuer == issuer) && const DeepCollectionEquality().equals(other.issuer, issuer) &&
(identical(other.name, name) || other.name == name) && const DeepCollectionEquality().equals(other.name, name) &&
(identical(other.secret, secret) || other.secret == secret) && const DeepCollectionEquality().equals(other.secret, secret) &&
(identical(other.oathType, oathType) || const DeepCollectionEquality().equals(other.oathType, oathType) &&
other.oathType == oathType) && const DeepCollectionEquality()
(identical(other.hashAlgorithm, hashAlgorithm) || .equals(other.hashAlgorithm, hashAlgorithm) &&
other.hashAlgorithm == hashAlgorithm) && const DeepCollectionEquality().equals(other.digits, digits) &&
(identical(other.digits, digits) || other.digits == digits) && const DeepCollectionEquality().equals(other.period, period) &&
(identical(other.period, period) || other.period == period) && const DeepCollectionEquality().equals(other.counter, counter));
(identical(other.counter, counter) || other.counter == counter));
} }
@override @override
int get hashCode => Object.hash(runtimeType, issuer, name, secret, oathType, int get hashCode => Object.hash(
hashAlgorithm, digits, period, counter); runtimeType,
const DeepCollectionEquality().hash(issuer),
const DeepCollectionEquality().hash(name),
const DeepCollectionEquality().hash(secret),
const DeepCollectionEquality().hash(oathType),
const DeepCollectionEquality().hash(hashAlgorithm),
const DeepCollectionEquality().hash(digits),
const DeepCollectionEquality().hash(period),
const DeepCollectionEquality().hash(counter));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override

View File

@ -5,7 +5,7 @@ import '../models.dart';
import 'account_view.dart'; import 'account_view.dart';
class AccountList extends StatelessWidget { class AccountList extends StatelessWidget {
final DeviceNode device; final YubiKeyData device;
final List<OathPair> credentials; final List<OathPair> credentials;
final List<String> favorites; final List<String> favorites;
const AccountList(this.device, this.credentials, this.favorites, {Key? key}) const AccountList(this.device, this.credentials, this.favorites, {Key? key})

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../management/models.dart';
import '../../widgets/circle_timer.dart'; import '../../widgets/circle_timer.dart';
import '../../app/models.dart'; import '../../app/models.dart';
import '../models.dart'; import '../models.dart';
@ -35,7 +36,7 @@ class _ExpireNotifier extends StateNotifier<bool> {
} }
class AccountView extends ConsumerWidget { class AccountView extends ConsumerWidget {
final DeviceNode device; final YubiKeyData device;
final OathCredential credential; final OathCredential credential;
final OathCode? code; final OathCode? code;
const AccountView(this.device, this.credential, this.code, {Key? key}) const AccountView(this.device, this.credential, this.code, {Key? key})
@ -117,7 +118,7 @@ class AccountView extends ConsumerWidget {
} }
try { try {
await ref await ref
.read(credentialListProvider(device.path).notifier) .read(credentialListProvider(device.node.path).notifier)
.calculate(credential); .calculate(credential);
} finally { } finally {
close?.call(); close?.call();

View File

@ -6,12 +6,12 @@ import '../state.dart';
import 'account_list.dart'; import 'account_list.dart';
class OathScreen extends ConsumerWidget { class OathScreen extends ConsumerWidget {
final DeviceNode device; final YubiKeyData device;
const OathScreen(this.device, {Key? key}) : super(key: key); const OathScreen(this.device, {Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(oathStateProvider(device.path)); final state = ref.watch(oathStateProvider(device.node.path));
if (state == null) { if (state == null) {
return Column( return Column(
@ -35,7 +35,7 @@ class OathScreen extends ConsumerWidget {
decoration: const InputDecoration(labelText: 'Password'), decoration: const InputDecoration(labelText: 'Password'),
onSubmitted: (value) async { onSubmitted: (value) async {
final result = await ref final result = await ref
.read(oathStateProvider(device.path).notifier) .read(oathStateProvider(device.node.path).notifier)
.unlock(value); .unlock(value);
if (!result) { if (!result) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@ -51,7 +51,7 @@ class OathScreen extends ConsumerWidget {
), ),
); );
} else { } else {
final accounts = ref.watch(credentialListProvider(device.path)); final accounts = ref.watch(credentialListProvider(device.node.path));
if (accounts == null) { if (accounts == null) {
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,

View File

@ -323,7 +323,7 @@ packages:
name: material_color_utilities name: material_color_utilities
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.2" version: "0.1.3"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -615,7 +615,7 @@ packages:
name: window_manager name: window_manager
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.3" version: "0.1.4"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@ -41,7 +41,7 @@ dependencies:
flutter_riverpod: ^1.0.0 flutter_riverpod: ^1.0.0
json_annotation: ^4.3.0 json_annotation: ^4.3.0
freezed_annotation: ^1.0.0 freezed_annotation: ^1.0.0
window_manager: ^0.1.3 window_manager: ^0.1.4
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

@ -1 +1 @@
Subproject commit ab71cb6da0f19926400837d0b95fdde075830663 Subproject commit 765ccf63d9ccc972858d71730b9712514a9b0e0d