mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 18:22:39 +03:00
PIV: More slot information and ability to generate pubkey only
This commit is contained in:
parent
fd288c947b
commit
0a6eedcc99
@ -75,6 +75,7 @@ class InvalidPinException(RpcException):
|
||||
|
||||
@unique
|
||||
class GENERATE_TYPE(str, Enum):
|
||||
PUBLIC_KEY = "publicKey"
|
||||
CSR = "csr"
|
||||
CERTIFICATE = "certificate"
|
||||
|
||||
@ -304,7 +305,13 @@ def _get_cert_info(cert):
|
||||
not_before = cert.not_valid_before
|
||||
not_after = cert.not_valid_after
|
||||
|
||||
try:
|
||||
key_type = KEY_TYPE.from_public_key(cert.public_key())
|
||||
except ValueError:
|
||||
key_type = None
|
||||
|
||||
return dict(
|
||||
key_type=key_type,
|
||||
subject=cert.subject.rfc4514_string(),
|
||||
issuer=cert.issuer.rfc4514_string(),
|
||||
serial=hex(cert.serial_number)[2:],
|
||||
@ -348,7 +355,7 @@ class SlotsNode(RpcNode):
|
||||
f"{int(slot):02x}": dict(
|
||||
slot=int(slot),
|
||||
name=slot.name,
|
||||
has_key=metadata is not None if self._has_metadata else None,
|
||||
metadata=asdict(metadata) if metadata else None,
|
||||
cert_info=_get_cert_info(cert),
|
||||
)
|
||||
for slot, (metadata, cert) in self._slots.items()
|
||||
@ -450,6 +457,9 @@ class SlotNode(RpcNode):
|
||||
public_key = self.session.generate_key(
|
||||
self.slot, key_type, pin_policy, touch_policy
|
||||
)
|
||||
public_key_pem = public_key.public_bytes(
|
||||
encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo
|
||||
).decode()
|
||||
|
||||
if pin_policy != PIN_POLICY.NEVER:
|
||||
# TODO: Check if verified?
|
||||
@ -459,7 +469,9 @@ class SlotNode(RpcNode):
|
||||
if touch_policy in (TOUCH_POLICY.ALWAYS, TOUCH_POLICY.CACHED):
|
||||
signal("touch")
|
||||
|
||||
if generate_type == GENERATE_TYPE.CSR:
|
||||
if generate_type == GENERATE_TYPE.PUBLIC_KEY:
|
||||
result = public_key_pem
|
||||
elif generate_type == GENERATE_TYPE.CSR:
|
||||
csr = generate_csr(self.session, self.slot, public_key, subject)
|
||||
result = csr.public_bytes(encoding=Encoding.PEM).decode()
|
||||
elif generate_type == GENERATE_TYPE.CERTIFICATE:
|
||||
@ -479,13 +491,8 @@ class SlotNode(RpcNode):
|
||||
self.session.put_certificate(self.slot, cert)
|
||||
self.session.put_object(OBJECT_ID.CHUID, generate_chuid())
|
||||
else:
|
||||
raise ValueError("Unsupported GENERATE_TYPE")
|
||||
raise ValueError(f"Unsupported GENERATE_TYPE: {generate_type}")
|
||||
|
||||
self._refresh()
|
||||
|
||||
return dict(
|
||||
public_key=public_key.public_bytes(
|
||||
encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo
|
||||
).decode(),
|
||||
result=result,
|
||||
)
|
||||
return dict(public_key=public_key_pem, result=result)
|
||||
|
@ -334,6 +334,12 @@ class _DesktopPivSlotsNotifier extends PivSlotsNotifier {
|
||||
});
|
||||
|
||||
final (type, subject, validFrom, validTo) = parameters.when(
|
||||
publicKey: () => (
|
||||
GenerateType.publicKey,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
),
|
||||
certificate: (subject, validFrom, validTo) => (
|
||||
GenerateType.certificate,
|
||||
subject,
|
||||
|
@ -79,6 +79,7 @@
|
||||
"s_show_secret_key": null,
|
||||
"s_hide_secret_key": null,
|
||||
"s_private_key": null,
|
||||
"s_public_key": null,
|
||||
"s_invalid_length": "Ungültige Länge",
|
||||
"l_invalid_format_allowed_chars": null,
|
||||
"@l_invalid_format_allowed_chars": {
|
||||
@ -460,6 +461,7 @@
|
||||
"s_csr": null,
|
||||
"s_subject": null,
|
||||
"l_export_csr_file": null,
|
||||
"l_export_public_key_file": null,
|
||||
"l_select_import_file": null,
|
||||
"l_export_certificate": null,
|
||||
"l_export_certificate_file": null,
|
||||
|
@ -79,6 +79,7 @@
|
||||
"s_show_secret_key": "Show secret key",
|
||||
"s_hide_secret_key": "Hide secret key",
|
||||
"s_private_key": "Private key",
|
||||
"s_public_key": "Public key",
|
||||
"s_invalid_length": "Invalid length",
|
||||
"l_invalid_format_allowed_chars": "Invalid format, allowed characters: {characters}",
|
||||
"@l_invalid_format_allowed_chars": {
|
||||
@ -460,6 +461,7 @@
|
||||
"s_csr": "CSR",
|
||||
"s_subject": "Subject",
|
||||
"l_export_csr_file": "Save CSR to file",
|
||||
"l_export_public_key_file": "Save public key to file",
|
||||
"l_select_import_file": "Select file to import",
|
||||
"l_export_certificate": "Export certificate",
|
||||
"l_export_certificate_file": "Export certificate to file",
|
||||
|
@ -79,6 +79,7 @@
|
||||
"s_show_secret_key": null,
|
||||
"s_hide_secret_key": null,
|
||||
"s_private_key": "Clé privée",
|
||||
"s_public_key": null,
|
||||
"s_invalid_length": "Longueur invalide",
|
||||
"l_invalid_format_allowed_chars": null,
|
||||
"@l_invalid_format_allowed_chars": {
|
||||
@ -460,6 +461,7 @@
|
||||
"s_csr": "CSR",
|
||||
"s_subject": "Sujet",
|
||||
"l_export_csr_file": "Sauvegarder le CSR vers un fichier",
|
||||
"l_export_public_key_file": null,
|
||||
"l_select_import_file": "Sélectionnez un fichier à importer",
|
||||
"l_export_certificate": "Exporter le certificat",
|
||||
"l_export_certificate_file": "Exporter le certificat vers un fichier",
|
||||
|
@ -79,6 +79,7 @@
|
||||
"s_show_secret_key": null,
|
||||
"s_hide_secret_key": null,
|
||||
"s_private_key": "秘密鍵",
|
||||
"s_public_key": null,
|
||||
"s_invalid_length": "無効な長さです",
|
||||
"l_invalid_format_allowed_chars": null,
|
||||
"@l_invalid_format_allowed_chars": {
|
||||
@ -460,6 +461,7 @@
|
||||
"s_csr": "CSR",
|
||||
"s_subject": "サブジェクト",
|
||||
"l_export_csr_file": "CSRをファイルに保存",
|
||||
"l_export_public_key_file": null,
|
||||
"l_select_import_file": "インポートするファイルの選択",
|
||||
"l_export_certificate": "証明書をエクスポートする",
|
||||
"l_export_certificate_file": "証明書をファイルにエクスポートする",
|
||||
|
@ -79,6 +79,7 @@
|
||||
"s_show_secret_key": "Pokaż tajny klucz",
|
||||
"s_hide_secret_key": "Ukryj tajny klucz",
|
||||
"s_private_key": "Klucz prywatny",
|
||||
"s_public_key": null,
|
||||
"s_invalid_length": "Nieprawidłowa długość",
|
||||
"l_invalid_format_allowed_chars": "Nieprawidłowy format, dozwolone znaki: {characters}",
|
||||
"@l_invalid_format_allowed_chars": {
|
||||
@ -460,6 +461,7 @@
|
||||
"s_csr": "CSR",
|
||||
"s_subject": "Temat",
|
||||
"l_export_csr_file": "Zapisz CSR do pliku",
|
||||
"l_export_public_key_file": null,
|
||||
"l_select_import_file": "Wybierz plik do zaimportowania",
|
||||
"l_export_certificate": "Eksportuj certyfikat",
|
||||
"l_export_certificate_file": "Eksportuj certyfikat do pliku",
|
||||
|
@ -56,11 +56,14 @@ const appListItem9c = Key('$_prefix.9c.applistitem');
|
||||
const appListItem9d = Key('$_prefix.9d.applistitem');
|
||||
const appListItem9e = Key('$_prefix.9e.applistitem');
|
||||
|
||||
// CertInfo body keys
|
||||
// SlotMetadata body keys
|
||||
const slotMetadataKeyType = Key('$_prefix.slotMetadata.keyType');
|
||||
|
||||
const certInfoSubjectKey = Key('$_prefix.certInfo.subject');
|
||||
const certInfoIssuerKey = Key('$_prefix.certInfo.issuer');
|
||||
const certInfoSerialKey = Key('$_prefix.certInfo.serial');
|
||||
const certInfoFingerprintKey = Key('$_prefix.certInfo.fingerprint');
|
||||
const certInfoValidFromKey = Key('$_prefix.certInfo.validFrom');
|
||||
const certInfoValidToKey = Key('$_prefix.certInfo.validTo');
|
||||
// CertInfo body keys
|
||||
const certInfoKeyType = Key('$_prefix.certInfo.keyType');
|
||||
const certInfoSubject = Key('$_prefix.certInfo.subject');
|
||||
const certInfoIssuer = Key('$_prefix.certInfo.issuer');
|
||||
const certInfoSerial = Key('$_prefix.certInfo.serial');
|
||||
const certInfoFingerprint = Key('$_prefix.certInfo.fingerprint');
|
||||
const certInfoValidFrom = Key('$_prefix.certInfo.validFrom');
|
||||
const certInfoValidTo = Key('$_prefix.certInfo.validTo');
|
||||
|
@ -28,12 +28,13 @@ const defaultKeyType = KeyType.eccp256;
|
||||
const defaultGenerateType = GenerateType.certificate;
|
||||
|
||||
enum GenerateType {
|
||||
// TODO: Add "publicKey"? Needed for X25519
|
||||
publicKey,
|
||||
certificate,
|
||||
csr;
|
||||
|
||||
String getDisplayName(AppLocalizations l10n) {
|
||||
return switch (this) {
|
||||
GenerateType.publicKey => l10n.s_public_key,
|
||||
GenerateType.certificate => l10n.s_certificate,
|
||||
GenerateType.csr => l10n.s_csr,
|
||||
};
|
||||
@ -247,6 +248,7 @@ class PivState with _$PivState {
|
||||
@freezed
|
||||
class CertInfo with _$CertInfo {
|
||||
factory CertInfo({
|
||||
required KeyType? keyType,
|
||||
required String subject,
|
||||
required String issuer,
|
||||
required String serial,
|
||||
@ -263,7 +265,7 @@ class CertInfo with _$CertInfo {
|
||||
class PivSlot with _$PivSlot {
|
||||
factory PivSlot({
|
||||
required SlotId slot,
|
||||
bool? hasKey,
|
||||
SlotMetadata? metadata,
|
||||
CertInfo? certInfo,
|
||||
}) = _PivSlot;
|
||||
|
||||
@ -286,11 +288,14 @@ class PivExamineResult with _$PivExamineResult {
|
||||
|
||||
@freezed
|
||||
class PivGenerateParameters with _$PivGenerateParameters {
|
||||
factory PivGenerateParameters.publicKey() = _GeneratePublicKey;
|
||||
|
||||
factory PivGenerateParameters.certificate({
|
||||
required String subject,
|
||||
required DateTime validFrom,
|
||||
required DateTime validTo,
|
||||
}) = _GenerateCertificate;
|
||||
|
||||
factory PivGenerateParameters.csr({
|
||||
required String subject,
|
||||
}) = _GenerateCsr;
|
||||
@ -301,7 +306,7 @@ class PivGenerateResult with _$PivGenerateResult {
|
||||
factory PivGenerateResult({
|
||||
required GenerateType generateType,
|
||||
required String publicKey,
|
||||
required String result,
|
||||
String? result,
|
||||
}) = _PivGenerateResult;
|
||||
|
||||
factory PivGenerateResult.fromJson(Map<String, dynamic> json) =>
|
||||
|
@ -1431,6 +1431,7 @@ CertInfo _$CertInfoFromJson(Map<String, dynamic> json) {
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CertInfo {
|
||||
KeyType? get keyType => throw _privateConstructorUsedError;
|
||||
String get subject => throw _privateConstructorUsedError;
|
||||
String get issuer => throw _privateConstructorUsedError;
|
||||
String get serial => throw _privateConstructorUsedError;
|
||||
@ -1450,7 +1451,8 @@ abstract class $CertInfoCopyWith<$Res> {
|
||||
_$CertInfoCopyWithImpl<$Res, CertInfo>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String subject,
|
||||
{KeyType? keyType,
|
||||
String subject,
|
||||
String issuer,
|
||||
String serial,
|
||||
String notValidBefore,
|
||||
@ -1471,6 +1473,7 @@ class _$CertInfoCopyWithImpl<$Res, $Val extends CertInfo>
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? keyType = freezed,
|
||||
Object? subject = null,
|
||||
Object? issuer = null,
|
||||
Object? serial = null,
|
||||
@ -1479,6 +1482,10 @@ class _$CertInfoCopyWithImpl<$Res, $Val extends CertInfo>
|
||||
Object? fingerprint = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
keyType: freezed == keyType
|
||||
? _value.keyType
|
||||
: keyType // ignore: cast_nullable_to_non_nullable
|
||||
as KeyType?,
|
||||
subject: null == subject
|
||||
? _value.subject
|
||||
: subject // ignore: cast_nullable_to_non_nullable
|
||||
@ -1516,7 +1523,8 @@ abstract class _$$CertInfoImplCopyWith<$Res>
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String subject,
|
||||
{KeyType? keyType,
|
||||
String subject,
|
||||
String issuer,
|
||||
String serial,
|
||||
String notValidBefore,
|
||||
@ -1535,6 +1543,7 @@ class __$$CertInfoImplCopyWithImpl<$Res>
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? keyType = freezed,
|
||||
Object? subject = null,
|
||||
Object? issuer = null,
|
||||
Object? serial = null,
|
||||
@ -1543,6 +1552,10 @@ class __$$CertInfoImplCopyWithImpl<$Res>
|
||||
Object? fingerprint = null,
|
||||
}) {
|
||||
return _then(_$CertInfoImpl(
|
||||
keyType: freezed == keyType
|
||||
? _value.keyType
|
||||
: keyType // ignore: cast_nullable_to_non_nullable
|
||||
as KeyType?,
|
||||
subject: null == subject
|
||||
? _value.subject
|
||||
: subject // ignore: cast_nullable_to_non_nullable
|
||||
@ -1575,7 +1588,8 @@ class __$$CertInfoImplCopyWithImpl<$Res>
|
||||
@JsonSerializable()
|
||||
class _$CertInfoImpl implements _CertInfo {
|
||||
_$CertInfoImpl(
|
||||
{required this.subject,
|
||||
{required this.keyType,
|
||||
required this.subject,
|
||||
required this.issuer,
|
||||
required this.serial,
|
||||
required this.notValidBefore,
|
||||
@ -1585,6 +1599,8 @@ class _$CertInfoImpl implements _CertInfo {
|
||||
factory _$CertInfoImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$CertInfoImplFromJson(json);
|
||||
|
||||
@override
|
||||
final KeyType? keyType;
|
||||
@override
|
||||
final String subject;
|
||||
@override
|
||||
@ -1600,7 +1616,7 @@ class _$CertInfoImpl implements _CertInfo {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CertInfo(subject: $subject, issuer: $issuer, serial: $serial, notValidBefore: $notValidBefore, notValidAfter: $notValidAfter, fingerprint: $fingerprint)';
|
||||
return 'CertInfo(keyType: $keyType, subject: $subject, issuer: $issuer, serial: $serial, notValidBefore: $notValidBefore, notValidAfter: $notValidAfter, fingerprint: $fingerprint)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -1608,6 +1624,7 @@ class _$CertInfoImpl implements _CertInfo {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$CertInfoImpl &&
|
||||
(identical(other.keyType, keyType) || other.keyType == keyType) &&
|
||||
(identical(other.subject, subject) || other.subject == subject) &&
|
||||
(identical(other.issuer, issuer) || other.issuer == issuer) &&
|
||||
(identical(other.serial, serial) || other.serial == serial) &&
|
||||
@ -1621,7 +1638,7 @@ class _$CertInfoImpl implements _CertInfo {
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, subject, issuer, serial,
|
||||
int get hashCode => Object.hash(runtimeType, keyType, subject, issuer, serial,
|
||||
notValidBefore, notValidAfter, fingerprint);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@ -1640,7 +1657,8 @@ class _$CertInfoImpl implements _CertInfo {
|
||||
|
||||
abstract class _CertInfo implements CertInfo {
|
||||
factory _CertInfo(
|
||||
{required final String subject,
|
||||
{required final KeyType? keyType,
|
||||
required final String subject,
|
||||
required final String issuer,
|
||||
required final String serial,
|
||||
required final String notValidBefore,
|
||||
@ -1650,6 +1668,8 @@ abstract class _CertInfo implements CertInfo {
|
||||
factory _CertInfo.fromJson(Map<String, dynamic> json) =
|
||||
_$CertInfoImpl.fromJson;
|
||||
|
||||
@override
|
||||
KeyType? get keyType;
|
||||
@override
|
||||
String get subject;
|
||||
@override
|
||||
@ -1675,7 +1695,7 @@ PivSlot _$PivSlotFromJson(Map<String, dynamic> json) {
|
||||
/// @nodoc
|
||||
mixin _$PivSlot {
|
||||
SlotId get slot => throw _privateConstructorUsedError;
|
||||
bool? get hasKey => throw _privateConstructorUsedError;
|
||||
SlotMetadata? get metadata => throw _privateConstructorUsedError;
|
||||
CertInfo? get certInfo => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@ -1688,8 +1708,9 @@ abstract class $PivSlotCopyWith<$Res> {
|
||||
factory $PivSlotCopyWith(PivSlot value, $Res Function(PivSlot) then) =
|
||||
_$PivSlotCopyWithImpl<$Res, PivSlot>;
|
||||
@useResult
|
||||
$Res call({SlotId slot, bool? hasKey, CertInfo? certInfo});
|
||||
$Res call({SlotId slot, SlotMetadata? metadata, CertInfo? certInfo});
|
||||
|
||||
$SlotMetadataCopyWith<$Res>? get metadata;
|
||||
$CertInfoCopyWith<$Res>? get certInfo;
|
||||
}
|
||||
|
||||
@ -1707,7 +1728,7 @@ class _$PivSlotCopyWithImpl<$Res, $Val extends PivSlot>
|
||||
@override
|
||||
$Res call({
|
||||
Object? slot = null,
|
||||
Object? hasKey = freezed,
|
||||
Object? metadata = freezed,
|
||||
Object? certInfo = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
@ -1715,10 +1736,10 @@ class _$PivSlotCopyWithImpl<$Res, $Val extends PivSlot>
|
||||
? _value.slot
|
||||
: slot // ignore: cast_nullable_to_non_nullable
|
||||
as SlotId,
|
||||
hasKey: freezed == hasKey
|
||||
? _value.hasKey
|
||||
: hasKey // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
metadata: freezed == metadata
|
||||
? _value.metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
as SlotMetadata?,
|
||||
certInfo: freezed == certInfo
|
||||
? _value.certInfo
|
||||
: certInfo // ignore: cast_nullable_to_non_nullable
|
||||
@ -1726,6 +1747,18 @@ class _$PivSlotCopyWithImpl<$Res, $Val extends PivSlot>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SlotMetadataCopyWith<$Res>? get metadata {
|
||||
if (_value.metadata == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SlotMetadataCopyWith<$Res>(_value.metadata!, (value) {
|
||||
return _then(_value.copyWith(metadata: value) as $Val);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$CertInfoCopyWith<$Res>? get certInfo {
|
||||
@ -1746,8 +1779,10 @@ abstract class _$$PivSlotImplCopyWith<$Res> implements $PivSlotCopyWith<$Res> {
|
||||
__$$PivSlotImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({SlotId slot, bool? hasKey, CertInfo? certInfo});
|
||||
$Res call({SlotId slot, SlotMetadata? metadata, CertInfo? certInfo});
|
||||
|
||||
@override
|
||||
$SlotMetadataCopyWith<$Res>? get metadata;
|
||||
@override
|
||||
$CertInfoCopyWith<$Res>? get certInfo;
|
||||
}
|
||||
@ -1764,7 +1799,7 @@ class __$$PivSlotImplCopyWithImpl<$Res>
|
||||
@override
|
||||
$Res call({
|
||||
Object? slot = null,
|
||||
Object? hasKey = freezed,
|
||||
Object? metadata = freezed,
|
||||
Object? certInfo = freezed,
|
||||
}) {
|
||||
return _then(_$PivSlotImpl(
|
||||
@ -1772,10 +1807,10 @@ class __$$PivSlotImplCopyWithImpl<$Res>
|
||||
? _value.slot
|
||||
: slot // ignore: cast_nullable_to_non_nullable
|
||||
as SlotId,
|
||||
hasKey: freezed == hasKey
|
||||
? _value.hasKey
|
||||
: hasKey // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
metadata: freezed == metadata
|
||||
? _value.metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
as SlotMetadata?,
|
||||
certInfo: freezed == certInfo
|
||||
? _value.certInfo
|
||||
: certInfo // ignore: cast_nullable_to_non_nullable
|
||||
@ -1787,7 +1822,7 @@ class __$$PivSlotImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$PivSlotImpl implements _PivSlot {
|
||||
_$PivSlotImpl({required this.slot, this.hasKey, this.certInfo});
|
||||
_$PivSlotImpl({required this.slot, this.metadata, this.certInfo});
|
||||
|
||||
factory _$PivSlotImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$PivSlotImplFromJson(json);
|
||||
@ -1795,13 +1830,13 @@ class _$PivSlotImpl implements _PivSlot {
|
||||
@override
|
||||
final SlotId slot;
|
||||
@override
|
||||
final bool? hasKey;
|
||||
final SlotMetadata? metadata;
|
||||
@override
|
||||
final CertInfo? certInfo;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PivSlot(slot: $slot, hasKey: $hasKey, certInfo: $certInfo)';
|
||||
return 'PivSlot(slot: $slot, metadata: $metadata, certInfo: $certInfo)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -1810,14 +1845,15 @@ class _$PivSlotImpl implements _PivSlot {
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$PivSlotImpl &&
|
||||
(identical(other.slot, slot) || other.slot == slot) &&
|
||||
(identical(other.hasKey, hasKey) || other.hasKey == hasKey) &&
|
||||
(identical(other.metadata, metadata) ||
|
||||
other.metadata == metadata) &&
|
||||
(identical(other.certInfo, certInfo) ||
|
||||
other.certInfo == certInfo));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, slot, hasKey, certInfo);
|
||||
int get hashCode => Object.hash(runtimeType, slot, metadata, certInfo);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@ -1836,7 +1872,7 @@ class _$PivSlotImpl implements _PivSlot {
|
||||
abstract class _PivSlot implements PivSlot {
|
||||
factory _PivSlot(
|
||||
{required final SlotId slot,
|
||||
final bool? hasKey,
|
||||
final SlotMetadata? metadata,
|
||||
final CertInfo? certInfo}) = _$PivSlotImpl;
|
||||
|
||||
factory _PivSlot.fromJson(Map<String, dynamic> json) = _$PivSlotImpl.fromJson;
|
||||
@ -1844,7 +1880,7 @@ abstract class _PivSlot implements PivSlot {
|
||||
@override
|
||||
SlotId get slot;
|
||||
@override
|
||||
bool? get hasKey;
|
||||
SlotMetadata? get metadata;
|
||||
@override
|
||||
CertInfo? get certInfo;
|
||||
@override
|
||||
@ -2253,9 +2289,9 @@ abstract class _InvalidPassword implements PivExamineResult {
|
||||
|
||||
/// @nodoc
|
||||
mixin _$PivGenerateParameters {
|
||||
String get subject => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() publicKey,
|
||||
required TResult Function(
|
||||
String subject, DateTime validFrom, DateTime validTo)
|
||||
certificate,
|
||||
@ -2264,6 +2300,7 @@ mixin _$PivGenerateParameters {
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? publicKey,
|
||||
TResult? Function(String subject, DateTime validFrom, DateTime validTo)?
|
||||
certificate,
|
||||
TResult? Function(String subject)? csr,
|
||||
@ -2271,6 +2308,7 @@ mixin _$PivGenerateParameters {
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? publicKey,
|
||||
TResult Function(String subject, DateTime validFrom, DateTime validTo)?
|
||||
certificate,
|
||||
TResult Function(String subject)? csr,
|
||||
@ -2279,27 +2317,26 @@ mixin _$PivGenerateParameters {
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_GeneratePublicKey value) publicKey,
|
||||
required TResult Function(_GenerateCertificate value) certificate,
|
||||
required TResult Function(_GenerateCsr value) csr,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_GeneratePublicKey value)? publicKey,
|
||||
TResult? Function(_GenerateCertificate value)? certificate,
|
||||
TResult? Function(_GenerateCsr value)? csr,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_GeneratePublicKey value)? publicKey,
|
||||
TResult Function(_GenerateCertificate value)? certificate,
|
||||
TResult Function(_GenerateCsr value)? csr,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$PivGenerateParametersCopyWith<PivGenerateParameters> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -2307,8 +2344,6 @@ abstract class $PivGenerateParametersCopyWith<$Res> {
|
||||
factory $PivGenerateParametersCopyWith(PivGenerateParameters value,
|
||||
$Res Function(PivGenerateParameters) then) =
|
||||
_$PivGenerateParametersCopyWithImpl<$Res, PivGenerateParameters>;
|
||||
@useResult
|
||||
$Res call({String subject});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -2321,28 +2356,125 @@ class _$PivGenerateParametersCopyWithImpl<$Res,
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? subject = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
subject: null == subject
|
||||
? _value.subject
|
||||
: subject // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$GenerateCertificateImplCopyWith<$Res>
|
||||
implements $PivGenerateParametersCopyWith<$Res> {
|
||||
abstract class _$$GeneratePublicKeyImplCopyWith<$Res> {
|
||||
factory _$$GeneratePublicKeyImplCopyWith(_$GeneratePublicKeyImpl value,
|
||||
$Res Function(_$GeneratePublicKeyImpl) then) =
|
||||
__$$GeneratePublicKeyImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$GeneratePublicKeyImplCopyWithImpl<$Res>
|
||||
extends _$PivGenerateParametersCopyWithImpl<$Res, _$GeneratePublicKeyImpl>
|
||||
implements _$$GeneratePublicKeyImplCopyWith<$Res> {
|
||||
__$$GeneratePublicKeyImplCopyWithImpl(_$GeneratePublicKeyImpl _value,
|
||||
$Res Function(_$GeneratePublicKeyImpl) _then)
|
||||
: super(_value, _then);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$GeneratePublicKeyImpl implements _GeneratePublicKey {
|
||||
_$GeneratePublicKeyImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PivGenerateParameters.publicKey()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$GeneratePublicKeyImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() publicKey,
|
||||
required TResult Function(
|
||||
String subject, DateTime validFrom, DateTime validTo)
|
||||
certificate,
|
||||
required TResult Function(String subject) csr,
|
||||
}) {
|
||||
return publicKey();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? publicKey,
|
||||
TResult? Function(String subject, DateTime validFrom, DateTime validTo)?
|
||||
certificate,
|
||||
TResult? Function(String subject)? csr,
|
||||
}) {
|
||||
return publicKey?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? publicKey,
|
||||
TResult Function(String subject, DateTime validFrom, DateTime validTo)?
|
||||
certificate,
|
||||
TResult Function(String subject)? csr,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (publicKey != null) {
|
||||
return publicKey();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_GeneratePublicKey value) publicKey,
|
||||
required TResult Function(_GenerateCertificate value) certificate,
|
||||
required TResult Function(_GenerateCsr value) csr,
|
||||
}) {
|
||||
return publicKey(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_GeneratePublicKey value)? publicKey,
|
||||
TResult? Function(_GenerateCertificate value)? certificate,
|
||||
TResult? Function(_GenerateCsr value)? csr,
|
||||
}) {
|
||||
return publicKey?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_GeneratePublicKey value)? publicKey,
|
||||
TResult Function(_GenerateCertificate value)? certificate,
|
||||
TResult Function(_GenerateCsr value)? csr,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (publicKey != null) {
|
||||
return publicKey(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _GeneratePublicKey implements PivGenerateParameters {
|
||||
factory _GeneratePublicKey() = _$GeneratePublicKeyImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$GenerateCertificateImplCopyWith<$Res> {
|
||||
factory _$$GenerateCertificateImplCopyWith(_$GenerateCertificateImpl value,
|
||||
$Res Function(_$GenerateCertificateImpl) then) =
|
||||
__$$GenerateCertificateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String subject, DateTime validFrom, DateTime validTo});
|
||||
}
|
||||
@ -2421,6 +2553,7 @@ class _$GenerateCertificateImpl implements _GenerateCertificate {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() publicKey,
|
||||
required TResult Function(
|
||||
String subject, DateTime validFrom, DateTime validTo)
|
||||
certificate,
|
||||
@ -2432,6 +2565,7 @@ class _$GenerateCertificateImpl implements _GenerateCertificate {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? publicKey,
|
||||
TResult? Function(String subject, DateTime validFrom, DateTime validTo)?
|
||||
certificate,
|
||||
TResult? Function(String subject)? csr,
|
||||
@ -2442,6 +2576,7 @@ class _$GenerateCertificateImpl implements _GenerateCertificate {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? publicKey,
|
||||
TResult Function(String subject, DateTime validFrom, DateTime validTo)?
|
||||
certificate,
|
||||
TResult Function(String subject)? csr,
|
||||
@ -2456,6 +2591,7 @@ class _$GenerateCertificateImpl implements _GenerateCertificate {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_GeneratePublicKey value) publicKey,
|
||||
required TResult Function(_GenerateCertificate value) certificate,
|
||||
required TResult Function(_GenerateCsr value) csr,
|
||||
}) {
|
||||
@ -2465,6 +2601,7 @@ class _$GenerateCertificateImpl implements _GenerateCertificate {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_GeneratePublicKey value)? publicKey,
|
||||
TResult? Function(_GenerateCertificate value)? certificate,
|
||||
TResult? Function(_GenerateCsr value)? csr,
|
||||
}) {
|
||||
@ -2474,6 +2611,7 @@ class _$GenerateCertificateImpl implements _GenerateCertificate {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_GeneratePublicKey value)? publicKey,
|
||||
TResult Function(_GenerateCertificate value)? certificate,
|
||||
TResult Function(_GenerateCsr value)? csr,
|
||||
required TResult orElse(),
|
||||
@ -2491,23 +2629,19 @@ abstract class _GenerateCertificate implements PivGenerateParameters {
|
||||
required final DateTime validFrom,
|
||||
required final DateTime validTo}) = _$GenerateCertificateImpl;
|
||||
|
||||
@override
|
||||
String get subject;
|
||||
DateTime get validFrom;
|
||||
DateTime get validTo;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$GenerateCertificateImplCopyWith<_$GenerateCertificateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$GenerateCsrImplCopyWith<$Res>
|
||||
implements $PivGenerateParametersCopyWith<$Res> {
|
||||
abstract class _$$GenerateCsrImplCopyWith<$Res> {
|
||||
factory _$$GenerateCsrImplCopyWith(
|
||||
_$GenerateCsrImpl value, $Res Function(_$GenerateCsrImpl) then) =
|
||||
__$$GenerateCsrImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String subject});
|
||||
}
|
||||
@ -2567,6 +2701,7 @@ class _$GenerateCsrImpl implements _GenerateCsr {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() publicKey,
|
||||
required TResult Function(
|
||||
String subject, DateTime validFrom, DateTime validTo)
|
||||
certificate,
|
||||
@ -2578,6 +2713,7 @@ class _$GenerateCsrImpl implements _GenerateCsr {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? publicKey,
|
||||
TResult? Function(String subject, DateTime validFrom, DateTime validTo)?
|
||||
certificate,
|
||||
TResult? Function(String subject)? csr,
|
||||
@ -2588,6 +2724,7 @@ class _$GenerateCsrImpl implements _GenerateCsr {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? publicKey,
|
||||
TResult Function(String subject, DateTime validFrom, DateTime validTo)?
|
||||
certificate,
|
||||
TResult Function(String subject)? csr,
|
||||
@ -2602,6 +2739,7 @@ class _$GenerateCsrImpl implements _GenerateCsr {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_GeneratePublicKey value) publicKey,
|
||||
required TResult Function(_GenerateCertificate value) certificate,
|
||||
required TResult Function(_GenerateCsr value) csr,
|
||||
}) {
|
||||
@ -2611,6 +2749,7 @@ class _$GenerateCsrImpl implements _GenerateCsr {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_GeneratePublicKey value)? publicKey,
|
||||
TResult? Function(_GenerateCertificate value)? certificate,
|
||||
TResult? Function(_GenerateCsr value)? csr,
|
||||
}) {
|
||||
@ -2620,6 +2759,7 @@ class _$GenerateCsrImpl implements _GenerateCsr {
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_GeneratePublicKey value)? publicKey,
|
||||
TResult Function(_GenerateCertificate value)? certificate,
|
||||
TResult Function(_GenerateCsr value)? csr,
|
||||
required TResult orElse(),
|
||||
@ -2634,9 +2774,7 @@ class _$GenerateCsrImpl implements _GenerateCsr {
|
||||
abstract class _GenerateCsr implements PivGenerateParameters {
|
||||
factory _GenerateCsr({required final String subject}) = _$GenerateCsrImpl;
|
||||
|
||||
@override
|
||||
String get subject;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$GenerateCsrImplCopyWith<_$GenerateCsrImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
@ -2650,7 +2788,7 @@ PivGenerateResult _$PivGenerateResultFromJson(Map<String, dynamic> json) {
|
||||
mixin _$PivGenerateResult {
|
||||
GenerateType get generateType => throw _privateConstructorUsedError;
|
||||
String get publicKey => throw _privateConstructorUsedError;
|
||||
String get result => throw _privateConstructorUsedError;
|
||||
String? get result => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
@ -2664,7 +2802,7 @@ abstract class $PivGenerateResultCopyWith<$Res> {
|
||||
PivGenerateResult value, $Res Function(PivGenerateResult) then) =
|
||||
_$PivGenerateResultCopyWithImpl<$Res, PivGenerateResult>;
|
||||
@useResult
|
||||
$Res call({GenerateType generateType, String publicKey, String result});
|
||||
$Res call({GenerateType generateType, String publicKey, String? result});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -2682,7 +2820,7 @@ class _$PivGenerateResultCopyWithImpl<$Res, $Val extends PivGenerateResult>
|
||||
$Res call({
|
||||
Object? generateType = null,
|
||||
Object? publicKey = null,
|
||||
Object? result = null,
|
||||
Object? result = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
generateType: null == generateType
|
||||
@ -2693,10 +2831,10 @@ class _$PivGenerateResultCopyWithImpl<$Res, $Val extends PivGenerateResult>
|
||||
? _value.publicKey
|
||||
: publicKey // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
result: null == result
|
||||
result: freezed == result
|
||||
? _value.result
|
||||
: result // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
as String?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@ -2709,7 +2847,7 @@ abstract class _$$PivGenerateResultImplCopyWith<$Res>
|
||||
__$$PivGenerateResultImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({GenerateType generateType, String publicKey, String result});
|
||||
$Res call({GenerateType generateType, String publicKey, String? result});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -2725,7 +2863,7 @@ class __$$PivGenerateResultImplCopyWithImpl<$Res>
|
||||
$Res call({
|
||||
Object? generateType = null,
|
||||
Object? publicKey = null,
|
||||
Object? result = null,
|
||||
Object? result = freezed,
|
||||
}) {
|
||||
return _then(_$PivGenerateResultImpl(
|
||||
generateType: null == generateType
|
||||
@ -2736,10 +2874,10 @@ class __$$PivGenerateResultImplCopyWithImpl<$Res>
|
||||
? _value.publicKey
|
||||
: publicKey // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
result: null == result
|
||||
result: freezed == result
|
||||
? _value.result
|
||||
: result // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -2748,9 +2886,7 @@ class __$$PivGenerateResultImplCopyWithImpl<$Res>
|
||||
@JsonSerializable()
|
||||
class _$PivGenerateResultImpl implements _PivGenerateResult {
|
||||
_$PivGenerateResultImpl(
|
||||
{required this.generateType,
|
||||
required this.publicKey,
|
||||
required this.result});
|
||||
{required this.generateType, required this.publicKey, this.result});
|
||||
|
||||
factory _$PivGenerateResultImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$PivGenerateResultImplFromJson(json);
|
||||
@ -2760,7 +2896,7 @@ class _$PivGenerateResultImpl implements _PivGenerateResult {
|
||||
@override
|
||||
final String publicKey;
|
||||
@override
|
||||
final String result;
|
||||
final String? result;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@ -2802,7 +2938,7 @@ abstract class _PivGenerateResult implements PivGenerateResult {
|
||||
factory _PivGenerateResult(
|
||||
{required final GenerateType generateType,
|
||||
required final String publicKey,
|
||||
required final String result}) = _$PivGenerateResultImpl;
|
||||
final String? result}) = _$PivGenerateResultImpl;
|
||||
|
||||
factory _PivGenerateResult.fromJson(Map<String, dynamic> json) =
|
||||
_$PivGenerateResultImpl.fromJson;
|
||||
@ -2812,7 +2948,7 @@ abstract class _PivGenerateResult implements PivGenerateResult {
|
||||
@override
|
||||
String get publicKey;
|
||||
@override
|
||||
String get result;
|
||||
String? get result;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$PivGenerateResultImplCopyWith<_$PivGenerateResultImpl> get copyWith =>
|
||||
|
@ -133,6 +133,7 @@ Map<String, dynamic> _$$PivStateImplToJson(_$PivStateImpl instance) =>
|
||||
|
||||
_$CertInfoImpl _$$CertInfoImplFromJson(Map<String, dynamic> json) =>
|
||||
_$CertInfoImpl(
|
||||
keyType: $enumDecodeNullable(_$KeyTypeEnumMap, json['key_type']),
|
||||
subject: json['subject'] as String,
|
||||
issuer: json['issuer'] as String,
|
||||
serial: json['serial'] as String,
|
||||
@ -143,6 +144,7 @@ _$CertInfoImpl _$$CertInfoImplFromJson(Map<String, dynamic> json) =>
|
||||
|
||||
Map<String, dynamic> _$$CertInfoImplToJson(_$CertInfoImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'key_type': _$KeyTypeEnumMap[instance.keyType],
|
||||
'subject': instance.subject,
|
||||
'issuer': instance.issuer,
|
||||
'serial': instance.serial,
|
||||
@ -154,7 +156,9 @@ Map<String, dynamic> _$$CertInfoImplToJson(_$CertInfoImpl instance) =>
|
||||
_$PivSlotImpl _$$PivSlotImplFromJson(Map<String, dynamic> json) =>
|
||||
_$PivSlotImpl(
|
||||
slot: SlotId.fromJson(json['slot'] as int),
|
||||
hasKey: json['has_key'] as bool?,
|
||||
metadata: json['metadata'] == null
|
||||
? null
|
||||
: SlotMetadata.fromJson(json['metadata'] as Map<String, dynamic>),
|
||||
certInfo: json['cert_info'] == null
|
||||
? null
|
||||
: CertInfo.fromJson(json['cert_info'] as Map<String, dynamic>),
|
||||
@ -163,7 +167,7 @@ _$PivSlotImpl _$$PivSlotImplFromJson(Map<String, dynamic> json) =>
|
||||
Map<String, dynamic> _$$PivSlotImplToJson(_$PivSlotImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'slot': _$SlotIdEnumMap[instance.slot]!,
|
||||
'has_key': instance.hasKey,
|
||||
'metadata': instance.metadata,
|
||||
'cert_info': instance.certInfo,
|
||||
};
|
||||
|
||||
@ -209,7 +213,7 @@ _$PivGenerateResultImpl _$$PivGenerateResultImplFromJson(
|
||||
_$PivGenerateResultImpl(
|
||||
generateType: $enumDecode(_$GenerateTypeEnumMap, json['generate_type']),
|
||||
publicKey: json['public_key'] as String,
|
||||
result: json['result'] as String,
|
||||
result: json['result'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$PivGenerateResultImplToJson(
|
||||
@ -221,6 +225,7 @@ Map<String, dynamic> _$$PivGenerateResultImplToJson(
|
||||
};
|
||||
|
||||
const _$GenerateTypeEnumMap = {
|
||||
GenerateType.publicKey: 'publicKey',
|
||||
GenerateType.certificate: 'certificate',
|
||||
GenerateType.csr: 'csr',
|
||||
};
|
||||
|
@ -123,21 +123,33 @@ class PivActions extends ConsumerWidget {
|
||||
),
|
||||
);
|
||||
|
||||
switch (result?.generateType) {
|
||||
case GenerateType.csr:
|
||||
if (result != null) {
|
||||
final (fileExt, title, data) = switch (result.generateType) {
|
||||
GenerateType.publicKey => (
|
||||
'pem',
|
||||
l10n.l_export_public_key_file,
|
||||
result.publicKey,
|
||||
),
|
||||
GenerateType.csr => (
|
||||
'csr',
|
||||
l10n.l_export_csr_file,
|
||||
result.result,
|
||||
),
|
||||
_ => (null, null, null),
|
||||
};
|
||||
|
||||
if (fileExt != null) {
|
||||
final filePath = await FilePicker.platform.saveFile(
|
||||
dialogTitle: l10n.l_export_csr_file,
|
||||
allowedExtensions: ['csr'],
|
||||
dialogTitle: title,
|
||||
allowedExtensions: [fileExt],
|
||||
type: FileType.custom,
|
||||
lockParentWindow: true,
|
||||
);
|
||||
if (filePath != null) {
|
||||
final file = File(filePath);
|
||||
await file.writeAsString(result!.result, flush: true);
|
||||
await file.writeAsString(data!, flush: true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result != null;
|
||||
@ -250,165 +262,6 @@ class PivActions extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Widget registerPivActions(
|
||||
DevicePath devicePath,
|
||||
PivState pivState, {
|
||||
required WidgetRef ref,
|
||||
required Widget Function(BuildContext context) builder,
|
||||
Map<Type, Action<Intent>> actions = const {},
|
||||
}) {
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
return Actions(
|
||||
actions: {
|
||||
if (hasFeature(features.slotsGenerate))
|
||||
GenerateIntent:
|
||||
CallbackAction<GenerateIntent>(onInvoke: (intent) async {
|
||||
final withContext = ref.read(withContextProvider);
|
||||
if (!pivState.protectedKey &&
|
||||
!await withContext(
|
||||
(context) => _authIfNeeded(context, devicePath, pivState))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Avoid asking for PIN if not needed?
|
||||
final verified = await withContext((context) async =>
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) => PinDialog(devicePath))) ??
|
||||
false;
|
||||
|
||||
if (!verified) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await withContext((context) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final PivGenerateResult? result = await showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) => GenerateKeyDialog(
|
||||
devicePath,
|
||||
pivState,
|
||||
intent.slot,
|
||||
),
|
||||
);
|
||||
|
||||
switch (result?.generateType) {
|
||||
case GenerateType.csr:
|
||||
final filePath = await FilePicker.platform.saveFile(
|
||||
dialogTitle: l10n.l_export_csr_file,
|
||||
allowedExtensions: ['csr'],
|
||||
type: FileType.custom,
|
||||
lockParentWindow: true,
|
||||
);
|
||||
if (filePath != null) {
|
||||
final file = File(filePath);
|
||||
await file.writeAsString(result!.result, flush: true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result != null;
|
||||
});
|
||||
}),
|
||||
if (hasFeature(features.slotsImport))
|
||||
ImportIntent: CallbackAction<ImportIntent>(onInvoke: (intent) async {
|
||||
final withContext = ref.read(withContextProvider);
|
||||
|
||||
if (!await withContext(
|
||||
(context) => _authIfNeeded(context, devicePath, pivState))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final picked = await withContext(
|
||||
(context) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return await FilePicker.platform.pickFiles(
|
||||
allowedExtensions: ['pem', 'der', 'pfx', 'p12', 'key', 'crt'],
|
||||
type: FileType.custom,
|
||||
allowMultiple: false,
|
||||
lockParentWindow: true,
|
||||
dialogTitle: l10n.l_select_import_file);
|
||||
},
|
||||
);
|
||||
if (picked == null || picked.files.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await withContext((context) async =>
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) => ImportFileDialog(
|
||||
devicePath,
|
||||
pivState,
|
||||
intent.slot,
|
||||
File(picked.paths.first!),
|
||||
),
|
||||
) ??
|
||||
false);
|
||||
}),
|
||||
if (hasFeature(features.slotsExport))
|
||||
ExportIntent: CallbackAction<ExportIntent>(onInvoke: (intent) async {
|
||||
final (_, cert) = await ref
|
||||
.read(pivSlotsProvider(devicePath).notifier)
|
||||
.read(intent.slot.slot);
|
||||
|
||||
if (cert == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final withContext = ref.read(withContextProvider);
|
||||
|
||||
final filePath = await withContext((context) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return await FilePicker.platform.saveFile(
|
||||
dialogTitle: l10n.l_export_certificate_file,
|
||||
allowedExtensions: ['pem'],
|
||||
type: FileType.custom,
|
||||
lockParentWindow: true,
|
||||
);
|
||||
});
|
||||
|
||||
if (filePath == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final file = File(filePath);
|
||||
await file.writeAsString(cert, flush: true);
|
||||
|
||||
await withContext((context) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
showMessage(context, l10n.l_certificate_exported);
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
if (hasFeature(features.slotsDelete))
|
||||
DeleteIntent<PivSlot>:
|
||||
CallbackAction<DeleteIntent<PivSlot>>(onInvoke: (intent) async {
|
||||
final withContext = ref.read(withContextProvider);
|
||||
if (!await withContext(
|
||||
(context) => _authIfNeeded(context, devicePath, pivState))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final bool? deleted = await withContext((context) async =>
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) => DeleteCertificateDialog(
|
||||
devicePath,
|
||||
intent.target,
|
||||
),
|
||||
) ??
|
||||
false);
|
||||
return deleted;
|
||||
}),
|
||||
...actions,
|
||||
},
|
||||
child: Builder(builder: builder),
|
||||
);
|
||||
}
|
||||
|
||||
List<ActionItem> buildSlotActions(PivSlot slot, AppLocalizations l10n) {
|
||||
final hasCert = slot.certInfo != null;
|
||||
return [
|
||||
|
@ -22,13 +22,13 @@ import 'package:intl/intl.dart';
|
||||
import '../../app/message.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../widgets/tooltip_if_truncated.dart';
|
||||
import '../keys.dart';
|
||||
import '../keys.dart' as keys;
|
||||
import '../models.dart';
|
||||
|
||||
class CertInfoTable extends ConsumerWidget {
|
||||
final CertInfo certInfo;
|
||||
class _InfoTable extends ConsumerWidget {
|
||||
final Map<String, (String, Key)> values;
|
||||
|
||||
const CertInfoTable(this.certInfo, {super.key});
|
||||
const _InfoTable(this.values);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@ -38,22 +38,36 @@ class CertInfoTable extends ConsumerWidget {
|
||||
final subtitleStyle = textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
);
|
||||
final dateFormat =
|
||||
DateFormat.yMMMEd(ref.watch(currentLocaleProvider).toString());
|
||||
final clipboard = ref.watch(clipboardProvider);
|
||||
final withContext = ref.watch(withContextProvider);
|
||||
|
||||
Widget header(String title) => Text(
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: values.keys
|
||||
.map((title) => Text(
|
||||
title,
|
||||
textAlign: TextAlign.right,
|
||||
);
|
||||
|
||||
Widget body(String title, String value, Key key) => GestureDetector(
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: values.entries.map((e) {
|
||||
final title = e.key;
|
||||
final (value, key) = e.value;
|
||||
return GestureDetector(
|
||||
onDoubleTap: () async {
|
||||
await clipboard.setText(value);
|
||||
if (!clipboard.platformGivesFeedback()) {
|
||||
await withContext((context) async {
|
||||
showMessage(context, l10n.p_target_copied_clipboard(title));
|
||||
showMessage(
|
||||
context, l10n.p_target_copied_clipboard(title));
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -65,43 +79,55 @@ class CertInfoTable extends ConsumerWidget {
|
||||
RegExp(r',([A-Z]+)='), (match) => '\n${match[1]}='),
|
||||
),
|
||||
);
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
header(l10n.s_subject),
|
||||
header(l10n.s_issuer),
|
||||
header(l10n.s_serial),
|
||||
header(l10n.s_certificate_fingerprint),
|
||||
header(l10n.s_valid_from),
|
||||
header(l10n.s_valid_to),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
body(l10n.s_subject, certInfo.subject, certInfoSubjectKey),
|
||||
body(l10n.s_issuer, certInfo.issuer, certInfoIssuerKey),
|
||||
body(l10n.s_serial, certInfo.serial, certInfoSerialKey),
|
||||
body(l10n.s_certificate_fingerprint, certInfo.fingerprint,
|
||||
certInfoFingerprintKey),
|
||||
body(
|
||||
l10n.s_valid_from,
|
||||
dateFormat.format(DateTime.parse(certInfo.notValidBefore)),
|
||||
certInfoValidFromKey),
|
||||
body(
|
||||
l10n.s_valid_to,
|
||||
dateFormat.format(DateTime.parse(certInfo.notValidAfter)),
|
||||
certInfoValidToKey),
|
||||
],
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CertInfoTable extends ConsumerWidget {
|
||||
final CertInfo? certInfo;
|
||||
final SlotMetadata? metadata;
|
||||
|
||||
const CertInfoTable(this.certInfo, this.metadata, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final dateFormat =
|
||||
DateFormat.yMMMEd(ref.watch(currentLocaleProvider).toString());
|
||||
|
||||
final certInfo = this.certInfo;
|
||||
final metadata = this.metadata;
|
||||
return _InfoTable({
|
||||
if (metadata != null)
|
||||
l10n.s_private_key: (
|
||||
metadata.keyType.getDisplayName(l10n),
|
||||
keys.slotMetadataKeyType
|
||||
),
|
||||
if (certInfo != null) ...{
|
||||
l10n.s_public_key: (
|
||||
certInfo.keyType?.getDisplayName(l10n) ?? l10n.s_unknown_type,
|
||||
keys.certInfoKeyType
|
||||
),
|
||||
l10n.s_subject: (certInfo.subject, keys.certInfoSubject),
|
||||
l10n.s_issuer: (certInfo.issuer, keys.certInfoIssuer),
|
||||
l10n.s_serial: (certInfo.serial, keys.certInfoSerial),
|
||||
l10n.s_certificate_fingerprint: (
|
||||
certInfo.fingerprint,
|
||||
keys.certInfoFingerprint
|
||||
),
|
||||
l10n.s_valid_from: (
|
||||
dateFormat.format(DateTime.parse(certInfo.notValidBefore)),
|
||||
keys.certInfoValidFrom
|
||||
),
|
||||
l10n.s_valid_to: (
|
||||
dateFormat.format(DateTime.parse(certInfo.notValidAfter)),
|
||||
keys.certInfoValidTo
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -65,13 +65,14 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
_validToMax = DateTime.utc(now.year + 10, now.month, now.day);
|
||||
}
|
||||
|
||||
List<KeyType> _getSupportedKeyTypes() => [
|
||||
KeyType.rsa1024,
|
||||
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,
|
||||
@ -86,15 +87,20 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
);
|
||||
|
||||
final isFips =
|
||||
ref.watch(currentDeviceDataProvider).valueOrNull?.info.isFips ?? false;
|
||||
|
||||
final canSave = !_generating &&
|
||||
(!_invalidSubject || _generateType == GenerateType.publicKey);
|
||||
|
||||
return ResponsiveDialog(
|
||||
allowCancel: !_generating,
|
||||
title: Text(l10n.s_generate_key),
|
||||
actions: [
|
||||
TextButton(
|
||||
key: keys.saveButton,
|
||||
onPressed: _generating || _invalidSubject
|
||||
? null
|
||||
: () async {
|
||||
onPressed: canSave
|
||||
? () async {
|
||||
if (!await confirmOverwrite(
|
||||
context,
|
||||
widget.pivSlot,
|
||||
@ -111,11 +117,12 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
final pivNotifier =
|
||||
ref.read(pivSlotsProvider(widget.devicePath).notifier);
|
||||
|
||||
if (!await pivNotifier.validateRfc4514(_subject)) {
|
||||
if (!(_generateType == GenerateType.publicKey ||
|
||||
await pivNotifier.validateRfc4514(_subject))) {
|
||||
setState(() {
|
||||
_generating = false;
|
||||
});
|
||||
_invalidSubject = true;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -123,6 +130,8 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
widget.pivSlot.slot,
|
||||
_keyType,
|
||||
parameters: switch (_generateType) {
|
||||
GenerateType.publicKey =>
|
||||
PivGenerateParameters.publicKey(),
|
||||
GenerateType.certificate =>
|
||||
PivGenerateParameters.certificate(
|
||||
subject: _subject,
|
||||
@ -142,7 +151,8 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
}
|
||||
: null,
|
||||
child: Text(l10n.s_save),
|
||||
),
|
||||
],
|
||||
@ -169,7 +179,7 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
: null,
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
enabled: !_generating,
|
||||
enabled: !_generating && _generateType != GenerateType.publicKey,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_invalidSubject = value.isEmpty;
|
||||
@ -192,7 +202,7 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
runSpacing: 8.0,
|
||||
children: [
|
||||
ChoiceFilterChip<KeyType>(
|
||||
items: _getSupportedKeyTypes(),
|
||||
items: _getSupportedKeyTypes(isFips),
|
||||
value: _keyType,
|
||||
selected: _keyType != defaultKeyType,
|
||||
itemBuilder: (value) => Text(value.getDisplayName(l10n)),
|
||||
@ -201,6 +211,9 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
: (value) {
|
||||
setState(() {
|
||||
_keyType = value;
|
||||
if (value == KeyType.x25519) {
|
||||
_generateType = GenerateType.publicKey;
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
@ -209,7 +222,7 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
value: _generateType,
|
||||
selected: _generateType != defaultGenerateType,
|
||||
itemBuilder: (value) => Text(value.getDisplayName(l10n)),
|
||||
onChanged: _generating
|
||||
onChanged: _generating || _keyType == KeyType.x25519
|
||||
? null
|
||||
: (value) {
|
||||
setState(() {
|
||||
|
@ -256,7 +256,7 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
),
|
||||
SizedBox(
|
||||
height: 120, // Needed for layout, adapt if text sizes changes
|
||||
child: CertInfoTable(certInfo),
|
||||
child: CertInfoTable(certInfo, null),
|
||||
),
|
||||
]
|
||||
]
|
||||
|
@ -68,7 +68,7 @@ Future<bool> confirmOverwrite(
|
||||
required bool writeCert,
|
||||
}) async {
|
||||
final overwritesCert = writeCert && pivSlot.certInfo != null;
|
||||
final overwritesKey = writeKey ? pivSlot.hasKey : false;
|
||||
final overwritesKey = writeKey ? pivSlot.metadata != null : false;
|
||||
if (overwritesCert || overwritesKey != false) {
|
||||
return await showBlurDialog(
|
||||
context: context,
|
||||
|
@ -128,9 +128,14 @@ class _PivScreenState extends ConsumerState<PivScreen> {
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
selected.certInfo != null
|
||||
? CertInfoTable(selected.certInfo!)
|
||||
: Text(
|
||||
if (selected.certInfo != null ||
|
||||
selected.metadata != null) ...[
|
||||
CertInfoTable(selected.certInfo,
|
||||
selected.metadata),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
if (selected.certInfo == null)
|
||||
Text(
|
||||
l10n.l_no_certificate,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
@ -225,7 +230,7 @@ class _CertificateListItem extends ConsumerWidget {
|
||||
subtitle: certInfo != null
|
||||
// Simplify subtitle by stripping "CN=", etc.
|
||||
? certInfo.subject.replaceAll(RegExp(r'[A-Z]+='), ' ').trimLeft()
|
||||
: pivSlot.hasKey == true
|
||||
: pivSlot.metadata != null
|
||||
? l10n.l_key_no_certificate
|
||||
: l10n.l_no_certificate,
|
||||
trailing: expanded
|
||||
|
@ -59,6 +59,7 @@ class SlotDialog extends ConsumerWidget {
|
||||
}
|
||||
|
||||
final certInfo = slotData.certInfo;
|
||||
final metadata = slotData.metadata;
|
||||
return PivActions(
|
||||
devicePath: node.path,
|
||||
pivState: pivState,
|
||||
@ -79,14 +80,19 @@ class SlotDialog extends ConsumerWidget {
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (certInfo != null) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: CertInfoTable(certInfo),
|
||||
),
|
||||
] else ...[
|
||||
child: Column(
|
||||
children: [
|
||||
if (certInfo != null || metadata != null) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: CertInfoTable(certInfo, metadata),
|
||||
),
|
||||
],
|
||||
if (certInfo == null) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Text(
|
||||
l10n.l_no_certificate,
|
||||
softWrap: true,
|
||||
@ -94,11 +100,14 @@ class SlotDialog extends ConsumerWidget {
|
||||
style: subtitleStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
ActionListSection.fromMenuActions(
|
||||
context,
|
||||
l10n.s_actions,
|
||||
|
Loading…
Reference in New Issue
Block a user