mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-22 00:12:09 +03:00
Merge branch 'main' into dain/restricted-nfc
This commit is contained in:
commit
bba92b8b54
11
.github/workflows/android.yml
vendored
11
.github/workflows/android.yml
vendored
@ -7,23 +7,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone yubikit-android
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: Yubico/yubikit-android
|
||||
ref: dain/scp
|
||||
path: kit
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Build yubikit-android
|
||||
run: ./gradlew --stacktrace build publishToMavenLocal
|
||||
working-directory: ./kit
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: 'app'
|
||||
|
11
.github/workflows/codeql-analysis.yml
vendored
11
.github/workflows/codeql-analysis.yml
vendored
@ -33,23 +33,12 @@ jobs:
|
||||
languages: ${{ matrix.language }}
|
||||
setup-python-dependencies: false
|
||||
|
||||
- name: Clone yubikit-android
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: Yubico/yubikit-android
|
||||
ref: dain/scp
|
||||
path: kit
|
||||
|
||||
- name: set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Build yubikit-android
|
||||
run: ./gradlew --stacktrace build publishToMavenLocal
|
||||
working-directory: ./kit
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: 'app'
|
||||
|
4
.github/workflows/env
vendored
4
.github/workflows/env
vendored
@ -1,2 +1,2 @@
|
||||
FLUTTER=3.22.2
|
||||
PYVER=3.12.4
|
||||
FLUTTER=3.24.0
|
||||
PYVER=3.12.5
|
||||
|
8
.github/workflows/macos.yml
vendored
8
.github/workflows/macos.yml
vendored
@ -52,11 +52,17 @@ jobs:
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
architecture: 'x64'
|
||||
flutter-version: ${{ env.FLUTTER }}
|
||||
- run: flutter config --enable-macos-desktop
|
||||
- run: flutter --version
|
||||
|
||||
- name: Apply Flutter Patch
|
||||
run: |
|
||||
cd $FLUTTER_ROOT
|
||||
git apply $GITHUB_WORKSPACE/macos_assemble.patch
|
||||
env:
|
||||
GITHUB_WORKSPACE: ${{ github.workspace }}
|
||||
|
||||
- name: Run lints/tests
|
||||
env:
|
||||
SKIP: ${{ steps.cache-helper.outputs.cache-hit == 'true' && 'mypy,flake8,black,bandit' || ''}}
|
||||
|
@ -26,7 +26,8 @@ enum class FidoActionDescription(private val value: Int) {
|
||||
DeleteFingerprint(4),
|
||||
RenameFingerprint(5),
|
||||
RegisterFingerprint(6),
|
||||
ActionFailure(7);
|
||||
EnableEnterpriseAttestation(7),
|
||||
ActionFailure(8);
|
||||
|
||||
val id: Int
|
||||
get() = value + dialogDescriptionFidoIndex
|
||||
|
@ -42,6 +42,7 @@ import com.yubico.yubikit.core.smartcard.SmartCardConnection
|
||||
import com.yubico.yubikit.core.util.Result
|
||||
import com.yubico.yubikit.fido.ctap.BioEnrollment
|
||||
import com.yubico.yubikit.fido.ctap.ClientPin
|
||||
import com.yubico.yubikit.fido.ctap.Config
|
||||
import com.yubico.yubikit.fido.ctap.CredentialManagement
|
||||
import com.yubico.yubikit.fido.ctap.Ctap2Session.InfoData
|
||||
import com.yubico.yubikit.fido.ctap.FingerprintBioEnrollment
|
||||
@ -159,6 +160,8 @@ class FidoManager(
|
||||
|
||||
"cancelRegisterFingerprint" -> cancelRegisterFingerprint()
|
||||
|
||||
"enableEnterpriseAttestation" -> enableEnterpriseAttestation()
|
||||
|
||||
else -> throw NotImplementedError()
|
||||
}
|
||||
}
|
||||
@ -603,6 +606,42 @@ class FidoManager(
|
||||
).toString()
|
||||
}
|
||||
|
||||
private suspend fun enableEnterpriseAttestation(): String =
|
||||
connectionHelper.useSession(FidoActionDescription.EnableEnterpriseAttestation) { fidoSession ->
|
||||
try {
|
||||
val uvAuthProtocol = getPreferredPinUvAuthProtocol(fidoSession.cachedInfo)
|
||||
val clientPin = ClientPin(fidoSession, uvAuthProtocol)
|
||||
val token = if (pinStore.hasPin()) {
|
||||
clientPin.getPinToken(
|
||||
pinStore.getPin(),
|
||||
ClientPin.PIN_PERMISSION_ACFG,
|
||||
null
|
||||
)
|
||||
} else null
|
||||
|
||||
val config = Config(fidoSession, uvAuthProtocol, token)
|
||||
config.enableEnterpriseAttestation()
|
||||
fidoViewModel.setSessionState(
|
||||
Session(
|
||||
fidoSession.info,
|
||||
pinStore.hasPin(),
|
||||
pinRetries
|
||||
)
|
||||
)
|
||||
return@useSession JSONObject(
|
||||
mapOf(
|
||||
"success" to true,
|
||||
)
|
||||
).toString()
|
||||
} catch (e: Exception) {
|
||||
logger.error("Failed to enable enterprise attestation. ", e)
|
||||
return@useSession JSONObject(
|
||||
mapOf(
|
||||
"success" to false,
|
||||
)
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDisconnected() {
|
||||
if (!resetHelper.inProgress) {
|
||||
|
@ -29,7 +29,8 @@ data class Options(
|
||||
val credMgmt: Boolean,
|
||||
val credentialMgmtPreview: Boolean,
|
||||
val bioEnroll: Boolean?,
|
||||
val alwaysUv: Boolean
|
||||
val alwaysUv: Boolean,
|
||||
val ep: Boolean?,
|
||||
) {
|
||||
constructor(infoData: InfoData) : this(
|
||||
infoData.getOptionsBoolean("clientPin") == true,
|
||||
@ -37,6 +38,7 @@ data class Options(
|
||||
infoData.getOptionsBoolean("credentialMgmtPreview") == true,
|
||||
infoData.getOptionsBoolean("bioEnroll"),
|
||||
infoData.getOptionsBoolean("alwaysUv") == true,
|
||||
infoData.getOptionsBoolean("ep"),
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
@ -2,7 +2,6 @@ allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
project.ext {
|
||||
@ -10,7 +9,7 @@ allprojects {
|
||||
targetSdkVersion = 34
|
||||
compileSdkVersion = 34
|
||||
|
||||
yubiKitVersion = "2.6.1-SNAPSHOT"
|
||||
yubiKitVersion = "2.7.0-alpha01"
|
||||
junitVersion = "4.13.2"
|
||||
mockitoVersion = "5.12.0"
|
||||
}
|
||||
|
@ -543,16 +543,17 @@ class ScpConnectionNode(ConnectionNode):
|
||||
self.fips_capable = info.fips_capable
|
||||
self.scp_params = None
|
||||
try:
|
||||
scp = SecurityDomainSession(connection)
|
||||
if self.fips_capable != 0:
|
||||
scp = SecurityDomainSession(connection)
|
||||
|
||||
for ref in scp.get_key_information().keys():
|
||||
if ref.kid == 0x13:
|
||||
chain = scp.get_certificate_bundle(ref)
|
||||
if chain:
|
||||
pub_key = chain[-1].public_key()
|
||||
assert isinstance(pub_key, EllipticCurvePublicKey) # nosec
|
||||
self.scp_params = Scp11KeyParams(ref, pub_key)
|
||||
break
|
||||
for ref in scp.get_key_information().keys():
|
||||
if ref.kid == 0x13:
|
||||
chain = scp.get_certificate_bundle(ref)
|
||||
if chain:
|
||||
pub_key = chain[-1].public_key()
|
||||
assert isinstance(pub_key, EllipticCurvePublicKey) # nosec
|
||||
self.scp_params = Scp11KeyParams(ref, pub_key)
|
||||
break
|
||||
except NotSupportedError:
|
||||
pass
|
||||
|
||||
|
@ -23,7 +23,7 @@ from .base import (
|
||||
PinComplexityException,
|
||||
)
|
||||
from fido2.ctap import CtapError
|
||||
from fido2.ctap2 import Ctap2, ClientPin
|
||||
from fido2.ctap2 import Ctap2, ClientPin, Config
|
||||
from fido2.ctap2.credman import CredentialManagement
|
||||
from fido2.ctap2.bio import BioEnrollment, FPBioEnrollment, CaptureError
|
||||
from fido2.pcsc import CtapPcscDevice
|
||||
@ -200,6 +200,8 @@ class Ctap2Node(RpcNode):
|
||||
permissions |= ClientPin.PERMISSION.CREDENTIAL_MGMT
|
||||
if BioEnrollment.is_supported(self._info):
|
||||
permissions |= ClientPin.PERMISSION.BIO_ENROLL
|
||||
if Config.is_supported(self._info):
|
||||
permissions |= ClientPin.PERMISSION.AUTHENTICATOR_CFG
|
||||
try:
|
||||
if permissions:
|
||||
self._token = self.client_pin.get_pin_token(pin, permissions)
|
||||
@ -229,6 +231,14 @@ class Ctap2Node(RpcNode):
|
||||
except CtapError as e:
|
||||
return _handle_pin_error(e, self.client_pin)
|
||||
|
||||
@action(condition=lambda self: Config.is_supported(self._info))
|
||||
def enable_ep_attestation(self, params, event, signal):
|
||||
if self._info.options["clientPin"] and not self._token:
|
||||
raise AuthRequiredException()
|
||||
config = Config(self.ctap, self.client_pin.protocol, self._token)
|
||||
config._call(Config.CMD.ENABLE_ENTERPRISE_ATT)
|
||||
return dict()
|
||||
|
||||
@child(condition=lambda self: BioEnrollment.is_supported(self._info))
|
||||
def fingerprints(self):
|
||||
if not self._token:
|
||||
@ -391,8 +401,10 @@ class FingerprintNode(RpcNode):
|
||||
self.bio.set_name(self.template_id, name)
|
||||
self.name = name
|
||||
self.refresh()
|
||||
return dict()
|
||||
|
||||
@action
|
||||
def delete(self, params, event, signal):
|
||||
self.bio.remove_enrollment(self.template_id)
|
||||
self.refresh()
|
||||
return dict()
|
||||
|
@ -135,11 +135,18 @@ class PivNode(RpcNode):
|
||||
pin_attempts = self.session.get_pin_attempts()
|
||||
metadata = None
|
||||
|
||||
try:
|
||||
self.session.get_bio_metadata()
|
||||
supports_bio = True
|
||||
except NotSupportedError:
|
||||
supports_bio = False
|
||||
|
||||
return dict(
|
||||
version=self.session.version,
|
||||
authenticated=self._authenticated,
|
||||
derived_key=self._pivman_data.has_derived_key,
|
||||
stored_key=self._pivman_data.has_stored_key,
|
||||
supports_bio=supports_bio,
|
||||
chuid=self._get_object(OBJECT_ID.CHUID),
|
||||
ccc=self._get_object(OBJECT_ID.CAPABILITY),
|
||||
pin_attempts=pin_attempts,
|
||||
|
359
helper/poetry.lock
generated
359
helper/poetry.lock
generated
@ -28,63 +28,78 @@ testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-ch
|
||||
|
||||
[[package]]
|
||||
name = "cffi"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"},
|
||||
{file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"},
|
||||
{file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"},
|
||||
{file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"},
|
||||
{file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"},
|
||||
{file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"},
|
||||
{file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"},
|
||||
{file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"},
|
||||
{file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"},
|
||||
{file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"},
|
||||
{file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"},
|
||||
{file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"},
|
||||
{file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"},
|
||||
{file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"},
|
||||
{file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"},
|
||||
{file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"},
|
||||
{file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"},
|
||||
{file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"},
|
||||
{file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"},
|
||||
{file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"},
|
||||
{file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -117,43 +132,38 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "42.0.8"
|
||||
version = "43.0.0"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"},
|
||||
{file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"},
|
||||
{file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"},
|
||||
{file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"},
|
||||
{file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"},
|
||||
{file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"},
|
||||
{file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"},
|
||||
{file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"},
|
||||
{file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"},
|
||||
{file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"},
|
||||
{file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"},
|
||||
{file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"},
|
||||
{file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"},
|
||||
{file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"},
|
||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70"},
|
||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66"},
|
||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f"},
|
||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f"},
|
||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2"},
|
||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947"},
|
||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069"},
|
||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1"},
|
||||
{file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -166,18 +176,18 @@ nox = ["nox"]
|
||||
pep8test = ["check-sdist", "click", "mypy", "ruff"]
|
||||
sdist = ["build"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
|
||||
test = ["certifi", "cryptography-vectors (==43.0.0)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
|
||||
test-randomorder = ["pytest-randomly"]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.1"
|
||||
version = "1.2.2"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
|
||||
{file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"},
|
||||
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
|
||||
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
@ -202,13 +212,13 @@ pcsc = ["pyscard (>=1.9,<3)"]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "8.0.0"
|
||||
version = "8.2.0"
|
||||
description = "Read metadata from Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "importlib_metadata-8.0.0-py3-none-any.whl", hash = "sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f"},
|
||||
{file = "importlib_metadata-8.0.0.tar.gz", hash = "sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812"},
|
||||
{file = "importlib_metadata-8.2.0-py3-none-any.whl", hash = "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369"},
|
||||
{file = "importlib_metadata-8.2.0.tar.gz", hash = "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -221,21 +231,21 @@ test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "p
|
||||
|
||||
[[package]]
|
||||
name = "importlib-resources"
|
||||
version = "6.4.0"
|
||||
version = "6.4.2"
|
||||
description = "Read resources from Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"},
|
||||
{file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"},
|
||||
{file = "importlib_resources-6.4.2-py3-none-any.whl", hash = "sha256:8bba8c54a8a3afaa1419910845fa26ebd706dc716dd208d9b158b4b6966f5c5c"},
|
||||
{file = "importlib_resources-6.4.2.tar.gz", hash = "sha256:6cbfbefc449cc6e2095dd184691b7a12a04f40bc75dd4c55d31c34f174cdf57a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"]
|
||||
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
@ -286,21 +296,21 @@ testing = ["portend", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytes
|
||||
|
||||
[[package]]
|
||||
name = "jaraco-functools"
|
||||
version = "4.0.1"
|
||||
version = "4.0.2"
|
||||
description = "Functools like those found in stdlib"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "jaraco.functools-4.0.1-py3-none-any.whl", hash = "sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664"},
|
||||
{file = "jaraco_functools-4.0.1.tar.gz", hash = "sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8"},
|
||||
{file = "jaraco.functools-4.0.2-py3-none-any.whl", hash = "sha256:c9d16a3ed4ccb5a889ad8e0b7a343401ee5b2a71cee6ed192d3f68bc351e94e3"},
|
||||
{file = "jaraco_functools-4.0.2.tar.gz", hash = "sha256:3460c74cd0d32bf82b9576bbb3527c4364d5b27a21f5158a62aed6c4b42e23f5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
more-itertools = "*"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["jaraco.classes", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
|
||||
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
test = ["jaraco.classes", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "jeepney"
|
||||
@ -319,13 +329,13 @@ trio = ["async_generator", "trio"]
|
||||
|
||||
[[package]]
|
||||
name = "keyring"
|
||||
version = "25.2.1"
|
||||
version = "25.3.0"
|
||||
description = "Store and access your passwords safely."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "keyring-25.2.1-py3-none-any.whl", hash = "sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50"},
|
||||
{file = "keyring-25.2.1.tar.gz", hash = "sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b"},
|
||||
{file = "keyring-25.3.0-py3-none-any.whl", hash = "sha256:8d963da00ccdf06e356acd9bf3b743208878751032d8599c6cc89eb51310ffae"},
|
||||
{file = "keyring-25.3.0.tar.gz", hash = "sha256:8d85a1ea5d6db8515b59e1c5d1d1678b03cf7fc8b8dcfb1651e8c4a524eb42ef"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -340,8 +350,8 @@ SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""}
|
||||
|
||||
[package.extras]
|
||||
completion = ["shtab (>=1.1.0)"]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
testing = ["pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
|
||||
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
test = ["pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "macholib"
|
||||
@ -359,13 +369,13 @@ altgraph = ">=0.17"
|
||||
|
||||
[[package]]
|
||||
name = "more-itertools"
|
||||
version = "10.3.0"
|
||||
version = "10.4.0"
|
||||
description = "More routines for operating on iterables, beyond itertools"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "more-itertools-10.3.0.tar.gz", hash = "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463"},
|
||||
{file = "more_itertools-10.3.0-py3-none-any.whl", hash = "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"},
|
||||
{file = "more-itertools-10.4.0.tar.gz", hash = "sha256:fe0e63c4ab068eac62410ab05cccca2dc71ec44ba8ef29916a0090df061cf923"},
|
||||
{file = "more_itertools-10.4.0-py3-none-any.whl", hash = "sha256:0f7d9f83a0a8dcfa8a2694a770590d98a67ea943e3d9f5298309a484758c4e27"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -381,44 +391,44 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.10.1"
|
||||
version = "1.11.1"
|
||||
description = "Optional static typing for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"},
|
||||
{file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"},
|
||||
{file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"},
|
||||
{file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"},
|
||||
{file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"},
|
||||
{file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"},
|
||||
{file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"},
|
||||
{file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"},
|
||||
{file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"},
|
||||
{file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"},
|
||||
{file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"},
|
||||
{file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"},
|
||||
{file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"},
|
||||
{file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"},
|
||||
{file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"},
|
||||
{file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"},
|
||||
{file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"},
|
||||
{file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"},
|
||||
{file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"},
|
||||
{file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"},
|
||||
{file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"},
|
||||
{file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"},
|
||||
{file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"},
|
||||
{file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"},
|
||||
{file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"},
|
||||
{file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"},
|
||||
{file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"},
|
||||
{file = "mypy-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c"},
|
||||
{file = "mypy-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411"},
|
||||
{file = "mypy-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1e30dc3bfa4e157e53c1d17a0dad20f89dc433393e7702b813c10e200843b03"},
|
||||
{file = "mypy-1.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2c63350af88f43a66d3dfeeeb8d77af34a4f07d760b9eb3a8697f0386c7590b4"},
|
||||
{file = "mypy-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:a831671bad47186603872a3abc19634f3011d7f83b083762c942442d51c58d58"},
|
||||
{file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"},
|
||||
{file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"},
|
||||
{file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"},
|
||||
{file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"},
|
||||
{file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"},
|
||||
{file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"},
|
||||
{file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"},
|
||||
{file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"},
|
||||
{file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"},
|
||||
{file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"},
|
||||
{file = "mypy-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:749fd3213916f1751fff995fccf20c6195cae941dc968f3aaadf9bb4e430e5a2"},
|
||||
{file = "mypy-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b639dce63a0b19085213ec5fdd8cffd1d81988f47a2dec7100e93564f3e8fb3b"},
|
||||
{file = "mypy-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c956b49c5d865394d62941b109728c5c596a415e9c5b2be663dd26a1ff07bc0"},
|
||||
{file = "mypy-1.11.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45df906e8b6804ef4b666af29a87ad9f5921aad091c79cc38e12198e220beabd"},
|
||||
{file = "mypy-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:d44be7551689d9d47b7abc27c71257adfdb53f03880841a5db15ddb22dc63edb"},
|
||||
{file = "mypy-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2684d3f693073ab89d76da8e3921883019ea8a3ec20fa5d8ecca6a2db4c54bbe"},
|
||||
{file = "mypy-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79c07eb282cb457473add5052b63925e5cc97dfab9812ee65a7c7ab5e3cb551c"},
|
||||
{file = "mypy-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11965c2f571ded6239977b14deebd3f4c3abd9a92398712d6da3a772974fad69"},
|
||||
{file = "mypy-1.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a2b43895a0f8154df6519706d9bca8280cda52d3d9d1514b2d9c3e26792a0b74"},
|
||||
{file = "mypy-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:1a81cf05975fd61aec5ae16501a091cfb9f605dc3e3c878c0da32f250b74760b"},
|
||||
{file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"},
|
||||
{file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mypy-extensions = ">=1.0.0"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
typing-extensions = ">=4.1.0"
|
||||
typing-extensions = ">=4.6.0"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
@ -584,23 +594,23 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pyinstaller"
|
||||
version = "6.8.0"
|
||||
version = "6.10.0"
|
||||
description = "PyInstaller bundles a Python application and all its dependencies into a single package."
|
||||
optional = false
|
||||
python-versions = "<3.13,>=3.8"
|
||||
python-versions = "<3.14,>=3.8"
|
||||
files = [
|
||||
{file = "pyinstaller-6.8.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:5ff6bc2784c1026f8e2f04aa3760cbed41408e108a9d4cf1dd52ee8351a3f6e1"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:39ac424d2ee2457d2ab11a5091436e75a0cccae207d460d180aa1fcbbafdd528"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_i686.whl", hash = "sha256:355832a3acc7de90a255ecacd4b9f9e166a547a79c8905d49f14e3a75c1acdb9"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:6303c7a009f47e6a96ef65aed49f41e36ece8d079b9193ca92fe807403e5fe80"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2b71509468c811968c0b5decb5bbe85b6292ea52d7b1f26313d2aabb673fa9a5"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ff31c5b99e05a4384bbe2071df67ec8b2b347640a375eae9b40218be2f1754c6"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:000c36b13fe4cd8d0d8c2bc855b1ddcf39867b5adf389e6b5ca45b25fa3e619d"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:fe0af018d7d5077180e3144ada89a4da5df8d07716eb7e9482834a56dc57a4e8"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-win32.whl", hash = "sha256:d257f6645c7334cbd66f38a4fac62c3ad614cc46302b2b5d9f8cc48c563bce0e"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-win_amd64.whl", hash = "sha256:81cccfa9b16699b457f4788c5cc119b50f3cd4d0db924955f15c33f2ad27a50d"},
|
||||
{file = "pyinstaller-6.8.0-py3-none-win_arm64.whl", hash = "sha256:1c3060a263758cf7f0144ab4c016097b20451b2469d468763414665db1bb743d"},
|
||||
{file = "pyinstaller-6.8.0.tar.gz", hash = "sha256:3f4b6520f4423fe19bcc2fd63ab7238851ae2bdcbc98f25bc5d2f97cc62012e9"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:d60fb22859e11483af735aec115fdde09467cdbb29edd9844839f2c920b748c0"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:46d75359668993ddd98630a3669dc5249f3c446e35239b43bc7f4155bc574748"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-manylinux2014_i686.whl", hash = "sha256:3398a98fa17d47ccb31f8779ecbdacec025f7adb2f22757a54b706ac8b4fe906"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e9989f354ae4ed8a3bec7bdb37ae0d170751d6520e500f049c7cd0632d31d5c3"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:b7c90c91921b3749083115b28f30f40abf2bb481ceff196d2b2ce0eaa2b3d429"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6cf876d7d93b8b4f28d1ad57fa24645cf43119c79e985dd5e5f7a801245e6f53"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:db05e3f2f10f9f78c56f1fb163d9cb453433429fe4281218ebaf1ebfd39ba942"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:28eca3817f176fdc19747e1afcf434f13bb9f17a644f611be2c5a61b1f498ed7"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-win32.whl", hash = "sha256:703e041718987e46ba0568a2c71ecf2459fddef57cf9edf3efeed4a53e3dae3f"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-win_amd64.whl", hash = "sha256:95b55966e563e8b8f31a43882aea10169e9a11fdf38e626d86a2907b640c0701"},
|
||||
{file = "pyinstaller-6.10.0-py3-none-win_arm64.whl", hash = "sha256:308e0a8670c9c9ac0cebbf1bbb492e71b6675606f2ec78bc4adfc830d209e087"},
|
||||
{file = "pyinstaller-6.10.0.tar.gz", hash = "sha256:143840f8056ff7b910bf8f16f6cd92cc10a6c2680bb76d0a25d558d543d21270"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -609,7 +619,7 @@ importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
|
||||
macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""}
|
||||
packaging = ">=22.0"
|
||||
pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""}
|
||||
pyinstaller-hooks-contrib = ">=2024.6"
|
||||
pyinstaller-hooks-contrib = ">=2024.8"
|
||||
pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""}
|
||||
setuptools = ">=42.0.0"
|
||||
|
||||
@ -619,13 +629,13 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyinstaller-hooks-contrib"
|
||||
version = "2024.7"
|
||||
version = "2024.8"
|
||||
description = "Community maintained hooks for PyInstaller"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyinstaller_hooks_contrib-2024.7-py2.py3-none-any.whl", hash = "sha256:8bf0775771fbaf96bcd2f4dfd6f7ae6c1dd1b1efe254c7e50477b3c08e7841d8"},
|
||||
{file = "pyinstaller_hooks_contrib-2024.7.tar.gz", hash = "sha256:fd5f37dcf99bece184e40642af88be16a9b89613ecb958a8bd1136634fc9fac5"},
|
||||
{file = "pyinstaller_hooks_contrib-2024.8-py3-none-any.whl", hash = "sha256:0057fe9a5c398d3f580e73e58793a1d4a8315ca91c3df01efea1c14ed557825a"},
|
||||
{file = "pyinstaller_hooks_contrib-2024.8.tar.gz", hash = "sha256:29b68d878ab739e967055b56a93eb9b58e529d5b054fbab7a2f2bacf80cef3e2"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -662,13 +672,13 @@ pyro = ["Pyro"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.2.2"
|
||||
version = "8.3.2"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"},
|
||||
{file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"},
|
||||
{file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"},
|
||||
{file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@ -676,7 +686,7 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=1.5,<2.0"
|
||||
pluggy = ">=1.5,<2"
|
||||
tomli = {version = ">=1", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
@ -707,13 +717,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "pywin32-ctypes"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"},
|
||||
{file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"},
|
||||
{file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"},
|
||||
{file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -733,18 +743,19 @@ jeepney = ">=0.6"
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "70.2.0"
|
||||
version = "72.2.0"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"},
|
||||
{file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"},
|
||||
{file = "setuptools-72.2.0-py3-none-any.whl", hash = "sha256:f11dd94b7bae3a156a95ec151f24e4637fb4fa19c878e4d191bfb8b2d82728c4"},
|
||||
{file = "setuptools-72.2.0.tar.gz", hash = "sha256:80aacbf633704e9c8bfa1d99fa5dd4dc59573efcf9e4042c13d3bcef91ac2ef9"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||
core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
|
||||
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
|
||||
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
@ -800,13 +811,13 @@ pywin32 = {version = ">=223", markers = "sys_platform == \"win32\""}
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.19.2"
|
||||
version = "3.20.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"},
|
||||
{file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"},
|
||||
{file = "zipp-3.20.0-py3-none-any.whl", hash = "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d"},
|
||||
{file = "zipp-3.20.0.tar.gz", hash = "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -94,9 +94,10 @@ class RpcShell(cmd.Cmd):
|
||||
cmd = target.pop() if target else ""
|
||||
node = self.get_node(target)
|
||||
if node:
|
||||
names = [n + "/" for n in node.get("children", [])]
|
||||
body = node.get("body", {})
|
||||
names = [n + "/" for n in body.get("children", [])]
|
||||
if not nodes_only:
|
||||
actions = node.get("actions", [])
|
||||
actions = body.get("actions", [])
|
||||
if "get" in actions:
|
||||
actions.remove("get")
|
||||
names += actions
|
||||
@ -104,10 +105,10 @@ class RpcShell(cmd.Cmd):
|
||||
return res
|
||||
return []
|
||||
|
||||
def completedefault(self, cmd, text, *args):
|
||||
def completedefault(self, cmd, text, *args): # type: ignore
|
||||
return self.completepath(text)
|
||||
|
||||
def completenames(self, cmd, text, *ignored):
|
||||
def completenames(self, cmd, text, *ignored): # type: ignore
|
||||
return self.completepath(text)
|
||||
|
||||
def emptyline(self):
|
||||
|
@ -161,6 +161,29 @@ class _FidoStateNotifier extends FidoStateNotifier {
|
||||
throw decodedException;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> enableEnterpriseAttestation() async {
|
||||
try {
|
||||
final response = jsonDecode(await _methods.invokeMethod(
|
||||
'enableEnterpriseAttestation',
|
||||
));
|
||||
|
||||
if (response['success'] == true) {
|
||||
_log.debug('Enterprise attestation enabled');
|
||||
}
|
||||
} on PlatformException catch (pe) {
|
||||
var decodedException = pe.decode();
|
||||
if (decodedException is CancellationException) {
|
||||
_log.debug('User cancelled unlock FIDO operation');
|
||||
throw decodedException;
|
||||
}
|
||||
|
||||
_log.debug(
|
||||
'Platform exception during enable enterprise attestation: $pe');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final androidFingerprintProvider = AsyncNotifierProvider.autoDispose
|
||||
|
@ -80,6 +80,8 @@ enum _DDesc {
|
||||
fidoDeleteCredential,
|
||||
fidoDeleteFingerprint,
|
||||
fidoRenameFingerprint,
|
||||
fidoRegisterFingerprint,
|
||||
fidoEnableEnterpriseAttestation,
|
||||
fidoActionFailure,
|
||||
// Others
|
||||
invalid;
|
||||
@ -105,7 +107,9 @@ enum _DDesc {
|
||||
dialogDescriptionFidoIndex + 3: fidoDeleteCredential,
|
||||
dialogDescriptionFidoIndex + 4: fidoDeleteFingerprint,
|
||||
dialogDescriptionFidoIndex + 5: fidoRenameFingerprint,
|
||||
dialogDescriptionFidoIndex + 6: fidoActionFailure,
|
||||
dialogDescriptionFidoIndex + 6: fidoRegisterFingerprint,
|
||||
dialogDescriptionFidoIndex + 7: fidoEnableEnterpriseAttestation,
|
||||
dialogDescriptionFidoIndex + 8: fidoActionFailure,
|
||||
}[id] ??
|
||||
_DDesc.invalid;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ Future<T?> showBlurDialog<T>({
|
||||
required BuildContext context,
|
||||
required Widget Function(BuildContext) builder,
|
||||
RouteSettings? routeSettings,
|
||||
Color barrierColor = const Color(0x00cccccc),
|
||||
Color barrierColor = const Color(0x33000000),
|
||||
}) async =>
|
||||
await showGeneralDialog<T>(
|
||||
context: context,
|
||||
|
@ -20,7 +20,9 @@ mixin _$YubiKeyData {
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
DeviceInfo get info => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of YubiKeyData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$YubiKeyDataCopyWith<YubiKeyData> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -47,6 +49,8 @@ class _$YubiKeyDataCopyWithImpl<$Res, $Val extends YubiKeyData>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of YubiKeyData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -70,6 +74,8 @@ class _$YubiKeyDataCopyWithImpl<$Res, $Val extends YubiKeyData>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of YubiKeyData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$DeviceNodeCopyWith<$Res> get node {
|
||||
@ -78,6 +84,8 @@ class _$YubiKeyDataCopyWithImpl<$Res, $Val extends YubiKeyData>
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of YubiKeyData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$DeviceInfoCopyWith<$Res> get info {
|
||||
@ -111,6 +119,8 @@ class __$$YubiKeyDataImplCopyWithImpl<$Res>
|
||||
_$YubiKeyDataImpl _value, $Res Function(_$YubiKeyDataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of YubiKeyData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -165,7 +175,9 @@ class _$YubiKeyDataImpl implements _YubiKeyData {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, node, name, info);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of YubiKeyData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$YubiKeyDataImplCopyWith<_$YubiKeyDataImpl> get copyWith =>
|
||||
@ -183,8 +195,11 @@ abstract class _YubiKeyData implements YubiKeyData {
|
||||
String get name;
|
||||
@override
|
||||
DeviceInfo get info;
|
||||
|
||||
/// Create a copy of YubiKeyData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$YubiKeyDataImplCopyWith<_$YubiKeyDataImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -238,7 +253,9 @@ mixin _$DeviceNode {
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$DeviceNodeCopyWith<DeviceNode> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -262,6 +279,8 @@ class _$DeviceNodeCopyWithImpl<$Res, $Val extends DeviceNode>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -302,6 +321,8 @@ class __$$UsbYubiKeyNodeImplCopyWithImpl<$Res>
|
||||
_$UsbYubiKeyNodeImpl _value, $Res Function(_$UsbYubiKeyNodeImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -330,6 +351,8 @@ class __$$UsbYubiKeyNodeImplCopyWithImpl<$Res>
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$DeviceInfoCopyWith<$Res>? get info {
|
||||
@ -376,7 +399,9 @@ class _$UsbYubiKeyNodeImpl extends UsbYubiKeyNode {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, path, name, pid, info);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$UsbYubiKeyNodeImplCopyWith<_$UsbYubiKeyNodeImpl> get copyWith =>
|
||||
@ -463,8 +488,11 @@ abstract class UsbYubiKeyNode extends DeviceNode {
|
||||
String get name;
|
||||
UsbPid get pid;
|
||||
DeviceInfo? get info;
|
||||
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$UsbYubiKeyNodeImplCopyWith<_$UsbYubiKeyNodeImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -488,6 +516,8 @@ class __$$NfcReaderNodeImplCopyWithImpl<$Res>
|
||||
_$NfcReaderNodeImpl _value, $Res Function(_$NfcReaderNodeImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -534,7 +564,9 @@ class _$NfcReaderNodeImpl extends NfcReaderNode {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, path, name);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$NfcReaderNodeImplCopyWith<_$NfcReaderNodeImpl> get copyWith =>
|
||||
@ -618,8 +650,11 @@ abstract class NfcReaderNode extends DeviceNode {
|
||||
DevicePath get path;
|
||||
@override
|
||||
String get name;
|
||||
|
||||
/// Create a copy of DeviceNode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$NfcReaderNodeImplCopyWith<_$NfcReaderNodeImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -636,7 +671,9 @@ mixin _$ActionItem {
|
||||
Key? get key => throw _privateConstructorUsedError;
|
||||
Feature? get feature => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of ActionItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ActionItemCopyWith<ActionItem> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -669,6 +706,8 @@ class _$ActionItemCopyWithImpl<$Res, $Val extends ActionItem>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ActionItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -751,6 +790,8 @@ class __$$ActionItemImplCopyWithImpl<$Res>
|
||||
_$ActionItemImpl _value, $Res Function(_$ActionItemImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ActionItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -867,7 +908,9 @@ class _$ActionItemImpl implements _ActionItem {
|
||||
int get hashCode => Object.hash(runtimeType, icon, title, subtitle, shortcut,
|
||||
trailing, intent, actionStyle, key, feature);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of ActionItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ActionItemImplCopyWith<_$ActionItemImpl> get copyWith =>
|
||||
@ -904,8 +947,11 @@ abstract class _ActionItem implements ActionItem {
|
||||
Key? get key;
|
||||
@override
|
||||
Feature? get feature;
|
||||
|
||||
/// Create a copy of ActionItem
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ActionItemImplCopyWith<_$ActionItemImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -917,7 +963,9 @@ mixin _$WindowState {
|
||||
bool get active => throw _privateConstructorUsedError;
|
||||
bool get hidden => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of WindowState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$WindowStateCopyWith<WindowState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -941,6 +989,8 @@ class _$WindowStateCopyWithImpl<$Res, $Val extends WindowState>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of WindowState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -989,6 +1039,8 @@ class __$$WindowStateImplCopyWithImpl<$Res>
|
||||
_$WindowStateImpl _value, $Res Function(_$WindowStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of WindowState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1057,7 +1109,9 @@ class _$WindowStateImpl implements _WindowState {
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, focused, visible, active, hidden);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of WindowState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$WindowStateImplCopyWith<_$WindowStateImpl> get copyWith =>
|
||||
@ -1079,8 +1133,11 @@ abstract class _WindowState implements WindowState {
|
||||
bool get active;
|
||||
@override
|
||||
bool get hidden;
|
||||
|
||||
/// Create a copy of WindowState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$WindowStateImplCopyWith<_$WindowStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1098,8 +1155,12 @@ mixin _$KeyCustomization {
|
||||
@_ColorConverter()
|
||||
Color? get color => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this KeyCustomization to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of KeyCustomization
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$KeyCustomizationCopyWith<KeyCustomization> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1126,6 +1187,8 @@ class _$KeyCustomizationCopyWithImpl<$Res, $Val extends KeyCustomization>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of KeyCustomization
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1172,6 +1235,8 @@ class __$$KeyCustomizationImplCopyWithImpl<$Res>
|
||||
$Res Function(_$KeyCustomizationImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of KeyCustomization
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1232,11 +1297,13 @@ class _$KeyCustomizationImpl implements _KeyCustomization {
|
||||
(identical(other.color, color) || other.color == color));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, serial, name, color);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of KeyCustomization
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$KeyCustomizationImplCopyWith<_$KeyCustomizationImpl> get copyWith =>
|
||||
@ -1271,8 +1338,11 @@ abstract class _KeyCustomization implements KeyCustomization {
|
||||
@JsonKey(includeIfNull: false)
|
||||
@_ColorConverter()
|
||||
Color? get color;
|
||||
|
||||
/// Create a copy of KeyCustomization
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$KeyCustomizationImplCopyWith<_$KeyCustomizationImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -30,8 +30,10 @@ class AppListItem<T> extends ConsumerStatefulWidget {
|
||||
final String? semanticTitle;
|
||||
final Widget? trailing;
|
||||
final List<ActionItem> Function(BuildContext context)? buildPopupActions;
|
||||
final Widget Function(BuildContext context)? itemBuilder;
|
||||
final Intent? tapIntent;
|
||||
final Intent? doubleTapIntent;
|
||||
final Color? tileColor;
|
||||
final bool selected;
|
||||
|
||||
const AppListItem(
|
||||
@ -43,8 +45,10 @@ class AppListItem<T> extends ConsumerStatefulWidget {
|
||||
this.subtitle,
|
||||
this.trailing,
|
||||
this.buildPopupActions,
|
||||
this.itemBuilder,
|
||||
this.tapIntent,
|
||||
this.doubleTapIntent,
|
||||
this.tileColor,
|
||||
this.selected = false,
|
||||
});
|
||||
|
||||
@ -78,7 +82,7 @@ class _AppListItemState<T> extends ConsumerState<AppListItem> {
|
||||
item: widget.item,
|
||||
child: InkWell(
|
||||
focusNode: _focusNode,
|
||||
borderRadius: BorderRadius.circular(48),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
onSecondaryTapDown: buildPopupActions == null
|
||||
? null
|
||||
: (details) {
|
||||
@ -118,57 +122,62 @@ class _AppListItemState<T> extends ConsumerState<AppListItem> {
|
||||
: () {
|
||||
Actions.invoke(context, doubleTapIntent);
|
||||
},
|
||||
child: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: [
|
||||
const SizedBox(height: 64),
|
||||
ListTile(
|
||||
mouseCursor:
|
||||
widget.tapIntent != null ? SystemMouseCursors.click : null,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(48)),
|
||||
selectedTileColor: colorScheme.secondaryContainer,
|
||||
selectedColor: colorScheme.onSecondaryContainer,
|
||||
selected: widget.selected,
|
||||
leading: widget.leading,
|
||||
title: subtitle == null
|
||||
// We use SizedBox to fill entire space
|
||||
? SizedBox(
|
||||
height: 48,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
widget.title,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
widget.title,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
),
|
||||
subtitle: subtitle != null
|
||||
? Text(
|
||||
subtitle,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
)
|
||||
: null,
|
||||
trailing: trailing == null
|
||||
? null
|
||||
: Focus(
|
||||
skipTraversal: true,
|
||||
descendantsAreTraversable: false,
|
||||
child: trailing,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: widget.itemBuilder != null
|
||||
? widget.itemBuilder!.call(context)
|
||||
: Stack(
|
||||
alignment: AlignmentDirectional.center,
|
||||
children: [
|
||||
const SizedBox(height: 64),
|
||||
ListTile(
|
||||
mouseCursor: widget.tapIntent != null
|
||||
? SystemMouseCursors.click
|
||||
: null,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16)),
|
||||
selectedTileColor: colorScheme.secondaryContainer,
|
||||
selectedColor: colorScheme.onSecondaryContainer,
|
||||
tileColor: widget.tileColor,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
selected: widget.selected,
|
||||
leading: widget.leading,
|
||||
title: subtitle == null
|
||||
// We use SizedBox to fill entire space
|
||||
? SizedBox(
|
||||
height: 48,
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
widget.title,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
widget.title,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
),
|
||||
subtitle: subtitle != null
|
||||
? Text(
|
||||
subtitle,
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
)
|
||||
: null,
|
||||
trailing: trailing == null
|
||||
? null
|
||||
: Focus(
|
||||
skipTraversal: true,
|
||||
descendantsAreTraversable: false,
|
||||
child: trailing,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -22,6 +22,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../core/state.dart';
|
||||
import '../../management/models.dart';
|
||||
@ -29,18 +30,29 @@ import '../../widgets/delayed_visibility.dart';
|
||||
import '../../widgets/file_drop_target.dart';
|
||||
import '../message.dart';
|
||||
import '../shortcuts.dart';
|
||||
import '../state.dart';
|
||||
import 'fs_dialog.dart';
|
||||
import 'keys.dart';
|
||||
import 'navigation.dart';
|
||||
|
||||
final _navigationProvider = StateNotifierProvider<_NavigationProvider, bool>(
|
||||
(ref) => _NavigationProvider());
|
||||
final _navigationVisibilityProvider =
|
||||
StateNotifierProvider<_VisibilityNotifier, bool>((ref) =>
|
||||
_VisibilityNotifier('NAVIGATION_VISIBILITY', ref.watch(prefProvider)));
|
||||
|
||||
class _NavigationProvider extends StateNotifier<bool> {
|
||||
_NavigationProvider() : super(true);
|
||||
final _detailViewVisibilityProvider =
|
||||
StateNotifierProvider<_VisibilityNotifier, bool>((ref) =>
|
||||
_VisibilityNotifier('DETAIL_VIEW_VISIBILITY', ref.watch(prefProvider)));
|
||||
|
||||
class _VisibilityNotifier extends StateNotifier<bool> {
|
||||
final String _key;
|
||||
final SharedPreferences _prefs;
|
||||
_VisibilityNotifier(this._key, this._prefs)
|
||||
: super(_prefs.getBool(_key) ?? true);
|
||||
|
||||
void toggleExpanded() {
|
||||
state = !state;
|
||||
final newValue = !state;
|
||||
state = newValue;
|
||||
_prefs.setBool(_key, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,14 +320,17 @@ class _AppPageState extends ConsumerState<AppPage> {
|
||||
|
||||
Widget? _buildAppBarTitle(
|
||||
BuildContext context, bool hasRail, bool hasManage, bool fullyExpanded) {
|
||||
final showNavigation = ref.watch(_navigationProvider);
|
||||
final showNavigation = ref.watch(_navigationVisibilityProvider);
|
||||
final showDetailView = ref.watch(_detailViewVisibilityProvider);
|
||||
|
||||
EdgeInsets padding;
|
||||
if (fullyExpanded) {
|
||||
padding = EdgeInsets.only(left: showNavigation ? 280 : 72, right: 320);
|
||||
padding = EdgeInsets.only(
|
||||
left: showNavigation ? 280 : 72, right: showDetailView ? 320 : 0.0);
|
||||
} else if (!hasRail && hasManage) {
|
||||
padding = const EdgeInsets.only(right: 320);
|
||||
} else if (hasRail && hasManage) {
|
||||
padding = const EdgeInsets.only(left: 72, right: 320);
|
||||
padding = EdgeInsets.only(left: 72, right: showDetailView ? 320 : 0.0);
|
||||
} else if (hasRail && !hasManage) {
|
||||
padding = const EdgeInsets.only(left: 72);
|
||||
} else {
|
||||
@ -344,21 +359,23 @@ class _AppPageState extends ConsumerState<AppPage> {
|
||||
}
|
||||
|
||||
Widget _buildMainContent(BuildContext context, bool expanded) {
|
||||
final actions = widget.actionsBuilder?.call(context, expanded) ?? [];
|
||||
final showDetailView = ref.watch(_detailViewVisibilityProvider);
|
||||
final actions =
|
||||
widget.actionsBuilder?.call(context, expanded && showDetailView) ?? [];
|
||||
final content = Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: widget.centered
|
||||
? CrossAxisAlignment.center
|
||||
: CrossAxisAlignment.start,
|
||||
children: [
|
||||
widget.builder(context, expanded),
|
||||
widget.builder(context, expanded && showDetailView),
|
||||
if (actions.isNotEmpty)
|
||||
Align(
|
||||
alignment:
|
||||
widget.centered ? Alignment.center : Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16, bottom: 0, left: 16, right: 16),
|
||||
top: 16, bottom: 0, left: 18, right: 18),
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
@ -369,7 +386,7 @@ class _AppPageState extends ConsumerState<AppPage> {
|
||||
if (widget.footnote != null)
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(bottom: 16, top: 33, left: 16, right: 16),
|
||||
const EdgeInsets.only(bottom: 16, top: 33, left: 18, right: 18),
|
||||
child: Opacity(
|
||||
opacity: 0.6,
|
||||
child: Text(
|
||||
@ -399,7 +416,7 @@ class _AppPageState extends ConsumerState<AppPage> {
|
||||
alignment: Alignment.topLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 16.0, right: 16.0, bottom: 24.0, top: 4.0),
|
||||
left: 18.0, right: 18.0, bottom: 24.0, top: 4.0),
|
||||
child: _buildTitle(context),
|
||||
),
|
||||
),
|
||||
@ -452,7 +469,7 @@ class _AppPageState extends ConsumerState<AppPage> {
|
||||
child: Padding(
|
||||
key: _sliverTitleWrapperGlobalKey,
|
||||
padding: const EdgeInsets.only(
|
||||
left: 16.0, right: 16.0, bottom: 12.0, top: 4.0),
|
||||
left: 18.0, right: 18.0, bottom: 12.0, top: 4.0),
|
||||
child: _buildTitle(context),
|
||||
),
|
||||
),
|
||||
@ -499,7 +516,8 @@ class _AppPageState extends ConsumerState<AppPage> {
|
||||
BuildContext context, bool hasDrawer, bool hasRail, bool hasManage) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final fullyExpanded = !hasDrawer && hasRail && hasManage;
|
||||
final showNavigation = ref.watch(_navigationProvider);
|
||||
final showNavigation = ref.watch(_navigationVisibilityProvider);
|
||||
final showDetailView = ref.watch(_detailViewVisibilityProvider);
|
||||
final hasDetailsOrKeyActions =
|
||||
widget.detailViewBuilder != null || widget.keyActionsBuilder != null;
|
||||
var body = _buildMainContent(context, hasManage);
|
||||
@ -518,187 +536,211 @@ class _AppPageState extends ConsumerState<AppPage> {
|
||||
);
|
||||
}
|
||||
if (hasRail || hasManage) {
|
||||
body = Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (hasRail && (!fullyExpanded || !showNavigation))
|
||||
SizedBox(
|
||||
width: 72,
|
||||
child: _VisibilityListener(
|
||||
targetKey: _navKey,
|
||||
controller: _navController,
|
||||
child: SingleChildScrollView(
|
||||
child: NavigationContent(
|
||||
key: _navKey,
|
||||
shouldPop: false,
|
||||
extended: false,
|
||||
body = GestureDetector(
|
||||
behavior: HitTestBehavior.deferToChild,
|
||||
onTap: () {
|
||||
Actions.invoke(context, const EscapeIntent());
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
},
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (hasRail && (!fullyExpanded || !showNavigation))
|
||||
SizedBox(
|
||||
width: 72,
|
||||
child: _VisibilityListener(
|
||||
targetKey: _navKey,
|
||||
controller: _navController,
|
||||
child: SingleChildScrollView(
|
||||
child: NavigationContent(
|
||||
key: _navKey,
|
||||
shouldPop: false,
|
||||
extended: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (fullyExpanded && showNavigation)
|
||||
SizedBox(
|
||||
width: 280,
|
||||
child: _VisibilityListener(
|
||||
controller: _navController,
|
||||
targetKey: _navExpandedKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: NavigationContent(
|
||||
key: _navExpandedKey,
|
||||
shouldPop: false,
|
||||
extended: true,
|
||||
if (fullyExpanded && showNavigation)
|
||||
SizedBox(
|
||||
width: 280,
|
||||
child: _VisibilityListener(
|
||||
controller: _navController,
|
||||
targetKey: _navExpandedKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: NavigationContent(
|
||||
key: _navExpandedKey,
|
||||
shouldPop: false,
|
||||
extended: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: body),
|
||||
if (hasManage &&
|
||||
!hasDetailsOrKeyActions &&
|
||||
widget.capabilities != null &&
|
||||
widget.capabilities?.first != Capability.u2f)
|
||||
// Add a placeholder for the Manage/Details column. Exceptions are:
|
||||
// - the "Security Key" because it does not have any actions/details.
|
||||
// - pages without Capabilities
|
||||
const SizedBox(width: 336), // simulate column
|
||||
if (hasManage && hasDetailsOrKeyActions && showDetailView)
|
||||
_VisibilityListener(
|
||||
controller: _detailsController,
|
||||
targetKey: _detailsViewGlobalKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: SizedBox(
|
||||
width: 320,
|
||||
child: Column(
|
||||
key: _detailsViewGlobalKey,
|
||||
children: [
|
||||
if (widget.detailViewBuilder != null)
|
||||
widget.detailViewBuilder!(context),
|
||||
if (widget.keyActionsBuilder != null)
|
||||
widget.keyActionsBuilder!(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.deferToChild,
|
||||
onTap: () {
|
||||
Actions.invoke(context, const EscapeIntent());
|
||||
},
|
||||
child: Stack(children: [
|
||||
Container(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
body
|
||||
]),
|
||||
)),
|
||||
if (hasManage &&
|
||||
!hasDetailsOrKeyActions &&
|
||||
widget.capabilities != null &&
|
||||
widget.capabilities?.first != Capability.u2f)
|
||||
// Add a placeholder for the Manage/Details column. Exceptions are:
|
||||
// - the "Security Key" because it does not have any actions/details.
|
||||
// - pages without Capabilities
|
||||
const SizedBox(width: 336), // simulate column
|
||||
if (hasManage && hasDetailsOrKeyActions)
|
||||
_VisibilityListener(
|
||||
controller: _detailsController,
|
||||
targetKey: _detailsViewGlobalKey,
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: SizedBox(
|
||||
width: 320,
|
||||
child: Column(
|
||||
key: _detailsViewGlobalKey,
|
||||
children: [
|
||||
if (widget.detailViewBuilder != null)
|
||||
widget.detailViewBuilder!(context),
|
||||
if (widget.keyActionsBuilder != null)
|
||||
widget.keyActionsBuilder!(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
key: scaffoldGlobalKey,
|
||||
appBar: AppBar(
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
child: ListenableBuilder(
|
||||
listenable: _scrolledUnderController,
|
||||
builder: (context, child) {
|
||||
final visible = _scrolledUnderController.someIsScrolledUnder;
|
||||
return AnimatedOpacity(
|
||||
opacity: visible ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
height: 1.0,
|
||||
),
|
||||
);
|
||||
},
|
||||
appBar: _GestureDetectorAppBar(
|
||||
onTap: () {
|
||||
Actions.invoke(context, const EscapeIntent());
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
},
|
||||
appBar: AppBar(
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1.0),
|
||||
child: ListenableBuilder(
|
||||
listenable: _scrolledUnderController,
|
||||
builder: (context, child) {
|
||||
final visible = _scrolledUnderController.someIsScrolledUnder;
|
||||
return AnimatedOpacity(
|
||||
opacity: visible ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: Container(
|
||||
color: Theme.of(context).hoverColor,
|
||||
height: 1.0,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
scrolledUnderElevation: 0.0,
|
||||
leadingWidth: hasRail ? 84 : null,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
title: _buildAppBarTitle(
|
||||
context,
|
||||
hasRail,
|
||||
hasManage,
|
||||
fullyExpanded,
|
||||
),
|
||||
leading: hasRail
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: IconButton(
|
||||
icon: Icon(Symbols.menu, semanticLabel: navigationText),
|
||||
tooltip: navigationText,
|
||||
onPressed: fullyExpanded
|
||||
? () {
|
||||
ref
|
||||
.read(_navigationProvider.notifier)
|
||||
.toggleExpanded();
|
||||
}
|
||||
: () {
|
||||
scaffoldGlobalKey.currentState?.openDrawer();
|
||||
},
|
||||
),
|
||||
)),
|
||||
const SizedBox(width: 12),
|
||||
],
|
||||
)
|
||||
: Builder(
|
||||
builder: (context) {
|
||||
// Need to wrap with builder to get Scaffold context
|
||||
return IconButton(
|
||||
onPressed: () => Scaffold.of(context).openDrawer(),
|
||||
icon: const Icon(Symbols.menu),
|
||||
);
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
if (widget.actionButtonBuilder == null &&
|
||||
(widget.keyActionsBuilder != null && !hasManage))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: IconButton(
|
||||
key: actionsIconButtonKey,
|
||||
onPressed: () {
|
||||
showBlurDialog(
|
||||
context: context,
|
||||
barrierColor: Colors.transparent,
|
||||
builder: (context) => FsDialog(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 32),
|
||||
child: widget.keyActionsBuilder!(context),
|
||||
scrolledUnderElevation: 0.0,
|
||||
leadingWidth: hasRail ? 84 : null,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
title: _buildAppBarTitle(
|
||||
context,
|
||||
hasRail,
|
||||
hasManage,
|
||||
fullyExpanded,
|
||||
),
|
||||
centerTitle: true,
|
||||
leading: hasRail
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: IconButton(
|
||||
icon: Icon(Symbols.menu, semanticLabel: navigationText),
|
||||
tooltip: navigationText,
|
||||
onPressed: fullyExpanded
|
||||
? () {
|
||||
ref
|
||||
.read(
|
||||
_navigationVisibilityProvider.notifier)
|
||||
.toggleExpanded();
|
||||
}
|
||||
: () {
|
||||
scaffoldGlobalKey.currentState?.openDrawer();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: widget.keyActionsBadge
|
||||
? Badge(
|
||||
child: Icon(Symbols.more_vert,
|
||||
semanticLabel: l10n.s_configure_yk),
|
||||
)
|
||||
: Icon(Symbols.more_vert,
|
||||
semanticLabel: l10n.s_configure_yk),
|
||||
iconSize: 24,
|
||||
tooltip: l10n.s_configure_yk,
|
||||
padding: const EdgeInsets.all(12),
|
||||
)),
|
||||
const SizedBox(width: 12),
|
||||
],
|
||||
)
|
||||
: Builder(
|
||||
builder: (context) {
|
||||
// Need to wrap with builder to get Scaffold context
|
||||
return IconButton(
|
||||
onPressed: () => Scaffold.of(context).openDrawer(),
|
||||
icon: const Icon(Symbols.menu),
|
||||
);
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
if (widget.actionButtonBuilder == null &&
|
||||
(widget.keyActionsBuilder != null &&
|
||||
(!hasManage || !showDetailView)))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: IconButton(
|
||||
key: actionsIconButtonKey,
|
||||
onPressed: () {
|
||||
showBlurDialog(
|
||||
context: context,
|
||||
barrierColor: Colors.transparent,
|
||||
builder: (context) => FsDialog(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 32),
|
||||
child: widget.keyActionsBuilder!(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: widget.keyActionsBadge
|
||||
? Badge(
|
||||
child: Icon(Symbols.more_vert,
|
||||
semanticLabel: l10n.s_configure_yk),
|
||||
)
|
||||
: Icon(Symbols.more_vert,
|
||||
semanticLabel: l10n.s_configure_yk),
|
||||
iconSize: 24,
|
||||
tooltip: l10n.s_configure_yk,
|
||||
padding: const EdgeInsets.all(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.actionButtonBuilder != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: widget.actionButtonBuilder!.call(context),
|
||||
),
|
||||
],
|
||||
if (hasManage &&
|
||||
(widget.keyActionsBuilder != null ||
|
||||
widget.detailViewBuilder != null))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: IconButton(
|
||||
key: toggleDetailViewIconButtonKey,
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(_detailViewVisibilityProvider.notifier)
|
||||
.toggleExpanded();
|
||||
},
|
||||
icon: const Icon(Symbols.view_sidebar),
|
||||
iconSize: 24,
|
||||
tooltip: showDetailView
|
||||
? l10n.s_collapse_sidebar
|
||||
: l10n.s_expand_sidebar,
|
||||
padding: const EdgeInsets.all(12),
|
||||
),
|
||||
),
|
||||
if (widget.actionButtonBuilder != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: widget.actionButtonBuilder!.call(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
drawer: hasDrawer ? _buildDrawer(context) : null,
|
||||
body: body,
|
||||
@ -706,23 +748,66 @@ class _AppPageState extends ConsumerState<AppPage> {
|
||||
}
|
||||
}
|
||||
|
||||
class CapabilityBadge extends StatelessWidget {
|
||||
final Capability capability;
|
||||
class _GestureDetectorAppBar extends StatelessWidget
|
||||
implements PreferredSizeWidget {
|
||||
final AppBar appBar;
|
||||
final void Function() onTap;
|
||||
|
||||
const CapabilityBadge(this.capability, {super.key});
|
||||
const _GestureDetectorAppBar({required this.appBar, required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.deferToChild, onTap: onTap, child: appBar);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||
}
|
||||
|
||||
class CapabilityBadge extends ConsumerWidget {
|
||||
final Capability capability;
|
||||
final bool noTooltip;
|
||||
|
||||
const CapabilityBadge(this.capability, {super.key, this.noTooltip = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final text = Text(capability.getDisplayName(l10n));
|
||||
final (fipsCapable, fipsApproved) = ref
|
||||
.watch(currentDeviceDataProvider)
|
||||
.valueOrNull
|
||||
?.info
|
||||
.getFipsStatus(capability) ??
|
||||
(false, false);
|
||||
final label = fipsCapable
|
||||
? Row(
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.shield,
|
||||
color: colorScheme.onSecondaryContainer,
|
||||
size: 12,
|
||||
fill: fipsApproved ? 1 : 0,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
text,
|
||||
],
|
||||
)
|
||||
: text;
|
||||
return Badge(
|
||||
backgroundColor: colorScheme.secondaryContainer,
|
||||
textColor: colorScheme.onSecondaryContainer,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
largeSize: MediaQuery.of(context).textScaler.scale(20),
|
||||
label: Text(
|
||||
capability.getDisplayName(l10n),
|
||||
),
|
||||
label: fipsCapable && !noTooltip
|
||||
? Tooltip(
|
||||
message:
|
||||
fipsApproved ? l10n.l_fips_approved : l10n.l_fips_capable,
|
||||
child: label,
|
||||
)
|
||||
: label,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ const _prefix = 'app.keys';
|
||||
const deviceInfoListTile = Key('$_prefix.device_info_list_tile');
|
||||
const noDeviceAvatar = Key('$_prefix.no_device_avatar');
|
||||
const actionsIconButtonKey = Key('$_prefix.actions_icon_button');
|
||||
const toggleDetailViewIconButtonKey =
|
||||
Key('$_prefix.toggle_detail_view_icon_button');
|
||||
|
||||
// drawer items
|
||||
const homeDrawer = Key('$_prefix.drawer.home');
|
||||
|
@ -71,9 +71,9 @@ class MessagePage extends StatelessWidget {
|
||||
delayedContent: delayedContent,
|
||||
builder: (context, _) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 16.0,
|
||||
left: 18.0,
|
||||
top: 0.0,
|
||||
right: 16.0,
|
||||
right: 18.0,
|
||||
bottom: centered && actionsBuilder == null ? 96 : 0),
|
||||
child: SizedBox(
|
||||
width: centered ? 250 : 350,
|
||||
|
@ -163,6 +163,8 @@ class _ResetDialogState extends ConsumerState<ResetDialog> {
|
||||
_subscription = null;
|
||||
}, onError: (e) {
|
||||
_log.error('Error performing FIDO reset', e);
|
||||
|
||||
if (!context.mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
final String errorMessage;
|
||||
// TODO: Make this cleaner than importing desktop specific RpcError.
|
||||
|
@ -175,7 +175,7 @@ UserInteractionController _dialogUserInteraction(
|
||||
builder: (context) {
|
||||
return PopScope(
|
||||
canPop: onCancel != null,
|
||||
onPopInvoked: (didPop) {
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (didPop) {
|
||||
wasPopped = true;
|
||||
if (!completed && onCancel != null) {
|
||||
|
@ -20,7 +20,9 @@ mixin _$Version {
|
||||
int get minor => throw _privateConstructorUsedError;
|
||||
int get patch => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of Version
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$VersionCopyWith<Version> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
@ -42,6 +44,8 @@ class _$VersionCopyWithImpl<$Res, $Val extends Version>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of Version
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -84,6 +88,8 @@ class __$$VersionImplCopyWithImpl<$Res>
|
||||
_$VersionImpl _value, $Res Function(_$VersionImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of Version
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -140,7 +146,9 @@ class _$VersionImpl extends _Version {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, major, minor, patch);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of Version
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$VersionImplCopyWith<_$VersionImpl> get copyWith =>
|
||||
@ -158,8 +166,11 @@ abstract class _Version extends Version {
|
||||
int get minor;
|
||||
@override
|
||||
int get patch;
|
||||
|
||||
/// Create a copy of Version
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$VersionImplCopyWith<_$VersionImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../app/models.dart';
|
||||
import '../widgets/flex_box.dart';
|
||||
|
||||
bool get isDesktop => const [
|
||||
TargetPlatform.windows,
|
||||
@ -119,3 +120,20 @@ final featureProvider = Provider<FeatureProvider>((ref) {
|
||||
|
||||
return isEnabled;
|
||||
});
|
||||
|
||||
class LayoutNotifier extends StateNotifier<FlexLayout> {
|
||||
final String _key;
|
||||
final SharedPreferences _prefs;
|
||||
LayoutNotifier(this._key, this._prefs)
|
||||
: super(_fromName(_prefs.getString(_key)));
|
||||
|
||||
void setLayout(FlexLayout layout) {
|
||||
state = layout;
|
||||
_prefs.setString(_key, layout.name);
|
||||
}
|
||||
|
||||
static FlexLayout _fromName(String? name) => FlexLayout.values.firstWhere(
|
||||
(element) => element.name == name,
|
||||
orElse: () => FlexLayout.list,
|
||||
);
|
||||
}
|
||||
|
@ -87,15 +87,16 @@ class UsbDeviceNotifier extends StateNotifier<List<UsbYubiKeyNode>> {
|
||||
return;
|
||||
}
|
||||
|
||||
final pids = {
|
||||
for (var e in (scan['pids'] as Map).entries)
|
||||
UsbPid.fromValue(int.parse(e.key)): e.value as int
|
||||
};
|
||||
final numDevices = pids.values.fold<int>(0, (a, b) => a + b);
|
||||
final numDevices =
|
||||
(scan['pids'] as Map).values.fold<int>(0, (a, b) => a + b as int);
|
||||
if (_usbState != scan['state'] || state.length != numDevices) {
|
||||
var usbResult = await rpc.command('get', ['usb']);
|
||||
_log.info('USB state change', jsonEncode(usbResult));
|
||||
_usbState = usbResult['data']['state'];
|
||||
final pids = {
|
||||
for (var e in (usbResult['data']['pids'] as Map).entries)
|
||||
UsbPid.fromValue(int.parse(e.key)): e.value as int
|
||||
};
|
||||
List<UsbYubiKeyNode> usbDevices = [];
|
||||
|
||||
for (String id in (usbResult['children'] as Map).keys) {
|
||||
|
@ -184,6 +184,12 @@ class _DesktopFidoStateNotifier extends FidoStateNotifier {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> enableEnterpriseAttestation() async {
|
||||
await _session.command('enable_ep_attestation');
|
||||
ref.invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
final desktopFingerprintProvider = AsyncNotifierProvider.autoDispose
|
||||
|
@ -81,8 +81,13 @@ mixin _$RpcResponse {
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this RpcResponse to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$RpcResponseCopyWith<RpcResponse> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -106,6 +111,8 @@ class _$RpcResponseCopyWithImpl<$Res, $Val extends RpcResponse>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -139,6 +146,8 @@ class __$$SuccessImplCopyWithImpl<$Res>
|
||||
_$SuccessImpl _value, $Res Function(_$SuccessImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -203,14 +212,16 @@ class _$SuccessImpl implements Success {
|
||||
const DeepCollectionEquality().equals(other._flags, _flags));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_body),
|
||||
const DeepCollectionEquality().hash(_flags));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SuccessImplCopyWith<_$SuccessImpl> get copyWith =>
|
||||
@ -306,8 +317,11 @@ abstract class Success implements RpcResponse {
|
||||
@override
|
||||
Map<String, dynamic> get body;
|
||||
List<String> get flags;
|
||||
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SuccessImplCopyWith<_$SuccessImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -331,6 +345,8 @@ class __$$SignalImplCopyWithImpl<$Res>
|
||||
_$SignalImpl _value, $Res Function(_$SignalImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -388,12 +404,14 @@ class _$SignalImpl implements Signal {
|
||||
const DeepCollectionEquality().equals(other._body, _body));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, status, const DeepCollectionEquality().hash(_body));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SignalImplCopyWith<_$SignalImpl> get copyWith =>
|
||||
@ -489,8 +507,11 @@ abstract class Signal implements RpcResponse {
|
||||
String get status;
|
||||
@override
|
||||
Map<String, dynamic> get body;
|
||||
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SignalImplCopyWith<_$SignalImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -514,6 +535,8 @@ class __$$RpcErrorImplCopyWithImpl<$Res>
|
||||
_$RpcErrorImpl _value, $Res Function(_$RpcErrorImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -579,12 +602,14 @@ class _$RpcErrorImpl implements RpcError {
|
||||
const DeepCollectionEquality().equals(other._body, _body));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, status, message, const DeepCollectionEquality().hash(_body));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$RpcErrorImplCopyWith<_$RpcErrorImpl> get copyWith =>
|
||||
@ -682,8 +707,11 @@ abstract class RpcError implements RpcResponse {
|
||||
String get message;
|
||||
@override
|
||||
Map<String, dynamic> get body;
|
||||
|
||||
/// Create a copy of RpcResponse
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$RpcErrorImplCopyWith<_$RpcErrorImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -697,8 +725,12 @@ mixin _$RpcState {
|
||||
String get version => throw _privateConstructorUsedError;
|
||||
bool get isAdmin => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this RpcState to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of RpcState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$RpcStateCopyWith<RpcState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -721,6 +753,8 @@ class _$RpcStateCopyWithImpl<$Res, $Val extends RpcState>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of RpcState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -759,6 +793,8 @@ class __$$RpcStateImplCopyWithImpl<$Res>
|
||||
_$RpcStateImpl _value, $Res Function(_$RpcStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of RpcState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -805,11 +841,13 @@ class _$RpcStateImpl implements _RpcState {
|
||||
(identical(other.isAdmin, isAdmin) || other.isAdmin == isAdmin));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, version, isAdmin);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of RpcState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$RpcStateImplCopyWith<_$RpcStateImpl> get copyWith =>
|
||||
@ -834,8 +872,11 @@ abstract class _RpcState implements RpcState {
|
||||
String get version;
|
||||
@override
|
||||
bool get isAdmin;
|
||||
|
||||
/// Create a copy of RpcState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$RpcStateImplCopyWith<_$RpcStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ final actions = fido.feature('actions');
|
||||
final actionsPin = actions.feature('pin');
|
||||
final actionsAddFingerprint = actions.feature('addFingerprint');
|
||||
final actionsReset = actions.feature('reset');
|
||||
final enableEnterpriseAttestation =
|
||||
actions.feature('enableEnterpriseAttestation');
|
||||
|
||||
final credentials = fido.feature('credentials');
|
||||
|
||||
|
@ -25,6 +25,8 @@ const _credentialInfo = '$_prefix.credential.info';
|
||||
// Key actions
|
||||
const managePinAction = Key('$_keyAction.manage_pin');
|
||||
const addFingerprintAction = Key('$_keyAction.add_fingerprint');
|
||||
const enableEnterpriseAttestation =
|
||||
Key('$_keyAction.enable_enterprise_attestation');
|
||||
const newPin = Key('$_keyAction.new_pin');
|
||||
const confirmPin = Key('$_keyAction.confirm_pin');
|
||||
const currentPin = Key('$_keyAction.current_pin');
|
||||
|
@ -50,6 +50,8 @@ class FidoState with _$FidoState {
|
||||
bool get forcePinChange => info['force_pin_change'] == true;
|
||||
|
||||
bool get pinBlocked => pinRetries == 0;
|
||||
|
||||
bool? get enterpriseAttestation => info['options']['ep'];
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -24,8 +24,12 @@ mixin _$FidoState {
|
||||
bool get unlocked => throw _privateConstructorUsedError;
|
||||
int? get pinRetries => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this FidoState to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of FidoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$FidoStateCopyWith<FidoState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -48,6 +52,8 @@ class _$FidoStateCopyWithImpl<$Res, $Val extends FidoState>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of FidoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -91,6 +97,8 @@ class __$$FidoStateImplCopyWithImpl<$Res>
|
||||
_$FidoStateImpl _value, $Res Function(_$FidoStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of FidoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -158,12 +166,14 @@ class _$FidoStateImpl extends _FidoState {
|
||||
other.pinRetries == pinRetries));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,
|
||||
const DeepCollectionEquality().hash(_info), unlocked, pinRetries);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of FidoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FidoStateImplCopyWith<_$FidoStateImpl> get copyWith =>
|
||||
@ -193,8 +203,11 @@ abstract class _FidoState extends FidoState {
|
||||
bool get unlocked;
|
||||
@override
|
||||
int? get pinRetries;
|
||||
|
||||
/// Create a copy of FidoState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FidoStateImplCopyWith<_$FidoStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -256,6 +269,9 @@ class _$PinResultCopyWithImpl<$Res, $Val extends PinResult>
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PinResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -272,6 +288,9 @@ class __$$PinSuccessImplCopyWithImpl<$Res>
|
||||
__$$PinSuccessImplCopyWithImpl(
|
||||
_$PinSuccessImpl _value, $Res Function(_$PinSuccessImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PinResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -379,6 +398,8 @@ class __$$PinFailureImplCopyWithImpl<$Res>
|
||||
_$PinFailureImpl _value, $Res Function(_$PinFailureImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PinResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -392,6 +413,8 @@ class __$$PinFailureImplCopyWithImpl<$Res>
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of PinResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$FidoPinFailureReasonCopyWith<$Res> get reason {
|
||||
@ -425,7 +448,9 @@ class _$PinFailureImpl implements _PinFailure {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, reason);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PinResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PinFailureImplCopyWith<_$PinFailureImpl> get copyWith =>
|
||||
@ -498,7 +523,10 @@ abstract class _PinFailure implements PinResult {
|
||||
factory _PinFailure(final FidoPinFailureReason reason) = _$PinFailureImpl;
|
||||
|
||||
FidoPinFailureReason get reason;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PinResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PinFailureImplCopyWith<_$PinFailureImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -562,6 +590,9 @@ class _$FidoPinFailureReasonCopyWithImpl<$Res,
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of FidoPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -581,6 +612,8 @@ class __$$FidoInvalidPinImplCopyWithImpl<$Res>
|
||||
_$FidoInvalidPinImpl _value, $Res Function(_$FidoInvalidPinImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of FidoPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -628,7 +661,9 @@ class _$FidoInvalidPinImpl implements FidoInvalidPin {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, retries, authBlocked);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of FidoPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FidoInvalidPinImplCopyWith<_$FidoInvalidPinImpl> get copyWith =>
|
||||
@ -704,7 +739,10 @@ abstract class FidoInvalidPin implements FidoPinFailureReason {
|
||||
|
||||
int get retries;
|
||||
bool get authBlocked;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of FidoPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FidoInvalidPinImplCopyWith<_$FidoInvalidPinImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -723,6 +761,9 @@ class __$$FidoWeakPinImplCopyWithImpl<$Res>
|
||||
__$$FidoWeakPinImplCopyWithImpl(
|
||||
_$FidoWeakPinImpl _value, $Res Function(_$FidoWeakPinImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of FidoPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -820,8 +861,12 @@ mixin _$Fingerprint {
|
||||
String get templateId => throw _privateConstructorUsedError;
|
||||
String? get name => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this Fingerprint to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of Fingerprint
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$FingerprintCopyWith<Fingerprint> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -845,6 +890,8 @@ class _$FingerprintCopyWithImpl<$Res, $Val extends Fingerprint>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of Fingerprint
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -883,6 +930,8 @@ class __$$FingerprintImplCopyWithImpl<$Res>
|
||||
_$FingerprintImpl _value, $Res Function(_$FingerprintImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of Fingerprint
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -930,11 +979,13 @@ class _$FingerprintImpl extends _Fingerprint {
|
||||
(identical(other.name, name) || other.name == name));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, templateId, name);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of Fingerprint
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FingerprintImplCopyWith<_$FingerprintImpl> get copyWith =>
|
||||
@ -960,8 +1011,11 @@ abstract class _Fingerprint extends Fingerprint {
|
||||
String get templateId;
|
||||
@override
|
||||
String? get name;
|
||||
|
||||
/// Create a copy of Fingerprint
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FingerprintImplCopyWith<_$FingerprintImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1030,6 +1084,9 @@ class _$FingerprintEventCopyWithImpl<$Res, $Val extends FingerprintEvent>
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -1049,6 +1106,8 @@ class __$$EventCaptureImplCopyWithImpl<$Res>
|
||||
_$EventCaptureImpl _value, $Res Function(_$EventCaptureImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1088,7 +1147,9 @@ class _$EventCaptureImpl implements _EventCapture {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, remaining);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$EventCaptureImplCopyWith<_$EventCaptureImpl> get copyWith =>
|
||||
@ -1167,7 +1228,10 @@ abstract class _EventCapture implements FingerprintEvent {
|
||||
factory _EventCapture(final int remaining) = _$EventCaptureImpl;
|
||||
|
||||
int get remaining;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$EventCaptureImplCopyWith<_$EventCaptureImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1191,6 +1255,8 @@ class __$$EventCompleteImplCopyWithImpl<$Res>
|
||||
_$EventCompleteImpl _value, $Res Function(_$EventCompleteImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1204,6 +1270,8 @@ class __$$EventCompleteImplCopyWithImpl<$Res>
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$FingerprintCopyWith<$Res> get fingerprint {
|
||||
@ -1238,7 +1306,9 @@ class _$EventCompleteImpl implements _EventComplete {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, fingerprint);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$EventCompleteImplCopyWith<_$EventCompleteImpl> get copyWith =>
|
||||
@ -1317,7 +1387,10 @@ abstract class _EventComplete implements FingerprintEvent {
|
||||
factory _EventComplete(final Fingerprint fingerprint) = _$EventCompleteImpl;
|
||||
|
||||
Fingerprint get fingerprint;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$EventCompleteImplCopyWith<_$EventCompleteImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1339,6 +1412,8 @@ class __$$EventErrorImplCopyWithImpl<$Res>
|
||||
_$EventErrorImpl _value, $Res Function(_$EventErrorImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1377,7 +1452,9 @@ class _$EventErrorImpl implements _EventError {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, code);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$EventErrorImplCopyWith<_$EventErrorImpl> get copyWith =>
|
||||
@ -1456,7 +1533,10 @@ abstract class _EventError implements FingerprintEvent {
|
||||
factory _EventError(final int code) = _$EventErrorImpl;
|
||||
|
||||
int get code;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of FingerprintEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$EventErrorImplCopyWith<_$EventErrorImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1473,8 +1553,12 @@ mixin _$FidoCredential {
|
||||
String get userName => throw _privateConstructorUsedError;
|
||||
String? get displayName => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this FidoCredential to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of FidoCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$FidoCredentialCopyWith<FidoCredential> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1503,6 +1587,8 @@ class _$FidoCredentialCopyWithImpl<$Res, $Val extends FidoCredential>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of FidoCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1561,6 +1647,8 @@ class __$$FidoCredentialImplCopyWithImpl<$Res>
|
||||
_$FidoCredentialImpl _value, $Res Function(_$FidoCredentialImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of FidoCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1639,12 +1727,14 @@ class _$FidoCredentialImpl implements _FidoCredential {
|
||||
other.displayName == displayName));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, rpId, credentialId, userId, userName, displayName);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of FidoCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FidoCredentialImplCopyWith<_$FidoCredentialImpl> get copyWith =>
|
||||
@ -1680,8 +1770,11 @@ abstract class _FidoCredential implements FidoCredential {
|
||||
String get userName;
|
||||
@override
|
||||
String? get displayName;
|
||||
|
||||
/// Create a copy of FidoCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FidoCredentialImplCopyWith<_$FidoCredentialImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../app/models.dart';
|
||||
import '../core/state.dart';
|
||||
import '../widgets/flex_box.dart';
|
||||
import 'models.dart';
|
||||
|
||||
final passkeysSearchProvider =
|
||||
@ -32,6 +33,11 @@ class PasskeysSearchNotifier extends StateNotifier<String> {
|
||||
}
|
||||
}
|
||||
|
||||
final passkeysLayoutProvider =
|
||||
StateNotifierProvider<LayoutNotifier, FlexLayout>(
|
||||
(ref) => LayoutNotifier('FIDO_PASSKEYS_LAYOUT', ref.watch(prefProvider)),
|
||||
);
|
||||
|
||||
final fidoStateProvider = AsyncNotifierProvider.autoDispose
|
||||
.family<FidoStateNotifier, FidoState, DevicePath>(
|
||||
() => throw UnimplementedError(),
|
||||
@ -41,6 +47,7 @@ abstract class FidoStateNotifier extends ApplicationStateNotifier<FidoState> {
|
||||
Stream<InteractionEvent> reset();
|
||||
Future<PinResult> setPin(String newPin, {String? oldPin});
|
||||
Future<PinResult> unlock(String pin);
|
||||
Future<void> enableEnterpriseAttestation();
|
||||
}
|
||||
|
||||
final fingerprintProvider = AsyncNotifierProvider.autoDispose
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Yubico.
|
||||
* Copyright (C) 2022-2024 Yubico.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -123,6 +123,8 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
});
|
||||
}, onError: (error, stacktrace) {
|
||||
_log.error('Error adding fingerprint', error, stacktrace);
|
||||
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final String errorMessage;
|
||||
@ -255,7 +257,11 @@ class _AddFingerprintDialogState extends ConsumerState<AddFingerprintDialog>
|
||||
});
|
||||
},
|
||||
onFieldSubmitted: (_) {
|
||||
_submit();
|
||||
if (_label.isNotEmpty) {
|
||||
_submit();
|
||||
} else {
|
||||
_nameFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
)
|
||||
|
50
lib/fido/views/enterprise_attestation_dialog.dart
Normal file
50
lib/fido/views/enterprise_attestation_dialog.dart
Normal file
@ -0,0 +1,50 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
import '../state.dart';
|
||||
|
||||
class EnableEnterpriseAttestationDialog extends ConsumerWidget {
|
||||
final DevicePath devicePath;
|
||||
const EnableEnterpriseAttestationDialog(this.devicePath, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.s_enable_ep_attestation),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(fidoStateProvider(devicePath).notifier)
|
||||
.enableEnterpriseAttestation();
|
||||
await ref.read(withContextProvider)((context) async {
|
||||
Navigator.of(context).pop();
|
||||
showMessage(context, l10n.s_ep_attestation_enabled);
|
||||
});
|
||||
},
|
||||
child: Text(l10n.s_enable),
|
||||
),
|
||||
],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l10n.p_enable_ep_attestation_desc),
|
||||
]
|
||||
.map((e) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: e,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ import '../../app/views/app_list_item.dart';
|
||||
import '../../app/views/app_page.dart';
|
||||
import '../../app/views/message_page.dart';
|
||||
import '../../app/views/message_page_not_initialized.dart';
|
||||
import '../../core/models.dart';
|
||||
import '../../core/state.dart';
|
||||
import '../../exception/no_data_exception.dart';
|
||||
import '../../management/models.dart';
|
||||
@ -44,6 +45,14 @@ import 'key_actions.dart';
|
||||
import 'pin_dialog.dart';
|
||||
import 'pin_entry_form.dart';
|
||||
|
||||
List<Capability> _getCapabilities(YubiKeyData deviceData) => [
|
||||
Capability.fido2,
|
||||
if (deviceData.info.config.enabledCapabilities[Transport.usb]! &
|
||||
Capability.piv.value !=
|
||||
0)
|
||||
Capability.piv
|
||||
];
|
||||
|
||||
class FingerprintsScreen extends ConsumerWidget {
|
||||
final YubiKeyData deviceData;
|
||||
|
||||
@ -52,10 +61,11 @@ class FingerprintsScreen extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final capabilities = _getCapabilities(deviceData);
|
||||
return ref.watch(fidoStateProvider(deviceData.node.path)).when(
|
||||
loading: () => AppPage(
|
||||
title: l10n.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
centered: true,
|
||||
delayedContent: true,
|
||||
builder: (context, _) => const CircularProgressIndicator(),
|
||||
@ -64,7 +74,7 @@ class FingerprintsScreen extends ConsumerWidget {
|
||||
if (error is NoDataException) {
|
||||
return MessagePageNotInitialized(
|
||||
title: l10n.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
);
|
||||
}
|
||||
final enabled = deviceData
|
||||
@ -73,7 +83,7 @@ class FingerprintsScreen extends ConsumerWidget {
|
||||
if (Capability.fido2.value & enabled == 0) {
|
||||
return MessagePage(
|
||||
title: l10n.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
header: l10n.s_fido_disabled,
|
||||
message: l10n.l_webauthn_req_fido2,
|
||||
);
|
||||
@ -85,17 +95,17 @@ class FingerprintsScreen extends ConsumerWidget {
|
||||
},
|
||||
data: (fidoState) {
|
||||
return fidoState.unlocked
|
||||
? _FidoUnlockedPage(deviceData.node, fidoState)
|
||||
: _FidoLockedPage(deviceData.node, fidoState);
|
||||
? _FidoUnlockedPage(deviceData, fidoState)
|
||||
: _FidoLockedPage(deviceData, fidoState);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _FidoLockedPage extends ConsumerWidget {
|
||||
final DeviceNode node;
|
||||
final YubiKeyData deviceData;
|
||||
final FidoState state;
|
||||
|
||||
const _FidoLockedPage(this.node, this.state);
|
||||
const _FidoLockedPage(this.deviceData, this.state);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@ -103,6 +113,14 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
final hasActions = hasFeature(features.actions);
|
||||
|
||||
final capabilities = [
|
||||
Capability.fido2,
|
||||
if (deviceData.info.config.enabledCapabilities[Transport.usb]! &
|
||||
Capability.piv.value !=
|
||||
0)
|
||||
Capability.piv
|
||||
];
|
||||
|
||||
if (!state.hasPin) {
|
||||
return MessagePage(
|
||||
actionsBuilder: (context, expanded) => [
|
||||
@ -112,13 +130,14 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
onPressed: () async {
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) => FidoPinDialog(node.path, state));
|
||||
builder: (context) =>
|
||||
FidoPinDialog(deviceData.node.path, state));
|
||||
},
|
||||
avatar: const Icon(Symbols.pin),
|
||||
)
|
||||
],
|
||||
title: l10n.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
header: l10n.s_fingerprints_get_started,
|
||||
message: l10n.p_set_fingerprints_desc,
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
@ -129,7 +148,7 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
if (state.forcePinChange) {
|
||||
return MessagePage(
|
||||
title: l10n.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
header: l10n.s_pin_change_required,
|
||||
message: l10n.l_pin_change_required_desc,
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
@ -141,7 +160,8 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
onPressed: () async {
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) => FidoPinDialog(node.path, state));
|
||||
builder: (context) =>
|
||||
FidoPinDialog(deviceData.node.path, state));
|
||||
},
|
||||
avatar: const Icon(Symbols.pin),
|
||||
)
|
||||
@ -151,25 +171,26 @@ class _FidoLockedPage extends ConsumerWidget {
|
||||
|
||||
return AppPage(
|
||||
title: l10n.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
keyActionsBuilder: hasActions ? _buildActions : null,
|
||||
builder: (context, _) => Column(
|
||||
children: [
|
||||
PinEntryForm(state, node),
|
||||
PinEntryForm(state, deviceData.node),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActions(BuildContext context) =>
|
||||
fingerprintsBuildActions(context, node, state, -1);
|
||||
fingerprintsBuildActions(context, deviceData.node, state, -1);
|
||||
}
|
||||
|
||||
class _FidoUnlockedPage extends ConsumerStatefulWidget {
|
||||
final DeviceNode node;
|
||||
final YubiKeyData deviceData;
|
||||
final FidoState state;
|
||||
|
||||
_FidoUnlockedPage(this.node, this.state) : super(key: ObjectKey(node.path));
|
||||
_FidoUnlockedPage(this.deviceData, this.state)
|
||||
: super(key: ObjectKey(deviceData.node.path));
|
||||
|
||||
@override
|
||||
ConsumerState<ConsumerStatefulWidget> createState() =>
|
||||
@ -184,10 +205,12 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
final hasActions = hasFeature(features.actions);
|
||||
final capabilities = _getCapabilities(widget.deviceData);
|
||||
|
||||
final data = ref.watch(fingerprintProvider(widget.node.path)).asData;
|
||||
final data =
|
||||
ref.watch(fingerprintProvider(widget.deviceData.node.path)).asData;
|
||||
if (data == null) {
|
||||
return _buildLoadingPage(context);
|
||||
return _buildLoadingPage(context, capabilities);
|
||||
}
|
||||
final fingerprints = data.value;
|
||||
if (fingerprints.isEmpty) {
|
||||
@ -200,18 +223,18 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
await showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
AddFingerprintDialog(widget.node.path));
|
||||
AddFingerprintDialog(widget.deviceData.node.path));
|
||||
},
|
||||
avatar: const Icon(Symbols.fingerprint),
|
||||
)
|
||||
],
|
||||
title: l10n.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
header: l10n.s_fingerprints_get_started,
|
||||
message: l10n.l_add_one_or_more_fps,
|
||||
keyActionsBuilder: hasActions
|
||||
? (context) =>
|
||||
fingerprintsBuildActions(context, widget.node, widget.state, 0)
|
||||
? (context) => fingerprintsBuildActions(
|
||||
context, widget.deviceData.node, widget.state, 0)
|
||||
: null,
|
||||
keyActionsBadge: fingerprintsShowActionsNotifier(widget.state),
|
||||
);
|
||||
@ -219,7 +242,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
|
||||
final fingerprint = _selected;
|
||||
return FidoActions(
|
||||
devicePath: widget.node.path,
|
||||
devicePath: widget.deviceData.node.path,
|
||||
actions: (context) => {
|
||||
EscapeIntent: CallbackAction<EscapeIntent>(onInvoke: (intent) {
|
||||
if (_selected != null) {
|
||||
@ -266,7 +289,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
},
|
||||
builder: (context) => AppPage(
|
||||
title: l10n.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
detailViewBuilder: fingerprint != null
|
||||
? (context) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
@ -306,8 +329,8 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
)
|
||||
: null,
|
||||
keyActionsBuilder: hasActions
|
||||
? (context) => fingerprintsBuildActions(
|
||||
context, widget.node, widget.state, fingerprints.length)
|
||||
? (context) => fingerprintsBuildActions(context,
|
||||
widget.deviceData.node, widget.state, fingerprints.length)
|
||||
: null,
|
||||
keyActionsBadge: fingerprintsShowActionsNotifier(widget.state),
|
||||
builder: (context, expanded) {
|
||||
@ -331,24 +354,29 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
}),
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: fingerprints
|
||||
.map((fp) => _FingerprintListItem(
|
||||
fp,
|
||||
expanded: expanded,
|
||||
selected: fp == _selected,
|
||||
))
|
||||
.toList()),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: fingerprints
|
||||
.map((fp) => _FingerprintListItem(
|
||||
fp,
|
||||
expanded: expanded,
|
||||
selected: fp == _selected,
|
||||
))
|
||||
.toList()),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLoadingPage(BuildContext context) => AppPage(
|
||||
Widget _buildLoadingPage(
|
||||
BuildContext context, List<Capability> capabilities) =>
|
||||
AppPage(
|
||||
title: AppLocalizations.of(context)!.s_fingerprints,
|
||||
capabilities: const [Capability.fido2],
|
||||
capabilities: capabilities,
|
||||
centered: true,
|
||||
delayedContent: true,
|
||||
builder: (context, _) => const CircularProgressIndicator(),
|
||||
|
@ -25,6 +25,7 @@ import '../features.dart' as features;
|
||||
import '../keys.dart' as keys;
|
||||
import '../models.dart';
|
||||
import 'add_fingerprint_dialog.dart';
|
||||
import 'enterprise_attestation_dialog.dart';
|
||||
import 'pin_dialog.dart';
|
||||
|
||||
bool passkeysShowActionsNotifier(FidoState state) {
|
||||
@ -50,6 +51,14 @@ Widget _fidoBuildActions(BuildContext context, DeviceNode node, FidoState state,
|
||||
Theme.of(context).colorScheme;
|
||||
final authBlocked = state.pinBlocked;
|
||||
|
||||
final enterpriseAttestation = state.enterpriseAttestation;
|
||||
final showEnterpriseAttestation = enterpriseAttestation != null &&
|
||||
!(state.alwaysUv && !state.hasPin) &&
|
||||
!(!state.unlocked && state.hasPin) &&
|
||||
fingerprints == null;
|
||||
final canEnableEnterpriseAttestation =
|
||||
enterpriseAttestation == false && showEnterpriseAttestation;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
if (fingerprints != null)
|
||||
@ -115,8 +124,27 @@ Widget _fidoBuildActions(BuildContext context, DeviceNode node, FidoState state,
|
||||
}
|
||||
: null,
|
||||
),
|
||||
if (showEnterpriseAttestation)
|
||||
ActionListItem(
|
||||
key: keys.enableEnterpriseAttestation,
|
||||
feature: features.enableEnterpriseAttestation,
|
||||
icon: const Icon(Symbols.local_police),
|
||||
title: l10n.s_ep_attestation,
|
||||
subtitle:
|
||||
enterpriseAttestation ? l10n.s_enabled : l10n.s_disabled,
|
||||
onTap: canEnableEnterpriseAttestation
|
||||
? (context) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
EnableEnterpriseAttestationDialog(node.path),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import '../../exception/no_data_exception.dart';
|
||||
import '../../management/models.dart';
|
||||
import '../../widgets/app_input_decoration.dart';
|
||||
import '../../widgets/app_text_form_field.dart';
|
||||
import '../../widgets/flex_box.dart';
|
||||
import '../../widgets/list_title.dart';
|
||||
import '../features.dart' as features;
|
||||
import '../models.dart';
|
||||
@ -219,6 +220,7 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
late FocusNode searchFocus;
|
||||
late TextEditingController searchController;
|
||||
FidoCredential? _selected;
|
||||
bool _canRequestFocus = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -374,60 +376,103 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
},
|
||||
child: Builder(builder: (context) {
|
||||
child: LayoutBuilder(builder: (context, constraints) {
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
child: AppTextFormField(
|
||||
key: searchField,
|
||||
controller: searchController,
|
||||
focusNode: searchFocus,
|
||||
// Use the default style, but with a smaller font size:
|
||||
style: textTheme.titleMedium
|
||||
?.copyWith(fontSize: textTheme.titleSmall?.fontSize),
|
||||
decoration: AppInputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(48),
|
||||
borderSide: BorderSide(
|
||||
width: 0,
|
||||
style: searchFocus.hasFocus
|
||||
? BorderStyle.solid
|
||||
: BorderStyle.none,
|
||||
final width = constraints.maxWidth;
|
||||
final showLayoutOptions = width > 600;
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final layout = ref.watch(passkeysLayoutProvider);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10.0, vertical: 8.0),
|
||||
child: AppTextFormField(
|
||||
key: searchField,
|
||||
controller: searchController,
|
||||
canRequestFocus: _canRequestFocus,
|
||||
focusNode: searchFocus,
|
||||
// Use the default style, but with a smaller font size:
|
||||
style: textTheme.titleMedium
|
||||
?.copyWith(fontSize: textTheme.titleSmall?.fontSize),
|
||||
decoration: AppInputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(48),
|
||||
borderSide: BorderSide(
|
||||
width: 0,
|
||||
style: searchFocus.hasFocus
|
||||
? BorderStyle.solid
|
||||
: BorderStyle.none,
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.all(16),
|
||||
fillColor: Theme.of(context).hoverColor,
|
||||
filled: true,
|
||||
hintText: l10n.s_search_passkeys,
|
||||
isDense: true,
|
||||
prefixIcon: const Padding(
|
||||
padding: EdgeInsetsDirectional.only(start: 8.0),
|
||||
child: Icon(Icons.search_outlined),
|
||||
),
|
||||
suffixIcons: [
|
||||
if (searchController.text.isNotEmpty)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
iconSize: 16,
|
||||
onPressed: () {
|
||||
searchController.clear();
|
||||
ref
|
||||
.read(passkeysSearchProvider.notifier)
|
||||
.setFilter('');
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
if (searchController.text.isEmpty && showLayoutOptions)
|
||||
...FlexLayout.values.map(
|
||||
(e) => MouseRegion(
|
||||
onEnter: (event) {
|
||||
if (!searchFocus.hasFocus) {
|
||||
setState(() {
|
||||
_canRequestFocus = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
onExit: (event) {
|
||||
setState(() {
|
||||
_canRequestFocus = true;
|
||||
});
|
||||
},
|
||||
child: IconButton(
|
||||
tooltip: e.getDisplayName(l10n),
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(passkeysLayoutProvider.notifier)
|
||||
.setLayout(e);
|
||||
},
|
||||
icon: Icon(
|
||||
e.icon,
|
||||
color: e == layout
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.all(16),
|
||||
fillColor: Theme.of(context).hoverColor,
|
||||
filled: true,
|
||||
hintText: l10n.s_search_passkeys,
|
||||
isDense: true,
|
||||
prefixIcon: const Padding(
|
||||
padding: EdgeInsetsDirectional.only(start: 8.0),
|
||||
child: Icon(Icons.search_outlined),
|
||||
),
|
||||
suffixIcon: searchController.text.isNotEmpty
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
iconSize: 16,
|
||||
onPressed: () {
|
||||
searchController.clear();
|
||||
ref
|
||||
.read(passkeysSearchProvider.notifier)
|
||||
.setFilter('');
|
||||
setState(() {});
|
||||
},
|
||||
)
|
||||
: null,
|
||||
),
|
||||
onChanged: (value) {
|
||||
ref.read(passkeysSearchProvider.notifier).setFilter(value);
|
||||
setState(() {});
|
||||
},
|
||||
textInputAction: TextInputAction.next,
|
||||
onFieldSubmitted: (value) {
|
||||
Focus.of(context).focusInDirection(TraversalDirection.down);
|
||||
},
|
||||
).init(),
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(passkeysSearchProvider.notifier)
|
||||
.setFilter(value);
|
||||
setState(() {});
|
||||
},
|
||||
textInputAction: TextInputAction.next,
|
||||
onFieldSubmitted: (value) {
|
||||
Focus.of(context)
|
||||
.focusInDirection(TraversalDirection.down);
|
||||
},
|
||||
).init(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
@ -483,21 +528,37 @@ class _FidoUnlockedPageState extends ConsumerState<_FidoUnlockedPage> {
|
||||
}),
|
||||
}
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (filteredCredentials.isEmpty)
|
||||
Center(
|
||||
child: Text(l10n.s_no_passkeys),
|
||||
child: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final layout = ref.watch(passkeysLayoutProvider);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (filteredCredentials.isEmpty)
|
||||
Center(
|
||||
child: Text(l10n.s_no_passkeys),
|
||||
),
|
||||
FlexBox<FidoCredential>(
|
||||
items: filteredCredentials,
|
||||
itemBuilder: (cred) => _CredentialListItem(
|
||||
cred,
|
||||
expanded: expanded,
|
||||
selected: _selected == cred,
|
||||
tileColor: layout == FlexLayout.grid
|
||||
? Theme.of(context).hoverColor
|
||||
: null,
|
||||
),
|
||||
layout: layout,
|
||||
cellMinWidth: 265,
|
||||
spacing: layout == FlexLayout.grid ? 4.0 : 0.0,
|
||||
runSpacing: layout == FlexLayout.grid ? 4.0 : 0.0,
|
||||
)
|
||||
],
|
||||
),
|
||||
...filteredCredentials.map(
|
||||
(cred) => _CredentialListItem(
|
||||
cred,
|
||||
expanded: expanded,
|
||||
selected: _selected == cred,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -518,9 +579,10 @@ class _CredentialListItem extends StatelessWidget {
|
||||
final FidoCredential credential;
|
||||
final bool selected;
|
||||
final bool expanded;
|
||||
final Color? tileColor;
|
||||
|
||||
const _CredentialListItem(this.credential,
|
||||
{required this.expanded, required this.selected});
|
||||
{required this.expanded, required this.selected, this.tileColor});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -533,6 +595,7 @@ class _CredentialListItem extends StatelessWidget {
|
||||
backgroundColor: colorScheme.secondary,
|
||||
child: const Icon(Symbols.passkey),
|
||||
),
|
||||
tileColor: tileColor,
|
||||
title: credential.rpId,
|
||||
subtitle: credential.userName,
|
||||
trailing: expanded
|
||||
|
@ -52,6 +52,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
final _currentPinFocus = FocusNode();
|
||||
final _newPinController = TextEditingController();
|
||||
final _newPinFocus = FocusNode();
|
||||
final _confirmPinFocus = FocusNode();
|
||||
String _confirmPin = '';
|
||||
String? _currentPinError;
|
||||
String? _newPinError;
|
||||
@ -68,6 +69,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
_currentPinFocus.dispose();
|
||||
_newPinController.dispose();
|
||||
_newPinFocus.dispose();
|
||||
_confirmPinFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -86,6 +88,9 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
final isValid =
|
||||
currentPinLenOk && newPinLenOk && _newPinController.text == _confirmPin;
|
||||
|
||||
final newPinEnabled = !_isBlocked && currentPinLenOk;
|
||||
final confirmPinEnabled = !_isBlocked && currentPinLenOk && newPinLenOk;
|
||||
|
||||
final deviceData = ref.read(currentDeviceDataProvider).valueOrNull;
|
||||
|
||||
final hasPinComplexity = deviceData?.info.pinComplexity ?? false;
|
||||
@ -148,11 +153,19 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
_isObscureCurrent ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_currentIsWrong = false;
|
||||
});
|
||||
},
|
||||
onFieldSubmitted: (_) {
|
||||
if (_currentPinController.text.length < minPinLength) {
|
||||
_currentPinFocus.requestFocus();
|
||||
} else {
|
||||
_newPinFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
],
|
||||
Text(hasPinComplexity
|
||||
@ -172,31 +185,43 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_new_pin,
|
||||
enabled: !_isBlocked && currentPinLenOk,
|
||||
enabled: newPinEnabled,
|
||||
errorText: _newIsWrong ? _newPinError : null,
|
||||
errorMaxLines: 3,
|
||||
prefixIcon: const Icon(Symbols.pin),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
suffixIcon: ExcludeFocusTraversal(
|
||||
excluding: !newPinEnabled,
|
||||
child: IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_newIsWrong = false;
|
||||
});
|
||||
},
|
||||
onFieldSubmitted: (_) {
|
||||
if (_newPinController.text.length < minPinLength) {
|
||||
_newPinFocus.requestFocus();
|
||||
} else {
|
||||
_confirmPinFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
AppTextFormField(
|
||||
key: confirmPin,
|
||||
initialValue: _confirmPin,
|
||||
focusNode: _confirmPinFocus,
|
||||
maxLength: maxPinLength,
|
||||
inputFormatters: [limitBytesLength(maxPinLength)],
|
||||
buildCounter: buildByteCounterFor(_confirmPin),
|
||||
@ -206,19 +231,22 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_confirm_pin,
|
||||
prefixIcon: const Icon(Symbols.pin),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip:
|
||||
_isObscureConfirm ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
suffixIcon: ExcludeFocusTraversal(
|
||||
excluding: !confirmPinEnabled,
|
||||
child: IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip:
|
||||
_isObscureConfirm ? l10n.s_show_pin : l10n.s_hide_pin,
|
||||
),
|
||||
),
|
||||
enabled: !_isBlocked && currentPinLenOk && newPinLenOk,
|
||||
enabled: confirmPinEnabled,
|
||||
errorText:
|
||||
_newPinController.text.length == _confirmPin.length &&
|
||||
_newPinController.text != _confirmPin
|
||||
@ -226,6 +254,7 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
: null,
|
||||
helperText: '', // Prevents resizing when errorText shown
|
||||
),
|
||||
textInputAction: TextInputAction.done,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_confirmPin = value;
|
||||
@ -234,6 +263,8 @@ class _FidoPinDialogState extends ConsumerState<FidoPinDialog> {
|
||||
onFieldSubmitted: (_) {
|
||||
if (isValid) {
|
||||
_submit();
|
||||
} else {
|
||||
_confirmPinFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Yubico.
|
||||
* Copyright (C) 2022-2024 Yubico.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -41,12 +41,20 @@ class RenameFingerprintDialog extends ConsumerStatefulWidget {
|
||||
|
||||
class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
late String _label;
|
||||
late FocusNode _labelFocus;
|
||||
_RenameAccountDialogState();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_label = widget.fingerprint.name ?? '';
|
||||
_labelFocus = FocusNode();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_labelFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
_submit() async {
|
||||
@ -93,7 +101,9 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
Text(l10n.q_rename_target(widget.fingerprint.label)),
|
||||
Text(l10n.p_will_change_label_fp),
|
||||
AppTextFormField(
|
||||
autofocus: true,
|
||||
initialValue: _label,
|
||||
focusNode: _labelFocus,
|
||||
maxLength: 15,
|
||||
inputFormatters: [limitBytesLength(15)],
|
||||
buildCounter: buildByteCounterFor(_label),
|
||||
@ -110,6 +120,8 @@ class _RenameAccountDialogState extends ConsumerState<RenameFingerprintDialog> {
|
||||
onFieldSubmitted: (_) {
|
||||
if (_label.isNotEmpty) {
|
||||
_submit();
|
||||
} else {
|
||||
_labelFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
|
@ -29,7 +29,6 @@ import '../../app/views/app_page.dart';
|
||||
import '../../core/models.dart';
|
||||
import '../../core/state.dart';
|
||||
import '../../management/models.dart';
|
||||
import '../../widgets/choice_filter_chip.dart';
|
||||
import '../../widgets/product_image.dart';
|
||||
import 'key_actions.dart';
|
||||
import 'manage_label_dialog.dart';
|
||||
@ -72,7 +71,7 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
|
||||
homeBuildActions(context, widget.deviceData, ref),
|
||||
builder: (context, expanded) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -92,16 +91,14 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
|
||||
runSpacing: 8,
|
||||
children: Capability.values
|
||||
.where((c) => enabledCapabilities & c.value != 0)
|
||||
.map((c) => CapabilityBadge(c))
|
||||
.map((c) => CapabilityBadge(c, noTooltip: true))
|
||||
.toList(),
|
||||
),
|
||||
if (serial != null) ...[
|
||||
const SizedBox(height: 32.0),
|
||||
_DeviceColor(
|
||||
deviceData: widget.deviceData,
|
||||
initialCustomization: keyCustomization ??
|
||||
KeyCustomization(serial: serial))
|
||||
]
|
||||
if (widget.deviceData.info.fipsCapable != 0)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 38),
|
||||
child: _FipsLegend(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -131,6 +128,62 @@ class _HomeScreenState extends ConsumerState<HomeScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
class _FipsLegend extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Opacity(
|
||||
opacity: 0.6,
|
||||
child: Wrap(
|
||||
runSpacing: 0,
|
||||
spacing: 16,
|
||||
children: [
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
const WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 4),
|
||||
child: Icon(
|
||||
Symbols.shield,
|
||||
size: 12,
|
||||
fill: 0.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: l10n.l_fips_capable,
|
||||
style: Theme.of(context).textTheme.bodySmall),
|
||||
],
|
||||
),
|
||||
),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: [
|
||||
const WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 4),
|
||||
child: Icon(
|
||||
Symbols.shield,
|
||||
size: 12,
|
||||
fill: 1.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: l10n.l_fips_approved,
|
||||
style: Theme.of(context).textTheme.bodySmall),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DeviceContent extends ConsumerWidget {
|
||||
final YubiKeyData deviceData;
|
||||
final KeyCustomization? initialCustomization;
|
||||
@ -147,6 +200,9 @@ class _DeviceContent extends ConsumerWidget {
|
||||
final label = initialCustomization?.name;
|
||||
String displayName = label != null ? '$label ($name)' : name;
|
||||
|
||||
final defaultColor = ref.watch(defaultColorProvider);
|
||||
final customColor = initialCustomization?.color;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -158,22 +214,114 @@ class _DeviceContent extends ConsumerWidget {
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
if (serial != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: IconButton(
|
||||
icon: const Icon(Symbols.edit),
|
||||
onPressed: () async {
|
||||
await ref.read(withContextProvider)((context) async {
|
||||
await _showManageLabelDialog(
|
||||
initialCustomization ??
|
||||
KeyCustomization(serial: serial),
|
||||
context,
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
if (serial != null) ...[
|
||||
const SizedBox(width: 8),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Symbols.edit),
|
||||
tooltip: l10n.s_set_label,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
onPressed: () async {
|
||||
await ref.read(withContextProvider)((context) async {
|
||||
await _showManageLabelDialog(
|
||||
initialCustomization ??
|
||||
KeyCustomization(serial: serial),
|
||||
context,
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
PopupMenuButton(
|
||||
popUpAnimationStyle:
|
||||
AnimationStyle(duration: Duration.zero),
|
||||
menuPadding: EdgeInsets.zero,
|
||||
tooltip: l10n.s_set_color,
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
child: Center(
|
||||
child: Wrap(
|
||||
runSpacing: 8,
|
||||
spacing: 16,
|
||||
children: [
|
||||
...[
|
||||
Colors.teal,
|
||||
Colors.cyan,
|
||||
Colors.blueAccent,
|
||||
Colors.deepPurple,
|
||||
Colors.red,
|
||||
Colors.orange,
|
||||
Colors.yellow,
|
||||
// add nice color to devices with dynamic color
|
||||
if (isAndroid &&
|
||||
ref.read(androidSdkVersionProvider) >=
|
||||
31)
|
||||
Colors.lightGreen
|
||||
].map((e) => _ColorButton(
|
||||
color: e,
|
||||
isSelected:
|
||||
customColor?.value == e.value,
|
||||
onPressed: () {
|
||||
_updateColor(e, ref, serial);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
)),
|
||||
|
||||
// "use default color" button
|
||||
RawMaterialButton(
|
||||
onPressed: () {
|
||||
_updateColor(null, ref, serial);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
constraints: const BoxConstraints(
|
||||
minWidth: 26.0, minHeight: 26.0),
|
||||
fillColor: defaultColor,
|
||||
hoverColor: Colors.black12,
|
||||
shape: const CircleBorder(),
|
||||
child: Icon(
|
||||
customColor == null
|
||||
? Symbols.circle
|
||||
: Symbols.clear,
|
||||
fill: 1,
|
||||
size: 16,
|
||||
weight: 700,
|
||||
opticalSize: 20,
|
||||
color: defaultColor
|
||||
.computeLuminance() >
|
||||
0.7
|
||||
? Colors.grey // for bright colors
|
||||
: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
];
|
||||
},
|
||||
icon: Icon(
|
||||
Symbols.palette,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 3.0,
|
||||
width: 24.0,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withOpacity(0.9)),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
@ -195,10 +343,42 @@ class _DeviceContent extends ConsumerWidget {
|
||||
.titleSmall
|
||||
?.apply(color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
if (deviceData.info.pinComplexity)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: RichText(
|
||||
text: TextSpan(children: [
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 4),
|
||||
child: Icon(
|
||||
Symbols.check,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
)),
|
||||
TextSpan(
|
||||
text: l10n.l_pin_complexity,
|
||||
style: Theme.of(context).textTheme.titleSmall?.apply(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _updateColor(Color? color, WidgetRef ref, int serial) async {
|
||||
final manager = ref.read(keyCustomizationManagerProvider.notifier);
|
||||
await manager.set(
|
||||
serial: serial,
|
||||
name: initialCustomization?.name,
|
||||
color: color,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showManageLabelDialog(
|
||||
KeyCustomization keyCustomization, BuildContext context) async {
|
||||
await showBlurDialog(
|
||||
@ -210,97 +390,6 @@ class _DeviceContent extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _DeviceColor extends ConsumerWidget {
|
||||
final YubiKeyData deviceData;
|
||||
final KeyCustomization initialCustomization;
|
||||
const _DeviceColor(
|
||||
{required this.deviceData, required this.initialCustomization});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final defaultColor = ref.watch(defaultColorProvider);
|
||||
final customColor = initialCustomization.color;
|
||||
|
||||
return ChoiceFilterChip<Color?>(
|
||||
disableHover: true,
|
||||
value: customColor,
|
||||
items: const [null],
|
||||
selected: customColor != null && customColor.value != defaultColor.value,
|
||||
itemBuilder: (e) => Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
runSpacing: 8,
|
||||
spacing: 16,
|
||||
children: [
|
||||
...[
|
||||
Colors.teal,
|
||||
Colors.cyan,
|
||||
Colors.blueAccent,
|
||||
Colors.deepPurple,
|
||||
Colors.red,
|
||||
Colors.orange,
|
||||
Colors.yellow,
|
||||
// add nice color to devices with dynamic color
|
||||
if (isAndroid && ref.read(androidSdkVersionProvider) >= 31)
|
||||
Colors.lightGreen
|
||||
].map((e) => _ColorButton(
|
||||
color: e,
|
||||
isSelected: customColor?.value == e.value,
|
||||
onPressed: () {
|
||||
_updateColor(e, ref);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
)),
|
||||
|
||||
// "use default color" button
|
||||
RawMaterialButton(
|
||||
onPressed: () {
|
||||
_updateColor(null, ref);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
constraints: const BoxConstraints(minWidth: 26.0, minHeight: 26.0),
|
||||
fillColor: defaultColor,
|
||||
hoverColor: Colors.black12,
|
||||
shape: const CircleBorder(),
|
||||
child: Icon(customColor == null ? Symbols.circle : Symbols.clear,
|
||||
fill: 1,
|
||||
size: 16,
|
||||
weight: 700,
|
||||
opticalSize: 20,
|
||||
color: defaultColor.computeLuminance() > 0.7
|
||||
? Colors.grey // for bright colors
|
||||
: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
labelBuilder: (e) => Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
constraints: const BoxConstraints(minWidth: 22.0, minHeight: 22.0),
|
||||
decoration: BoxDecoration(
|
||||
color: customColor ?? defaultColor, shape: BoxShape.circle),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Flexible(child: Text(l10n.s_color))
|
||||
],
|
||||
),
|
||||
onChanged: (e) {},
|
||||
);
|
||||
}
|
||||
|
||||
void _updateColor(Color? color, WidgetRef ref) async {
|
||||
final manager = ref.read(keyCustomizationManagerProvider.notifier);
|
||||
await manager.set(
|
||||
serial: initialCustomization.serial,
|
||||
name: initialCustomization.name,
|
||||
color: color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ColorButton extends StatefulWidget {
|
||||
final Color? color;
|
||||
final bool isSelected;
|
||||
|
@ -34,6 +34,7 @@ Widget homeBuildActions(
|
||||
BuildContext context, YubiKeyData? deviceData, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
final interfacesLocked = deviceData?.info.resetBlocked != 0;
|
||||
final managementAvailability = hasFeature(features.management) &&
|
||||
switch (deviceData?.info.version) {
|
||||
Version version => (version.major > 4 || // YK5 and up
|
||||
@ -56,16 +57,21 @@ Widget homeBuildActions(
|
||||
title: deviceData.info.version.major > 4
|
||||
? l10n.s_toggle_applications
|
||||
: l10n.s_toggle_interfaces,
|
||||
subtitle: deviceData.info.version.major > 4
|
||||
? l10n.l_toggle_applications_desc
|
||||
: l10n.l_toggle_interfaces_desc,
|
||||
onTap: (context) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) => ManagementScreen(deviceData),
|
||||
);
|
||||
},
|
||||
subtitle: interfacesLocked
|
||||
? l10n.l_factory_reset_required
|
||||
: (deviceData.info.version.major > 4
|
||||
? l10n.l_toggle_applications_desc
|
||||
: l10n.l_toggle_interfaces_desc),
|
||||
onTap: interfacesLocked
|
||||
? null
|
||||
: (context) {
|
||||
Navigator.of(context)
|
||||
.popUntil((route) => route.isFirst);
|
||||
showBlurDialog(
|
||||
context: context,
|
||||
builder: (context) => ManagementScreen(deviceData),
|
||||
);
|
||||
},
|
||||
),
|
||||
if (getResetCapabilities(hasFeature).any((c) =>
|
||||
c.value &
|
||||
|
@ -30,6 +30,9 @@
|
||||
"s_delete": "Löschen",
|
||||
"s_move": null,
|
||||
"s_quit": "Beenden",
|
||||
"s_enable": null,
|
||||
"s_enabled": null,
|
||||
"s_disabled": null,
|
||||
"s_status": null,
|
||||
"s_unlock": "Entsperren",
|
||||
"s_calculate": "Berechnen",
|
||||
@ -45,6 +48,8 @@
|
||||
"s_hide_window": "Fenster verstecken",
|
||||
"s_expand_navigation": null,
|
||||
"s_collapse_navigation": null,
|
||||
"s_expand_sidebar": null,
|
||||
"s_collapse_sidebar": null,
|
||||
"q_rename_target": "{label} umbenennen?",
|
||||
"@q_rename_target": {
|
||||
"placeholders": {
|
||||
@ -121,6 +126,12 @@
|
||||
"s_light_mode": "Heller Modus",
|
||||
"s_dark_mode": "Dunkler Modus",
|
||||
|
||||
"@_layout": {},
|
||||
"s_list_layout": null,
|
||||
"s_grid_layout": null,
|
||||
"s_mixed_layout": null,
|
||||
"s_select_layout": null,
|
||||
|
||||
"@_yubikey_selection": {},
|
||||
"s_select_to_scan": "Zum Scannen auswählen",
|
||||
"s_hide_device": "Gerät verstecken",
|
||||
@ -149,6 +160,8 @@
|
||||
}
|
||||
},
|
||||
"l_firmware_version": null,
|
||||
"l_fips_capable": null,
|
||||
"l_fips_approved": null,
|
||||
|
||||
"@_yubikey_interactions": {},
|
||||
"l_insert_yk": "YubiKey anschließen",
|
||||
@ -301,6 +314,10 @@
|
||||
"common_pin": {}
|
||||
}
|
||||
},
|
||||
"s_ep_attestation": null,
|
||||
"s_ep_attestation_enabled": null,
|
||||
"s_enable_ep_attestation": null,
|
||||
"p_enable_ep_attestation_desc": null,
|
||||
"s_pin_required": null,
|
||||
"p_pin_required_desc": null,
|
||||
"l_piv_pin_blocked": null,
|
||||
@ -330,6 +347,7 @@
|
||||
"l_warning_default_puk": null,
|
||||
"l_default_pin_used": null,
|
||||
"l_default_puk_used": null,
|
||||
"l_pin_complexity": null,
|
||||
|
||||
"@_passwords": {},
|
||||
"s_password": "Passwort",
|
||||
@ -339,6 +357,7 @@
|
||||
"s_show_password": null,
|
||||
"s_hide_password": null,
|
||||
"l_optional_password_protection": "Optionaler Passwortschutz",
|
||||
"l_password_protection": null,
|
||||
"s_new_password": "Neues Passwort",
|
||||
"s_current_password": "Aktuelles Passwort",
|
||||
"s_confirm_password": "Passwort bestätigen",
|
||||
@ -352,6 +371,7 @@
|
||||
"l_keystore_unavailable": "Passwortspeicher des Betriebssystems nicht verfügbar",
|
||||
"l_remember_pw_failed": "Konnte Passwort nicht speichern",
|
||||
"l_unlock_first": "Zuerst mit Passwort entsperren",
|
||||
"l_set_password_first": null,
|
||||
"l_enter_oath_pw": "Das OATH-Passwort für Ihren YubiKey eingeben",
|
||||
"p_enter_current_password_or_reset": "Geben Sie Ihr aktuelles Passwort ein. Wenn Sie Ihr Passwort nicht wissen, müssen Sie den YubiKey zurücksetzen.",
|
||||
"p_enter_new_password": "Geben Sie Ihr neues Passwort ein. Ein Passwort kann Buchstaben, Ziffern und spezielle Zeichen enthalten.",
|
||||
@ -410,6 +430,7 @@
|
||||
"s_pin_account": "Konto anpinnen",
|
||||
"s_unpin_account": "Konto nicht mehr anpinnen",
|
||||
"s_no_pinned_accounts": "Keine angepinnten Konten",
|
||||
"s_pinned": null,
|
||||
"l_pin_account_desc": null,
|
||||
"s_rename_account": "Konto umbenennen",
|
||||
"l_rename_account_desc": null,
|
||||
@ -635,7 +656,9 @@
|
||||
"p_subject_desc": null,
|
||||
"l_rfc4514_invalid": null,
|
||||
"rfc4514_examples": null,
|
||||
"s_allow_fingerprint": null,
|
||||
"p_cert_options_desc": null,
|
||||
"p_cert_options_bio_desc": null,
|
||||
"s_overwrite_slot": null,
|
||||
"p_overwrite_slot_desc": null,
|
||||
"@p_overwrite_slot_desc": {
|
||||
@ -778,6 +801,7 @@
|
||||
"s_reset": "Zurücksetzen",
|
||||
"s_factory_reset": "Werkseinstellungen",
|
||||
"l_factory_reset_desc": null,
|
||||
"l_factory_reset_required": null,
|
||||
"l_oath_application_reset": "OATH Anwendung zurücksetzen",
|
||||
"l_fido_app_reset": "FIDO Anwendung zurückgesetzt",
|
||||
"l_reset_failed": "Fehler beim Zurücksetzen: {message}",
|
||||
@ -885,6 +909,7 @@
|
||||
|
||||
"@_key_customization": {},
|
||||
"s_set_label": null,
|
||||
"s_set_color": null,
|
||||
"s_change_label": null,
|
||||
"s_color": null,
|
||||
"p_set_will_add_custom_name": null,
|
||||
|
@ -30,6 +30,9 @@
|
||||
"s_delete": "Delete",
|
||||
"s_move": "Move",
|
||||
"s_quit": "Quit",
|
||||
"s_enable": "Enable",
|
||||
"s_enabled": "Enabled",
|
||||
"s_disabled": "Disabled",
|
||||
"s_status": "Status",
|
||||
"s_unlock": "Unlock",
|
||||
"s_calculate": "Calculate",
|
||||
@ -45,6 +48,8 @@
|
||||
"s_hide_window": "Hide window",
|
||||
"s_expand_navigation": "Expand navigation",
|
||||
"s_collapse_navigation": "Collapse navigation",
|
||||
"s_expand_sidebar": "Expand sidebar",
|
||||
"s_collapse_sidebar": "Collapse sidebar",
|
||||
"q_rename_target": "Rename {label}?",
|
||||
"@q_rename_target": {
|
||||
"placeholders": {
|
||||
@ -121,6 +126,12 @@
|
||||
"s_light_mode": "Light mode",
|
||||
"s_dark_mode": "Dark mode",
|
||||
|
||||
"@_layout": {},
|
||||
"s_list_layout": "List layout",
|
||||
"s_grid_layout": "Grid layout",
|
||||
"s_mixed_layout": "Mixed layout",
|
||||
"s_select_layout": "Select layout",
|
||||
|
||||
"@_yubikey_selection": {},
|
||||
"s_select_to_scan": "Select to scan",
|
||||
"s_hide_device": "Hide device",
|
||||
@ -149,6 +160,8 @@
|
||||
}
|
||||
},
|
||||
"l_firmware_version": "Firmware version: {version}",
|
||||
"l_fips_capable": "FIPS capable",
|
||||
"l_fips_approved": "FIPS approved",
|
||||
|
||||
"@_yubikey_interactions": {},
|
||||
"l_insert_yk": "Insert your YubiKey",
|
||||
@ -301,6 +314,10 @@
|
||||
"common_pin": {}
|
||||
}
|
||||
},
|
||||
"s_ep_attestation": "Enterprise Attestation",
|
||||
"s_ep_attestation_enabled": "Enterprise Attestation enabled",
|
||||
"s_enable_ep_attestation": "Enable Enterprise Attestation",
|
||||
"p_enable_ep_attestation_desc": "This will enable Enterprise Attestation, allowing authorized domains to uniquely identify your YubiKey.",
|
||||
"s_pin_required": "PIN required",
|
||||
"p_pin_required_desc": "The action you are about to perform requires the PIV PIN to be entered.",
|
||||
"l_piv_pin_blocked": "Blocked, use PUK to reset",
|
||||
@ -330,6 +347,7 @@
|
||||
"l_warning_default_puk": "Warning: Default PUK used",
|
||||
"l_default_pin_used": "Default PIN used",
|
||||
"l_default_puk_used": "Default PUK used",
|
||||
"l_pin_complexity": "PIN complexity enforced",
|
||||
|
||||
"@_passwords": {},
|
||||
"s_password": "Password",
|
||||
@ -339,6 +357,7 @@
|
||||
"s_show_password": "Show password",
|
||||
"s_hide_password": "Hide password",
|
||||
"l_optional_password_protection": "Optional password protection",
|
||||
"l_password_protection": "Password protection of accounts",
|
||||
"s_new_password": "New password",
|
||||
"s_current_password": "Current password",
|
||||
"s_confirm_password": "Confirm password",
|
||||
@ -352,6 +371,7 @@
|
||||
"l_keystore_unavailable": "OS Keystore unavailable",
|
||||
"l_remember_pw_failed": "Failed to remember password",
|
||||
"l_unlock_first": "Unlock with password first",
|
||||
"l_set_password_first": "Set a password first",
|
||||
"l_enter_oath_pw": "Enter the OATH password for your YubiKey",
|
||||
"p_enter_current_password_or_reset": "Enter your current password. If you don't know your password, you'll need to reset the YubiKey.",
|
||||
"p_enter_new_password": "Enter your new password. A password may contain letters, numbers and special characters.",
|
||||
@ -410,6 +430,7 @@
|
||||
"s_pin_account": "Pin account",
|
||||
"s_unpin_account": "Unpin account",
|
||||
"s_no_pinned_accounts": "No pinned accounts",
|
||||
"s_pinned": "Pinned",
|
||||
"l_pin_account_desc": "Keep your important accounts together",
|
||||
"s_rename_account": "Rename account",
|
||||
"l_rename_account_desc": "Edit the issuer/name of the account",
|
||||
@ -635,7 +656,9 @@
|
||||
"p_subject_desc": "A distinguished name (DN) formatted in accordance to the RFC 4514 specification.",
|
||||
"l_rfc4514_invalid": "Invalid RFC 4514 format",
|
||||
"rfc4514_examples": "Examples:\nCN=Example Name\nCN=jsmith,DC=example,DC=net",
|
||||
"s_allow_fingerprint": "Allow fingerprint",
|
||||
"p_cert_options_desc": "Key algorithm to use, output format, and expiration date (certificate only).",
|
||||
"p_cert_options_bio_desc": "Key algorithm to use, output format, expiration date (certificate only), and if biometrics can be used instead of PIN.",
|
||||
"s_overwrite_slot": "Overwrite slot",
|
||||
"p_overwrite_slot_desc": "This will permanently overwrite existing content in slot {slot}.",
|
||||
"@p_overwrite_slot_desc": {
|
||||
@ -778,6 +801,7 @@
|
||||
"s_reset": "Reset",
|
||||
"s_factory_reset": "Factory reset",
|
||||
"l_factory_reset_desc": "Restore YubiKey defaults",
|
||||
"l_factory_reset_required": "Factory reset required",
|
||||
"l_oath_application_reset": "OATH application reset",
|
||||
"l_fido_app_reset": "FIDO application reset",
|
||||
"l_reset_failed": "Error performing reset: {message}",
|
||||
@ -885,6 +909,7 @@
|
||||
|
||||
"@_key_customization": {},
|
||||
"s_set_label": "Set label",
|
||||
"s_set_color": "Set color",
|
||||
"s_change_label": "Change label",
|
||||
"s_color": "Color",
|
||||
"p_set_will_add_custom_name": "This will give your YubiKey a custom name.",
|
||||
|
@ -30,6 +30,9 @@
|
||||
"s_delete": "Supprimer",
|
||||
"s_move": "Déplacer",
|
||||
"s_quit": "Quitter",
|
||||
"s_enable": null,
|
||||
"s_enabled": null,
|
||||
"s_disabled": null,
|
||||
"s_status": "État",
|
||||
"s_unlock": "Déverrouiller",
|
||||
"s_calculate": "Calculer",
|
||||
@ -45,6 +48,8 @@
|
||||
"s_hide_window": "Masquer fenêtre",
|
||||
"s_expand_navigation": "Développer la navigation",
|
||||
"s_collapse_navigation": "Réduire la navigation",
|
||||
"s_expand_sidebar": null,
|
||||
"s_collapse_sidebar": null,
|
||||
"q_rename_target": "Renommer {label}\u00a0?",
|
||||
"@q_rename_target": {
|
||||
"placeholders": {
|
||||
@ -121,6 +126,12 @@
|
||||
"s_light_mode": "Thème clair",
|
||||
"s_dark_mode": "Thème sombre",
|
||||
|
||||
"@_layout": {},
|
||||
"s_list_layout": null,
|
||||
"s_grid_layout": null,
|
||||
"s_mixed_layout": null,
|
||||
"s_select_layout": null,
|
||||
|
||||
"@_yubikey_selection": {},
|
||||
"s_select_to_scan": "Sélectionner pour scanner",
|
||||
"s_hide_device": "Masquer appareil",
|
||||
@ -149,6 +160,8 @@
|
||||
}
|
||||
},
|
||||
"l_firmware_version": "Version du firmware : {version}",
|
||||
"l_fips_capable": null,
|
||||
"l_fips_approved": null,
|
||||
|
||||
"@_yubikey_interactions": {},
|
||||
"l_insert_yk": "Insérez votre YubiKey",
|
||||
@ -301,6 +314,10 @@
|
||||
"common_pin": {}
|
||||
}
|
||||
},
|
||||
"s_ep_attestation": null,
|
||||
"s_ep_attestation_enabled": null,
|
||||
"s_enable_ep_attestation": null,
|
||||
"p_enable_ep_attestation_desc": null,
|
||||
"s_pin_required": "PIN requis",
|
||||
"p_pin_required_desc": "L'action que vous allez effectuer nécessite la saisie du PIN PIV.",
|
||||
"l_piv_pin_blocked": "Bloqué, utilisez PUK pour réinitialiser",
|
||||
@ -330,6 +347,7 @@
|
||||
"l_warning_default_puk": "Attention : PUK par défaut utilisé",
|
||||
"l_default_pin_used": "Code PIN par défaut utilisé",
|
||||
"l_default_puk_used": "PUK par défaut utilisé",
|
||||
"l_pin_complexity": null,
|
||||
|
||||
"@_passwords": {},
|
||||
"s_password": "Mot de passe",
|
||||
@ -339,6 +357,7 @@
|
||||
"s_show_password": "Montrer mot de passe",
|
||||
"s_hide_password": "Masquer mot de passe",
|
||||
"l_optional_password_protection": "Protection par mot de passe facultative",
|
||||
"l_password_protection": null,
|
||||
"s_new_password": "Nouveau mot de passe",
|
||||
"s_current_password": "Mot de passe actuel",
|
||||
"s_confirm_password": "Confirmer mot de passe",
|
||||
@ -352,6 +371,7 @@
|
||||
"l_keystore_unavailable": "OS Keystore indisponible",
|
||||
"l_remember_pw_failed": "Mémorisation mot de passe impossible",
|
||||
"l_unlock_first": "Débloquez d'abord avec mot de passe",
|
||||
"l_set_password_first": null,
|
||||
"l_enter_oath_pw": "Saisissez le mot de passe OATH de votre YubiKey",
|
||||
"p_enter_current_password_or_reset": "Saisissez votre mot de passe actuel. Vous ne connaissez votre mot de passe\u00a0? Réinitialisez la YubiKey.",
|
||||
"p_enter_new_password": "Saisissez votre nouveau mot de passe. Un mot de passe peut inclure des lettres, chiffres et caractères spéciaux.",
|
||||
@ -410,6 +430,7 @@
|
||||
"s_pin_account": "Épingler compte",
|
||||
"s_unpin_account": "Détacher compte",
|
||||
"s_no_pinned_accounts": "Aucun compte épinglé",
|
||||
"s_pinned": null,
|
||||
"l_pin_account_desc": "Conserver vos comptes importants ensemble",
|
||||
"s_rename_account": "Renommer compte",
|
||||
"l_rename_account_desc": "Modifier émetteur/nom du compte",
|
||||
@ -635,7 +656,9 @@
|
||||
"p_subject_desc": "DN (nom distinctif) formaté conformément à la spécification RFC 4514.",
|
||||
"l_rfc4514_invalid": "Format RFC 4514 non valide",
|
||||
"rfc4514_examples": "Exemples\u00a0:\nCN=exemple de nom\nCN=jsmith,DC=exemple,DC=net",
|
||||
"s_allow_fingerprint": null,
|
||||
"p_cert_options_desc": "Algorithme clé à utiliser, format de sortie et date d'expiration (certificat uniquement).",
|
||||
"p_cert_options_bio_desc": null,
|
||||
"s_overwrite_slot": "Écraser slot",
|
||||
"p_overwrite_slot_desc": "Cela écrasera définitivement le contenu du slot {slot}.",
|
||||
"@p_overwrite_slot_desc": {
|
||||
@ -778,6 +801,7 @@
|
||||
"s_reset": "Réinitialiser",
|
||||
"s_factory_reset": "Réinitialisation usine",
|
||||
"l_factory_reset_desc": "Restaurer les paramètres par défaut de la YubiKey",
|
||||
"l_factory_reset_required": null,
|
||||
"l_oath_application_reset": "Réinitialisation OATH",
|
||||
"l_fido_app_reset": "Réinitialisation FIDO",
|
||||
"l_reset_failed": "Erreur de réinitialisation\u00a0: {message}",
|
||||
@ -885,6 +909,7 @@
|
||||
|
||||
"@_key_customization": {},
|
||||
"s_set_label": "Définir l'étiquette",
|
||||
"s_set_color": null,
|
||||
"s_change_label": "Modifier l'étiquette",
|
||||
"s_color": "Couleur",
|
||||
"p_set_will_add_custom_name": "Cela donnera un nom personnalisé à votre YubiKey.",
|
||||
|
@ -30,6 +30,9 @@
|
||||
"s_delete": "削除",
|
||||
"s_move": "移動",
|
||||
"s_quit": "終了",
|
||||
"s_enable": null,
|
||||
"s_enabled": null,
|
||||
"s_disabled": null,
|
||||
"s_status": "ステータス",
|
||||
"s_unlock": "ロック解除",
|
||||
"s_calculate": "計算",
|
||||
@ -45,6 +48,8 @@
|
||||
"s_hide_window": "ウィンドウを非表示",
|
||||
"s_expand_navigation": "ナビゲーションを展開",
|
||||
"s_collapse_navigation": "ナビゲーションを閉じる",
|
||||
"s_expand_sidebar": null,
|
||||
"s_collapse_sidebar": null,
|
||||
"q_rename_target": "{label}の名前を変更しますか?",
|
||||
"@q_rename_target": {
|
||||
"placeholders": {
|
||||
@ -121,6 +126,12 @@
|
||||
"s_light_mode": "ライトモード",
|
||||
"s_dark_mode": "ダークモード",
|
||||
|
||||
"@_layout": {},
|
||||
"s_list_layout": null,
|
||||
"s_grid_layout": null,
|
||||
"s_mixed_layout": null,
|
||||
"s_select_layout": null,
|
||||
|
||||
"@_yubikey_selection": {},
|
||||
"s_select_to_scan": "選択してスキャン",
|
||||
"s_hide_device": "デバイスを非表示",
|
||||
@ -149,6 +160,8 @@
|
||||
}
|
||||
},
|
||||
"l_firmware_version": "ファームウェアバージョン: {version}",
|
||||
"l_fips_capable": null,
|
||||
"l_fips_approved": null,
|
||||
|
||||
"@_yubikey_interactions": {},
|
||||
"l_insert_yk": "YubiKeyを挿入してください",
|
||||
@ -301,6 +314,10 @@
|
||||
"common_pin": {}
|
||||
}
|
||||
},
|
||||
"s_ep_attestation": null,
|
||||
"s_ep_attestation_enabled": null,
|
||||
"s_enable_ep_attestation": null,
|
||||
"p_enable_ep_attestation_desc": null,
|
||||
"s_pin_required": "PINが必要",
|
||||
"p_pin_required_desc": "実行しようとしているアクションでは、PIV PINを入力する必要があります。",
|
||||
"l_piv_pin_blocked": "ブロックされています。リセットするにはPUKを使用してください",
|
||||
@ -330,6 +347,7 @@
|
||||
"l_warning_default_puk": "警告: デフォルトのPUKが使用されています",
|
||||
"l_default_pin_used": "デフォルトのPINが使用されています",
|
||||
"l_default_puk_used": "既定のPUKを使用",
|
||||
"l_pin_complexity": null,
|
||||
|
||||
"@_passwords": {},
|
||||
"s_password": "パスワード",
|
||||
@ -339,6 +357,7 @@
|
||||
"s_show_password": "パスワードを表示",
|
||||
"s_hide_password": "パスワードを非表示",
|
||||
"l_optional_password_protection": "オプションのパスワード保護",
|
||||
"l_password_protection": null,
|
||||
"s_new_password": "新しいパスワード",
|
||||
"s_current_password": "現在のパスワード",
|
||||
"s_confirm_password": "パスワードを確認",
|
||||
@ -352,6 +371,7 @@
|
||||
"l_keystore_unavailable": "OSのキーストアを利用できません",
|
||||
"l_remember_pw_failed": "パスワードを記憶できませんでした",
|
||||
"l_unlock_first": "最初にパスワードでロックを解除",
|
||||
"l_set_password_first": null,
|
||||
"l_enter_oath_pw": "YubiKeyのOATHパスワードを入力",
|
||||
"p_enter_current_password_or_reset": "現在のパスワードを入力してください。パスワードがわからない場合は、YubiKeyをリセットする必要があります。",
|
||||
"p_enter_new_password": "新しいパスワードを入力してください。パスワードには文字、数字、特殊文字を含めることができます。",
|
||||
@ -410,6 +430,7 @@
|
||||
"s_pin_account": "アカウントをピン留めする",
|
||||
"s_unpin_account": "アカウントのピン留めを解除",
|
||||
"s_no_pinned_accounts": "ピン留めされたアカウントはありません",
|
||||
"s_pinned": null,
|
||||
"l_pin_account_desc": "重要なアカウントをまとめて保持",
|
||||
"s_rename_account": "アカウント名を変更",
|
||||
"l_rename_account_desc": "アカウントの発行者/名前を編集",
|
||||
@ -635,7 +656,9 @@
|
||||
"p_subject_desc": "RFC 4514仕様に準拠した形式の識別名(DN)。",
|
||||
"l_rfc4514_invalid": "無効なRFC 4514形式",
|
||||
"rfc4514_examples": "例:\nCN=Example Name CN=jsmith,DC=example,\nDC=net",
|
||||
"s_allow_fingerprint": null,
|
||||
"p_cert_options_desc": "使用する鍵アルゴリズム、出力形式、および有効期限(証明書のみ)。",
|
||||
"p_cert_options_bio_desc": null,
|
||||
"s_overwrite_slot": "スロットを上書き",
|
||||
"p_overwrite_slot_desc": "これにより、スロット{slot}内の既存コンテンツが完全に上書きされます。",
|
||||
"@p_overwrite_slot_desc": {
|
||||
@ -778,6 +801,7 @@
|
||||
"s_reset": "リセット",
|
||||
"s_factory_reset": "工場出荷時の状態にリセット",
|
||||
"l_factory_reset_desc": "YubiKey の既定値を復元",
|
||||
"l_factory_reset_required": null,
|
||||
"l_oath_application_reset": "OATHアプリケーションのリセット",
|
||||
"l_fido_app_reset": "FIDOアプリケーションのリセット",
|
||||
"l_reset_failed": "リセットの実行エラー:{message}",
|
||||
@ -885,6 +909,7 @@
|
||||
|
||||
"@_key_customization": {},
|
||||
"s_set_label": "ラベルを設定",
|
||||
"s_set_color": null,
|
||||
"s_change_label": "ラベルを変更",
|
||||
"s_color": "色",
|
||||
"p_set_will_add_custom_name": "これにより、YubiKey にカスタム名を付けることができます。",
|
||||
|
@ -30,6 +30,9 @@
|
||||
"s_delete": "Usuń",
|
||||
"s_move": null,
|
||||
"s_quit": "Wyjdź",
|
||||
"s_enable": null,
|
||||
"s_enabled": null,
|
||||
"s_disabled": null,
|
||||
"s_status": "Status",
|
||||
"s_unlock": "Odblokuj",
|
||||
"s_calculate": "Oblicz",
|
||||
@ -45,6 +48,8 @@
|
||||
"s_hide_window": "Ukryj okno",
|
||||
"s_expand_navigation": null,
|
||||
"s_collapse_navigation": null,
|
||||
"s_expand_sidebar": null,
|
||||
"s_collapse_sidebar": null,
|
||||
"q_rename_target": "Zmienić nazwę {label}?",
|
||||
"@q_rename_target": {
|
||||
"placeholders": {
|
||||
@ -121,6 +126,12 @@
|
||||
"s_light_mode": "Jasny",
|
||||
"s_dark_mode": "Ciemny",
|
||||
|
||||
"@_layout": {},
|
||||
"s_list_layout": null,
|
||||
"s_grid_layout": null,
|
||||
"s_mixed_layout": null,
|
||||
"s_select_layout": null,
|
||||
|
||||
"@_yubikey_selection": {},
|
||||
"s_select_to_scan": "Wybierz, aby skanować",
|
||||
"s_hide_device": "Ukryj urządzenie",
|
||||
@ -149,6 +160,8 @@
|
||||
}
|
||||
},
|
||||
"l_firmware_version": null,
|
||||
"l_fips_capable": null,
|
||||
"l_fips_approved": null,
|
||||
|
||||
"@_yubikey_interactions": {},
|
||||
"l_insert_yk": "Podłącz klucz YubiKey",
|
||||
@ -301,6 +314,10 @@
|
||||
"common_pin": {}
|
||||
}
|
||||
},
|
||||
"s_ep_attestation": null,
|
||||
"s_ep_attestation_enabled": null,
|
||||
"s_enable_ep_attestation": null,
|
||||
"p_enable_ep_attestation_desc": null,
|
||||
"s_pin_required": "Wymagany PIN",
|
||||
"p_pin_required_desc": "Czynność, którą zamierzasz wykonać, wymaga wprowadzenia kodu PIN PIV.",
|
||||
"l_piv_pin_blocked": "Zablokowano, użyj PUK, aby zresetować",
|
||||
@ -330,6 +347,7 @@
|
||||
"l_warning_default_puk": null,
|
||||
"l_default_pin_used": null,
|
||||
"l_default_puk_used": null,
|
||||
"l_pin_complexity": null,
|
||||
|
||||
"@_passwords": {},
|
||||
"s_password": "Hasło",
|
||||
@ -339,6 +357,7 @@
|
||||
"s_show_password": "Pokaż hasło",
|
||||
"s_hide_password": "Ukryj hasło",
|
||||
"l_optional_password_protection": "Opcjonalna ochrona hasłem",
|
||||
"l_password_protection": null,
|
||||
"s_new_password": "Nowe hasło",
|
||||
"s_current_password": "Aktualne hasło",
|
||||
"s_confirm_password": "Potwierdź hasło",
|
||||
@ -352,6 +371,7 @@
|
||||
"l_keystore_unavailable": "Magazyn kluczy systemu operacyjnego jest niedostępny",
|
||||
"l_remember_pw_failed": "Nie udało się zapamiętać hasła",
|
||||
"l_unlock_first": "Najpierw odblokuj hasłem",
|
||||
"l_set_password_first": null,
|
||||
"l_enter_oath_pw": "Wprowadź hasło OATH dla klucza YubiKey",
|
||||
"p_enter_current_password_or_reset": "Wprowadź aktualne hasło. Jeśli go nie znasz, musisz zresetować klucz YubiKey.",
|
||||
"p_enter_new_password": "Wprowadź nowe hasło. Może ono zawierać litery, cyfry i znaki specjalne.",
|
||||
@ -410,6 +430,7 @@
|
||||
"s_pin_account": "Przypnij konto",
|
||||
"s_unpin_account": "Odepnij konto",
|
||||
"s_no_pinned_accounts": "Brak przypiętych kont",
|
||||
"s_pinned": null,
|
||||
"l_pin_account_desc": "Przechowuj ważne konta razem",
|
||||
"s_rename_account": "Zmień nazwę konta",
|
||||
"l_rename_account_desc": "Edytuj wydawcę/nazwę konta",
|
||||
@ -635,7 +656,9 @@
|
||||
"p_subject_desc": "Nazwa wyróżniająca (DN) sformatowana zgodnie ze specyfikacją RFC 4514.",
|
||||
"l_rfc4514_invalid": "Nieprawidłowy format RFC 4514",
|
||||
"rfc4514_examples": "Przykłady:\nCN=Przykładowa Nazwa\nCN=jkowalski,DC=przyklad,DC=pl",
|
||||
"s_allow_fingerprint": null,
|
||||
"p_cert_options_desc": "Algorytm klucza do użycia, format wyjściowy i data wygaśnięcia (tylko certyfikat).",
|
||||
"p_cert_options_bio_desc": null,
|
||||
"s_overwrite_slot": "Nadpisz slot",
|
||||
"p_overwrite_slot_desc": "Spowoduje to trwałe nadpisanie istniejącej zawartości w slocie {slot}.",
|
||||
"@p_overwrite_slot_desc": {
|
||||
@ -778,6 +801,7 @@
|
||||
"s_reset": "Zresetuj",
|
||||
"s_factory_reset": "Ustawienia fabryczne",
|
||||
"l_factory_reset_desc": null,
|
||||
"l_factory_reset_required": null,
|
||||
"l_oath_application_reset": "Reset funkcji OATH",
|
||||
"l_fido_app_reset": "Reset funkcji FIDO",
|
||||
"l_reset_failed": "Błąd podczas resetowania: {message}",
|
||||
@ -885,6 +909,7 @@
|
||||
|
||||
"@_key_customization": {},
|
||||
"s_set_label": null,
|
||||
"s_set_color": null,
|
||||
"s_change_label": null,
|
||||
"s_color": null,
|
||||
"p_set_will_add_custom_name": null,
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import 'dart:developer' as developer;
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
@ -27,6 +28,7 @@ import 'app/state.dart';
|
||||
import 'core/state.dart';
|
||||
import 'desktop/init.dart' as desktop;
|
||||
import 'error_page.dart';
|
||||
import 'version.dart';
|
||||
|
||||
final _log = Logger('main');
|
||||
|
||||
@ -43,6 +45,12 @@ void main(List<String> argv) async {
|
||||
_initializeDebugLogging();
|
||||
throw UnimplementedError('Platform not supported');
|
||||
}
|
||||
_log.info('Running Yubico Authenticator...', {
|
||||
'app_version': version,
|
||||
'dart': Platform.version,
|
||||
'os': Platform.operatingSystem,
|
||||
'os_version': Platform.operatingSystemVersion,
|
||||
});
|
||||
runApp(initializedApp);
|
||||
} catch (e) {
|
||||
_log.warning('Platform initialization failed: $e');
|
||||
|
@ -26,8 +26,12 @@ mixin _$DeviceConfig {
|
||||
int? get challengeResponseTimeout => throw _privateConstructorUsedError;
|
||||
int? get deviceFlags => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this DeviceConfig to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of DeviceConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$DeviceConfigCopyWith<DeviceConfig> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -55,6 +59,8 @@ class _$DeviceConfigCopyWithImpl<$Res, $Val extends DeviceConfig>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of DeviceConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -107,6 +113,8 @@ class __$$DeviceConfigImplCopyWithImpl<$Res>
|
||||
_$DeviceConfigImpl _value, $Res Function(_$DeviceConfigImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of DeviceConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -183,7 +191,7 @@ class _$DeviceConfigImpl implements _DeviceConfig {
|
||||
other.deviceFlags == deviceFlags));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
@ -192,7 +200,9 @@ class _$DeviceConfigImpl implements _DeviceConfig {
|
||||
challengeResponseTimeout,
|
||||
deviceFlags);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of DeviceConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$DeviceConfigImplCopyWith<_$DeviceConfigImpl> get copyWith =>
|
||||
@ -224,8 +234,11 @@ abstract class _DeviceConfig implements DeviceConfig {
|
||||
int? get challengeResponseTimeout;
|
||||
@override
|
||||
int? get deviceFlags;
|
||||
|
||||
/// Create a copy of DeviceConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$DeviceConfigImplCopyWith<_$DeviceConfigImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -250,8 +263,12 @@ mixin _$DeviceInfo {
|
||||
int get fipsApproved => throw _privateConstructorUsedError;
|
||||
int get resetBlocked => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this DeviceInfo to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of DeviceInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$DeviceInfoCopyWith<DeviceInfo> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -290,6 +307,8 @@ class _$DeviceInfoCopyWithImpl<$Res, $Val extends DeviceInfo>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of DeviceInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -358,6 +377,8 @@ class _$DeviceInfoCopyWithImpl<$Res, $Val extends DeviceInfo>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of DeviceInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$DeviceConfigCopyWith<$Res> get config {
|
||||
@ -366,6 +387,8 @@ class _$DeviceInfoCopyWithImpl<$Res, $Val extends DeviceInfo>
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of DeviceInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$VersionCopyWith<$Res> get version {
|
||||
@ -411,6 +434,8 @@ class __$$DeviceInfoImplCopyWithImpl<$Res>
|
||||
_$DeviceInfoImpl _value, $Res Function(_$DeviceInfoImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of DeviceInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -565,7 +590,7 @@ class _$DeviceInfoImpl extends _DeviceInfo {
|
||||
other.resetBlocked == resetBlocked));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
@ -582,7 +607,9 @@ class _$DeviceInfoImpl extends _DeviceInfo {
|
||||
fipsApproved,
|
||||
resetBlocked);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of DeviceInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$DeviceInfoImplCopyWith<_$DeviceInfoImpl> get copyWith =>
|
||||
@ -639,8 +666,11 @@ abstract class _DeviceInfo extends DeviceInfo {
|
||||
int get fipsApproved;
|
||||
@override
|
||||
int get resetBlocked;
|
||||
|
||||
/// Create a copy of DeviceInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$DeviceInfoImplCopyWith<_$DeviceInfoImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -258,3 +258,5 @@ class CredentialData with _$CredentialData {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
enum OathLayout { list, grid, mixed }
|
||||
|
@ -29,8 +29,12 @@ mixin _$OathCredential {
|
||||
int get period => throw _privateConstructorUsedError;
|
||||
bool get touchRequired => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this OathCredential to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of OathCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OathCredentialCopyWith<OathCredential> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -61,6 +65,8 @@ class _$OathCredentialCopyWithImpl<$Res, $Val extends OathCredential>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OathCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -131,6 +137,8 @@ class __$$OathCredentialImplCopyWithImpl<$Res>
|
||||
_$OathCredentialImpl _value, $Res Function(_$OathCredentialImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of OathCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -222,12 +230,14 @@ class _$OathCredentialImpl implements _OathCredential {
|
||||
other.touchRequired == touchRequired));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, deviceId, id, issuer, name, oathType, period, touchRequired);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of OathCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$OathCredentialImplCopyWith<_$OathCredentialImpl> get copyWith =>
|
||||
@ -270,8 +280,11 @@ abstract class _OathCredential implements OathCredential {
|
||||
int get period;
|
||||
@override
|
||||
bool get touchRequired;
|
||||
|
||||
/// Create a copy of OathCredential
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$OathCredentialImplCopyWith<_$OathCredentialImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -286,8 +299,12 @@ mixin _$OathCode {
|
||||
int get validFrom => throw _privateConstructorUsedError;
|
||||
int get validTo => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this OathCode to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of OathCode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OathCodeCopyWith<OathCode> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -310,6 +327,8 @@ class _$OathCodeCopyWithImpl<$Res, $Val extends OathCode>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OathCode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -353,6 +372,8 @@ class __$$OathCodeImplCopyWithImpl<$Res>
|
||||
_$OathCodeImpl _value, $Res Function(_$OathCodeImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of OathCode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -408,11 +429,13 @@ class _$OathCodeImpl implements _OathCode {
|
||||
(identical(other.validTo, validTo) || other.validTo == validTo));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, value, validFrom, validTo);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of OathCode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$OathCodeImplCopyWith<_$OathCodeImpl> get copyWith =>
|
||||
@ -440,8 +463,11 @@ abstract class _OathCode implements OathCode {
|
||||
int get validFrom;
|
||||
@override
|
||||
int get validTo;
|
||||
|
||||
/// Create a copy of OathCode
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$OathCodeImplCopyWith<_$OathCodeImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -455,8 +481,12 @@ mixin _$OathPair {
|
||||
OathCredential get credential => throw _privateConstructorUsedError;
|
||||
OathCode? get code => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this OathPair to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of OathPair
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OathPairCopyWith<OathPair> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -482,6 +512,8 @@ class _$OathPairCopyWithImpl<$Res, $Val extends OathPair>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OathPair
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -500,6 +532,8 @@ class _$OathPairCopyWithImpl<$Res, $Val extends OathPair>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of OathPair
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$OathCredentialCopyWith<$Res> get credential {
|
||||
@ -508,6 +542,8 @@ class _$OathPairCopyWithImpl<$Res, $Val extends OathPair>
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of OathPair
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$OathCodeCopyWith<$Res>? get code {
|
||||
@ -545,6 +581,8 @@ class __$$OathPairImplCopyWithImpl<$Res>
|
||||
_$OathPairImpl _value, $Res Function(_$OathPairImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of OathPair
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -592,11 +630,13 @@ class _$OathPairImpl implements _OathPair {
|
||||
(identical(other.code, code) || other.code == code));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, credential, code);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of OathPair
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$OathPairImplCopyWith<_$OathPairImpl> get copyWith =>
|
||||
@ -621,8 +661,11 @@ abstract class _OathPair implements OathPair {
|
||||
OathCredential get credential;
|
||||
@override
|
||||
OathCode? get code;
|
||||
|
||||
/// Create a copy of OathPair
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$OathPairImplCopyWith<_$OathPairImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -640,8 +683,12 @@ mixin _$OathState {
|
||||
bool get locked => throw _privateConstructorUsedError;
|
||||
KeystoreState get keystore => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this OathState to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of OathState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OathStateCopyWith<OathState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -672,6 +719,8 @@ class _$OathStateCopyWithImpl<$Res, $Val extends OathState>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OathState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -710,6 +759,8 @@ class _$OathStateCopyWithImpl<$Res, $Val extends OathState>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of OathState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$VersionCopyWith<$Res> get version {
|
||||
@ -747,6 +798,8 @@ class __$$OathStateImplCopyWithImpl<$Res>
|
||||
_$OathStateImpl _value, $Res Function(_$OathStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of OathState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -833,12 +886,14 @@ class _$OathStateImpl extends _OathState {
|
||||
other.keystore == keystore));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, deviceId, version, hasKey, remembered, locked, keystore);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of OathState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$OathStateImplCopyWith<_$OathStateImpl> get copyWith =>
|
||||
@ -875,8 +930,11 @@ abstract class _OathState extends OathState {
|
||||
bool get locked;
|
||||
@override
|
||||
KeystoreState get keystore;
|
||||
|
||||
/// Create a copy of OathState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$OathStateImplCopyWith<_$OathStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -896,8 +954,12 @@ mixin _$CredentialData {
|
||||
int get period => throw _privateConstructorUsedError;
|
||||
int get counter => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this CredentialData to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of CredentialData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$CredentialDataCopyWith<CredentialData> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -929,6 +991,8 @@ class _$CredentialDataCopyWithImpl<$Res, $Val extends CredentialData>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of CredentialData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1005,6 +1069,8 @@ class __$$CredentialDataImplCopyWithImpl<$Res>
|
||||
_$CredentialDataImpl _value, $Res Function(_$CredentialDataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of CredentialData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1115,12 +1181,14 @@ class _$CredentialDataImpl extends _CredentialData {
|
||||
(identical(other.counter, counter) || other.counter == counter));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, issuer, name, secret, oathType,
|
||||
hashAlgorithm, digits, period, counter);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of CredentialData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$CredentialDataImplCopyWith<_$CredentialDataImpl> get copyWith =>
|
||||
@ -1166,8 +1234,11 @@ abstract class _CredentialData extends CredentialData {
|
||||
int get period;
|
||||
@override
|
||||
int get counter;
|
||||
|
||||
/// Create a copy of CredentialData
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$CredentialDataImplCopyWith<_$CredentialDataImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -38,6 +38,53 @@ class AccountsSearchNotifier extends StateNotifier<String> {
|
||||
}
|
||||
}
|
||||
|
||||
final oathLayoutProvider =
|
||||
StateNotifierProvider.autoDispose<OathLayoutNotfier, OathLayout>((ref) {
|
||||
final device = ref.watch(currentDeviceProvider);
|
||||
List<OathPair> credentials = device != null
|
||||
? ref.read(filteredCredentialsProvider(
|
||||
ref.read(credentialListProvider(device.path)) ?? []))
|
||||
: [];
|
||||
final favorites = ref.watch(favoritesProvider);
|
||||
final pinnedCreds =
|
||||
credentials.where((entry) => favorites.contains(entry.credential.id));
|
||||
return OathLayoutNotfier('OATH_STATE_LAYOUT', ref.watch(prefProvider),
|
||||
credentials, pinnedCreds.toList());
|
||||
});
|
||||
|
||||
class OathLayoutNotfier extends StateNotifier<OathLayout> {
|
||||
final String _key;
|
||||
final SharedPreferences _prefs;
|
||||
OathLayoutNotfier(this._key, this._prefs, List<OathPair> credentials,
|
||||
List<OathPair> pinnedCredentials)
|
||||
: super(
|
||||
_fromName(_prefs.getString(_key), credentials, pinnedCredentials));
|
||||
|
||||
void setLayout(OathLayout layout) {
|
||||
state = layout;
|
||||
_prefs.setString(_key, layout.name);
|
||||
}
|
||||
|
||||
static OathLayout _fromName(String? name, List<OathPair> credentials,
|
||||
List<OathPair> pinnedCredentials) {
|
||||
final layout = OathLayout.values.firstWhere(
|
||||
(element) => element.name == name,
|
||||
orElse: () => OathLayout.list,
|
||||
);
|
||||
// Default to list view if current key does not have
|
||||
// pinned credentials
|
||||
if (layout == OathLayout.mixed) {
|
||||
if (pinnedCredentials.isEmpty) {
|
||||
return OathLayout.list;
|
||||
}
|
||||
if (pinnedCredentials.length == credentials.length) {
|
||||
return OathLayout.grid;
|
||||
}
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
|
||||
final oathStateProvider = AsyncNotifierProvider.autoDispose
|
||||
.family<OathStateNotifier, OathState, DevicePath>(
|
||||
() => throw UnimplementedError(),
|
||||
|
@ -26,7 +26,6 @@ import '../../app/shortcuts.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../core/state.dart';
|
||||
import '../../widgets/circle_timer.dart';
|
||||
import '../../widgets/custom_icons.dart';
|
||||
import '../features.dart' as features;
|
||||
import '../keys.dart' as keys;
|
||||
import '../models.dart';
|
||||
@ -90,7 +89,7 @@ class AccountHelper {
|
||||
ActionItem(
|
||||
key: keys.togglePinAction,
|
||||
feature: features.accountsPin,
|
||||
icon: pinned ? pushPinStrokeIcon : const Icon(Symbols.push_pin),
|
||||
icon: Icon(pinned ? Symbols.keep_off : Symbols.keep),
|
||||
title: pinned ? l10n.s_unpin_account : l10n.s_pin_account,
|
||||
subtitle: l10n.l_pin_account_desc,
|
||||
intent: TogglePinIntent(credential),
|
||||
|
@ -18,6 +18,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../widgets/flex_box.dart';
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
import 'account_view.dart';
|
||||
@ -32,6 +33,9 @@ class AccountList extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final theme = Theme.of(context);
|
||||
final labelStyle =
|
||||
theme.textTheme.bodyMedium?.copyWith(color: theme.colorScheme.primary);
|
||||
final credentials = ref.watch(filteredCredentialsProvider(accounts));
|
||||
final favorites = ref.watch(favoritesProvider);
|
||||
if (credentials.isEmpty) {
|
||||
@ -45,32 +49,71 @@ class AccountList extends ConsumerWidget {
|
||||
final creds =
|
||||
credentials.where((entry) => !favorites.contains(entry.credential.id));
|
||||
|
||||
final oathLayout = ref.watch(oathLayoutProvider);
|
||||
final pinnedLayout =
|
||||
(oathLayout == OathLayout.grid || oathLayout == OathLayout.mixed)
|
||||
? FlexLayout.grid
|
||||
: FlexLayout.list;
|
||||
final normalLayout =
|
||||
oathLayout == OathLayout.grid ? FlexLayout.grid : FlexLayout.list;
|
||||
|
||||
return FocusTraversalGroup(
|
||||
policy: WidgetOrderTraversalPolicy(),
|
||||
child: Column(
|
||||
children: [
|
||||
...pinnedCreds.map(
|
||||
(entry) => AccountView(
|
||||
entry.credential,
|
||||
expanded: expanded,
|
||||
selected: entry.credential == selected,
|
||||
),
|
||||
),
|
||||
if (pinnedCreds.isNotEmpty && creds.isNotEmpty)
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (pinnedCreds.isNotEmpty) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 18, bottom: 8),
|
||||
child: Text(l10n.s_pinned, style: labelStyle),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: FlexBox<OathPair>(
|
||||
items: pinnedCreds.toList(),
|
||||
itemBuilder: (value) => AccountView(
|
||||
value.credential,
|
||||
expanded: expanded,
|
||||
selected: value.credential == selected,
|
||||
large: pinnedLayout == FlexLayout.grid,
|
||||
),
|
||||
cellMinWidth: 250,
|
||||
spacing: pinnedLayout == FlexLayout.grid ? 4.0 : 0.0,
|
||||
runSpacing: pinnedLayout == FlexLayout.grid ? 4.0 : 0.0,
|
||||
layout: pinnedLayout,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (pinnedCreds.isNotEmpty && creds.isNotEmpty) ...[
|
||||
const SizedBox(height: 24),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 18, bottom: 8),
|
||||
child: Text(
|
||||
l10n.s_accounts,
|
||||
style: labelStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Divider(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: FlexBox<OathPair>(
|
||||
items: creds.toList(),
|
||||
itemBuilder: (value) => AccountView(
|
||||
value.credential,
|
||||
expanded: expanded,
|
||||
selected: value.credential == selected,
|
||||
large: normalLayout == FlexLayout.grid,
|
||||
),
|
||||
cellMinWidth: 250,
|
||||
spacing: normalLayout == FlexLayout.grid ? 4.0 : 0.0,
|
||||
runSpacing: normalLayout == FlexLayout.grid ? 4.0 : 0.0,
|
||||
layout: normalLayout,
|
||||
),
|
||||
),
|
||||
...creds.map(
|
||||
(entry) => AccountView(
|
||||
entry.credential,
|
||||
expanded: expanded,
|
||||
selected: entry.credential == selected,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -30,8 +30,12 @@ class AccountView extends ConsumerStatefulWidget {
|
||||
final OathCredential credential;
|
||||
final bool expanded;
|
||||
final bool selected;
|
||||
final bool large;
|
||||
const AccountView(this.credential,
|
||||
{super.key, required this.expanded, required this.selected});
|
||||
{super.key,
|
||||
required this.expanded,
|
||||
required this.selected,
|
||||
this.large = false});
|
||||
|
||||
@override
|
||||
ConsumerState<ConsumerStatefulWidget> createState() => _AccountViewState();
|
||||
@ -116,6 +120,95 @@ class _AccountViewState extends ConsumerState<AccountView> {
|
||||
? CopyIntent<OathCredential>(credential)
|
||||
: null,
|
||||
buildPopupActions: (_) => helper.buildActions(),
|
||||
itemBuilder: widget.large
|
||||
? (context) {
|
||||
return ListTile(
|
||||
mouseCursor: !(isDesktop && !widget.expanded)
|
||||
? SystemMouseCursors.click
|
||||
: null,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16)),
|
||||
selectedTileColor:
|
||||
Theme.of(context).colorScheme.secondaryContainer,
|
||||
selectedColor:
|
||||
Theme.of(context).colorScheme.onSecondaryContainer,
|
||||
selected: widget.selected,
|
||||
tileColor: Theme.of(context).hoverColor,
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
|
||||
title: Column(
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AccountIcon(
|
||||
issuer: credential.issuer,
|
||||
defaultWidget: circleAvatar),
|
||||
const SizedBox(width: 12),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
helper.title,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge
|
||||
?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface),
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
),
|
||||
if (subtitle != null)
|
||||
Text(
|
||||
subtitle,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant),
|
||||
overflow: TextOverflow.fade,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Focus(
|
||||
skipTraversal: true,
|
||||
descendantsAreTraversable: false,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
helper.code != null
|
||||
? FilledButton.tonalIcon(
|
||||
icon: helper.buildCodeIcon(),
|
||||
label: helper.buildCodeLabel(),
|
||||
style: buttonStyle,
|
||||
onPressed:
|
||||
Actions.handler(context, openIntent),
|
||||
)
|
||||
: FilledButton.tonal(
|
||||
style: buttonStyle,
|
||||
onPressed:
|
||||
Actions.handler(context, openIntent),
|
||||
child: helper.buildCodeIcon()),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../app/views/action_list.dart';
|
||||
import '../../management/models.dart';
|
||||
import '../features.dart' as features;
|
||||
import '../icon_provider/icon_pack_dialog.dart';
|
||||
import '../keys.dart' as keys;
|
||||
@ -39,6 +40,28 @@ Widget oathBuildActions(
|
||||
}) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final capacity = oathState.capacity;
|
||||
final (fipsCapable, fipsApproved) = ref
|
||||
.watch(currentDeviceDataProvider)
|
||||
.valueOrNull
|
||||
?.info
|
||||
.getFipsStatus(Capability.oath) ??
|
||||
(false, false);
|
||||
|
||||
final String? subtitle;
|
||||
final bool enabled;
|
||||
if (used == null) {
|
||||
subtitle = l10n.l_unlock_first;
|
||||
enabled = false;
|
||||
} else if (fipsCapable & !fipsApproved) {
|
||||
subtitle = l10n.l_set_password_first;
|
||||
enabled = false;
|
||||
} else if (capacity != null) {
|
||||
subtitle = l10n.l_accounts_used(used, capacity);
|
||||
enabled = capacity > used;
|
||||
} else {
|
||||
subtitle = null;
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
@ -47,14 +70,10 @@ Widget oathBuildActions(
|
||||
feature: features.actionsAdd,
|
||||
key: keys.addAccountAction,
|
||||
title: l10n.s_add_account,
|
||||
subtitle: used == null
|
||||
? l10n.l_unlock_first
|
||||
: (capacity != null
|
||||
? l10n.l_accounts_used(used, capacity)
|
||||
: null),
|
||||
subtitle: subtitle,
|
||||
actionStyle: ActionStyle.primary,
|
||||
icon: const Icon(Symbols.person_add_alt),
|
||||
onTap: used != null && (capacity == null || capacity > used)
|
||||
onTap: enabled
|
||||
? (context) async {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
await addOathAccount(context, ref, devicePath, oathState);
|
||||
@ -82,7 +101,7 @@ Widget oathBuildActions(
|
||||
feature: features.actionsPassword,
|
||||
title:
|
||||
oathState.hasKey ? l10n.s_manage_password : l10n.s_set_password,
|
||||
subtitle: l10n.l_optional_password_protection,
|
||||
subtitle: l10n.l_password_protection,
|
||||
icon: const Icon(Symbols.password),
|
||||
onTap: (context) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022-2023 Yubico.
|
||||
* Copyright (C) 2022-2024 Yubico.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -34,6 +34,7 @@ import '../state.dart';
|
||||
class ManagePasswordDialog extends ConsumerStatefulWidget {
|
||||
final DevicePath path;
|
||||
final OathState state;
|
||||
|
||||
const ManagePasswordDialog(this.path, this.state, {super.key});
|
||||
|
||||
@override
|
||||
@ -44,6 +45,8 @@ class ManagePasswordDialog extends ConsumerStatefulWidget {
|
||||
class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
final _currentPasswordController = TextEditingController();
|
||||
final _currentPasswordFocus = FocusNode();
|
||||
final _newPasswordFocus = FocusNode();
|
||||
final _confirmPasswordFocus = FocusNode();
|
||||
String _newPassword = '';
|
||||
String _confirmPassword = '';
|
||||
bool _currentIsWrong = false;
|
||||
@ -55,6 +58,8 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
void dispose() {
|
||||
_currentPasswordController.dispose();
|
||||
_currentPasswordFocus.dispose();
|
||||
_newPasswordFocus.dispose();
|
||||
_confirmPasswordFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -92,6 +97,13 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
_newPassword == _confirmPassword &&
|
||||
(!widget.state.hasKey || _currentPasswordController.text.isNotEmpty);
|
||||
|
||||
final newPasswordEnabled =
|
||||
!widget.state.hasKey || _currentPasswordController.text.isNotEmpty;
|
||||
|
||||
final confirmPasswordEnabled =
|
||||
(!widget.state.hasKey || _currentPasswordController.text.isNotEmpty) &&
|
||||
_newPassword.isNotEmpty;
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(
|
||||
widget.state.hasKey ? l10n.s_manage_password : l10n.s_set_password),
|
||||
@ -141,6 +153,13 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
_currentIsWrong = false;
|
||||
});
|
||||
},
|
||||
onSubmitted: (_) {
|
||||
if (_currentPasswordController.text.isEmpty) {
|
||||
_currentPasswordFocus.requestFocus();
|
||||
} else {
|
||||
_newPasswordFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
Wrap(
|
||||
spacing: 4.0,
|
||||
@ -204,24 +223,27 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
autofocus: !widget.state.hasKey,
|
||||
obscureText: _isObscureNew,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
focusNode: _newPasswordFocus,
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_new_password,
|
||||
prefixIcon: const Icon(Symbols.password),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
enabled: !widget.state.hasKey ||
|
||||
_currentPasswordController.text.isNotEmpty,
|
||||
suffixIcon: ExcludeFocusTraversal(
|
||||
excluding: !newPasswordEnabled,
|
||||
child: IconButton(
|
||||
icon: Icon(_isObscureNew
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureNew = !_isObscureNew;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureNew
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
),
|
||||
enabled: newPasswordEnabled,
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
@ -230,34 +252,38 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
});
|
||||
},
|
||||
onSubmitted: (_) {
|
||||
if (isValid) {
|
||||
_submit();
|
||||
if (_newPassword.isNotEmpty) {
|
||||
_confirmPasswordFocus.requestFocus();
|
||||
} else if (_newPassword.isEmpty) {
|
||||
_newPasswordFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
AppTextField(
|
||||
key: keys.confirmPasswordField,
|
||||
obscureText: _isObscureConfirm,
|
||||
focusNode: _confirmPasswordFocus,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
decoration: AppInputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: l10n.s_confirm_password,
|
||||
prefixIcon: const Icon(Symbols.password),
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureConfirm
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
enabled: (!widget.state.hasKey ||
|
||||
_currentPasswordController.text.isNotEmpty) &&
|
||||
_newPassword.isNotEmpty,
|
||||
suffixIcon: ExcludeFocusTraversal(
|
||||
excluding: !confirmPasswordEnabled,
|
||||
child: IconButton(
|
||||
icon: Icon(_isObscureConfirm
|
||||
? Symbols.visibility
|
||||
: Symbols.visibility_off),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isObscureConfirm = !_isObscureConfirm;
|
||||
});
|
||||
},
|
||||
tooltip: _isObscureConfirm
|
||||
? l10n.s_show_password
|
||||
: l10n.s_hide_password),
|
||||
),
|
||||
enabled: confirmPasswordEnabled,
|
||||
errorText: _newPassword.length == _confirmPassword.length &&
|
||||
_newPassword != _confirmPassword
|
||||
? l10n.l_password_mismatch
|
||||
@ -273,6 +299,8 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
|
||||
onSubmitted: (_) {
|
||||
if (isValid) {
|
||||
_submit();
|
||||
} else {
|
||||
_confirmPasswordFocus.requestFocus();
|
||||
}
|
||||
},
|
||||
).init(),
|
||||
|
@ -53,6 +53,19 @@ import 'key_actions.dart';
|
||||
import 'unlock_form.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
extension on OathLayout {
|
||||
IconData get _icon => switch (this) {
|
||||
OathLayout.list => Symbols.list,
|
||||
OathLayout.grid => Symbols.grid_view,
|
||||
OathLayout.mixed => Symbols.vertical_split
|
||||
};
|
||||
String getDisplayName(AppLocalizations l10n) => switch (this) {
|
||||
OathLayout.list => l10n.s_list_layout,
|
||||
OathLayout.grid => l10n.s_grid_layout,
|
||||
OathLayout.mixed => l10n.s_mixed_layout
|
||||
};
|
||||
}
|
||||
|
||||
class OathScreen extends ConsumerWidget {
|
||||
final DevicePath devicePath;
|
||||
|
||||
@ -123,6 +136,7 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
|
||||
late FocusNode searchFocus;
|
||||
late TextEditingController searchController;
|
||||
OathCredential? _selected;
|
||||
bool _canRequestFocus = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -376,60 +390,171 @@ class _UnlockedViewState extends ConsumerState<_UnlockedView> {
|
||||
}
|
||||
return KeyEventResult.ignored;
|
||||
},
|
||||
child: Builder(builder: (context) {
|
||||
child: LayoutBuilder(builder: (context, constraints) {
|
||||
final width = constraints.maxWidth;
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
return Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
|
||||
child: AppTextFormField(
|
||||
key: searchField,
|
||||
controller: searchController,
|
||||
focusNode: searchFocus,
|
||||
// Use the default style, but with a smaller font size:
|
||||
style: textTheme.titleMedium
|
||||
?.copyWith(fontSize: textTheme.titleSmall?.fontSize),
|
||||
decoration: AppInputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(48),
|
||||
borderSide: BorderSide(
|
||||
width: 0,
|
||||
style: searchFocus.hasFocus
|
||||
? BorderStyle.solid
|
||||
: BorderStyle.none,
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final credentials = ref.watch(filteredCredentialsProvider(
|
||||
ref.watch(credentialListProvider(widget.devicePath)) ??
|
||||
[]));
|
||||
final favorites = ref.watch(favoritesProvider);
|
||||
final pinnedCreds = credentials
|
||||
.where((entry) => favorites.contains(entry.credential.id));
|
||||
|
||||
final availableLayouts = pinnedCreds.isEmpty ||
|
||||
pinnedCreds.length == credentials.length
|
||||
? OathLayout.values
|
||||
.where((element) => element != OathLayout.mixed)
|
||||
: OathLayout.values;
|
||||
final oathLayout = ref.watch(oathLayoutProvider);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10.0, vertical: 8.0),
|
||||
child: AppTextFormField(
|
||||
key: searchField,
|
||||
controller: searchController,
|
||||
canRequestFocus: _canRequestFocus,
|
||||
focusNode: searchFocus,
|
||||
// Use the default style, but with a smaller font size:
|
||||
style: textTheme.titleMedium
|
||||
?.copyWith(fontSize: textTheme.titleSmall?.fontSize),
|
||||
decoration: AppInputDecoration(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(48),
|
||||
borderSide: BorderSide(
|
||||
width: 0,
|
||||
style: searchFocus.hasFocus
|
||||
? BorderStyle.solid
|
||||
: BorderStyle.none,
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.all(16),
|
||||
fillColor: Theme.of(context).hoverColor,
|
||||
filled: true,
|
||||
hintText: l10n.s_search_accounts,
|
||||
isDense: true,
|
||||
prefixIcon: const Padding(
|
||||
padding: EdgeInsetsDirectional.only(start: 8.0),
|
||||
child: Icon(Icons.search_outlined),
|
||||
),
|
||||
suffixIcons: [
|
||||
if (searchController.text.isNotEmpty)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
iconSize: 16,
|
||||
onPressed: () {
|
||||
searchController.clear();
|
||||
ref
|
||||
.read(accountsSearchProvider.notifier)
|
||||
.setFilter('');
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
if (searchController.text.isEmpty) ...[
|
||||
if (width >= 450)
|
||||
...availableLayouts.map(
|
||||
(e) => MouseRegion(
|
||||
onEnter: (event) {
|
||||
if (!searchFocus.hasFocus) {
|
||||
setState(() {
|
||||
_canRequestFocus = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
onExit: (event) {
|
||||
setState(() {
|
||||
_canRequestFocus = true;
|
||||
});
|
||||
},
|
||||
child: IconButton(
|
||||
tooltip: e.getDisplayName(l10n),
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(oathLayoutProvider.notifier)
|
||||
.setLayout(e);
|
||||
},
|
||||
icon: Icon(
|
||||
e._icon,
|
||||
color: e == oathLayout
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (width < 450)
|
||||
MouseRegion(
|
||||
onEnter: (event) {
|
||||
if (!searchFocus.hasFocus) {
|
||||
setState(() {
|
||||
_canRequestFocus = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
onExit: (event) {
|
||||
setState(() {
|
||||
_canRequestFocus = true;
|
||||
});
|
||||
},
|
||||
child: PopupMenuButton(
|
||||
constraints: const BoxConstraints.tightFor(),
|
||||
tooltip: 'Select layout',
|
||||
popUpAnimationStyle:
|
||||
AnimationStyle(duration: Duration.zero),
|
||||
icon: Icon(
|
||||
oathLayout._icon,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
itemBuilder: (context) => [
|
||||
...availableLayouts.map(
|
||||
(e) => PopupMenuItem(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
Tooltip(
|
||||
message: e.getDisplayName(l10n),
|
||||
child: Icon(
|
||||
e._icon,
|
||||
color: e == oathLayout
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
: null,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
ref
|
||||
.read(oathLayoutProvider.notifier)
|
||||
.setLayout(e);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.all(16),
|
||||
fillColor: Theme.of(context).hoverColor,
|
||||
filled: true,
|
||||
hintText: l10n.s_search_accounts,
|
||||
isDense: true,
|
||||
prefixIcon: const Padding(
|
||||
padding: EdgeInsetsDirectional.only(start: 8.0),
|
||||
child: Icon(Icons.search_outlined),
|
||||
),
|
||||
suffixIcon: searchController.text.isNotEmpty
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
iconSize: 16,
|
||||
onPressed: () {
|
||||
searchController.clear();
|
||||
ref
|
||||
.read(accountsSearchProvider.notifier)
|
||||
.setFilter('');
|
||||
setState(() {});
|
||||
},
|
||||
)
|
||||
: null,
|
||||
),
|
||||
onChanged: (value) {
|
||||
ref.read(accountsSearchProvider.notifier).setFilter(value);
|
||||
setState(() {});
|
||||
},
|
||||
textInputAction: TextInputAction.next,
|
||||
onFieldSubmitted: (value) {
|
||||
Focus.of(context).focusInDirection(TraversalDirection.down);
|
||||
},
|
||||
).init(),
|
||||
|
||||
onChanged: (value) {
|
||||
ref
|
||||
.read(accountsSearchProvider.notifier)
|
||||
.setFilter(value);
|
||||
setState(() {});
|
||||
},
|
||||
textInputAction: TextInputAction.next,
|
||||
onFieldSubmitted: (value) {
|
||||
Focus.of(context)
|
||||
.focusInDirection(TraversalDirection.down);
|
||||
},
|
||||
).init(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
|
@ -23,8 +23,12 @@ mixin _$OtpState {
|
||||
bool get slot1Configured => throw _privateConstructorUsedError;
|
||||
bool get slot2Configured => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this OtpState to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of OtpState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OtpStateCopyWith<OtpState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -47,6 +51,8 @@ class _$OtpStateCopyWithImpl<$Res, $Val extends OtpState>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OtpState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -85,6 +91,8 @@ class __$$OtpStateImplCopyWithImpl<$Res>
|
||||
_$OtpStateImpl _value, $Res Function(_$OtpStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of OtpState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -134,12 +142,14 @@ class _$OtpStateImpl extends _OtpState {
|
||||
other.slot2Configured == slot2Configured));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, slot1Configured, slot2Configured);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of OtpState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$OtpStateImplCopyWith<_$OtpStateImpl> get copyWith =>
|
||||
@ -166,8 +176,11 @@ abstract class _OtpState extends OtpState {
|
||||
bool get slot1Configured;
|
||||
@override
|
||||
bool get slot2Configured;
|
||||
|
||||
/// Create a copy of OtpState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$OtpStateImplCopyWith<_$OtpStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -177,7 +190,9 @@ mixin _$OtpSlot {
|
||||
SlotId get slot => throw _privateConstructorUsedError;
|
||||
bool get isConfigured => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of OtpSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OtpSlotCopyWith<OtpSlot> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
@ -199,6 +214,8 @@ class _$OtpSlotCopyWithImpl<$Res, $Val extends OtpSlot>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OtpSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -236,6 +253,8 @@ class __$$OtpSlotImplCopyWithImpl<$Res>
|
||||
_$OtpSlotImpl _value, $Res Function(_$OtpSlotImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of OtpSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -283,7 +302,9 @@ class _$OtpSlotImpl implements _OtpSlot {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, slot, isConfigured);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of OtpSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$OtpSlotImplCopyWith<_$OtpSlotImpl> get copyWith =>
|
||||
@ -299,8 +320,11 @@ abstract class _OtpSlot implements OtpSlot {
|
||||
SlotId get slot;
|
||||
@override
|
||||
bool get isConfigured;
|
||||
|
||||
/// Create a copy of OtpSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$OtpSlotImplCopyWith<_$OtpSlotImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -316,8 +340,12 @@ mixin _$SlotConfigurationOptions {
|
||||
bool? get requireTouch => throw _privateConstructorUsedError;
|
||||
bool? get appendCr => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this SlotConfigurationOptions to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of SlotConfigurationOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$SlotConfigurationOptionsCopyWith<SlotConfigurationOptions> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -342,6 +370,8 @@ class _$SlotConfigurationOptionsCopyWithImpl<$Res,
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of SlotConfigurationOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -388,6 +418,8 @@ class __$$SlotConfigurationOptionsImplCopyWithImpl<$Res>
|
||||
$Res Function(_$SlotConfigurationOptionsImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of SlotConfigurationOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -446,11 +478,13 @@ class _$SlotConfigurationOptionsImpl implements _SlotConfigurationOptions {
|
||||
other.appendCr == appendCr));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, digits8, requireTouch, appendCr);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of SlotConfigurationOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SlotConfigurationOptionsImplCopyWith<_$SlotConfigurationOptionsImpl>
|
||||
@ -480,8 +514,11 @@ abstract class _SlotConfigurationOptions implements SlotConfigurationOptions {
|
||||
bool? get requireTouch;
|
||||
@override
|
||||
bool? get appendCr;
|
||||
|
||||
/// Create a copy of SlotConfigurationOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SlotConfigurationOptionsImplCopyWith<_$SlotConfigurationOptionsImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -570,8 +607,13 @@ mixin _$SlotConfiguration {
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this SlotConfiguration to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$SlotConfigurationCopyWith<SlotConfiguration> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -597,6 +639,8 @@ class _$SlotConfigurationCopyWithImpl<$Res, $Val extends SlotConfiguration>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -610,6 +654,8 @@ class _$SlotConfigurationCopyWithImpl<$Res, $Val extends SlotConfiguration>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SlotConfigurationOptionsCopyWith<$Res>? get options {
|
||||
@ -646,6 +692,8 @@ class __$$SlotConfigurationHotpImplCopyWithImpl<$Res>
|
||||
$Res Function(_$SlotConfigurationHotpImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -699,11 +747,13 @@ class _$SlotConfigurationHotpImpl extends _SlotConfigurationHotp {
|
||||
(identical(other.options, options) || other.options == options));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, key, options);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SlotConfigurationHotpImplCopyWith<_$SlotConfigurationHotpImpl>
|
||||
@ -818,8 +868,11 @@ abstract class _SlotConfigurationHotp extends SlotConfiguration {
|
||||
String get key;
|
||||
@override
|
||||
SlotConfigurationOptions? get options;
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SlotConfigurationHotpImplCopyWith<_$SlotConfigurationHotpImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -849,6 +902,8 @@ class __$$SlotConfigurationHmacSha1ImplCopyWithImpl<$Res>
|
||||
$Res Function(_$SlotConfigurationHmacSha1Impl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -902,11 +957,13 @@ class _$SlotConfigurationHmacSha1Impl extends _SlotConfigurationHmacSha1 {
|
||||
(identical(other.options, options) || other.options == options));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, key, options);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SlotConfigurationHmacSha1ImplCopyWith<_$SlotConfigurationHmacSha1Impl>
|
||||
@ -1022,8 +1079,11 @@ abstract class _SlotConfigurationHmacSha1 extends SlotConfiguration {
|
||||
String get key;
|
||||
@override
|
||||
SlotConfigurationOptions? get options;
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SlotConfigurationHmacSha1ImplCopyWith<_$SlotConfigurationHmacSha1Impl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1056,6 +1116,8 @@ class __$$SlotConfigurationStaticPasswordImplCopyWithImpl<$Res>
|
||||
$Res Function(_$SlotConfigurationStaticPasswordImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1124,12 +1186,14 @@ class _$SlotConfigurationStaticPasswordImpl
|
||||
(identical(other.options, options) || other.options == options));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, password, keyboardLayout, options);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SlotConfigurationStaticPasswordImplCopyWith<
|
||||
@ -1248,8 +1312,11 @@ abstract class _SlotConfigurationStaticPassword extends SlotConfiguration {
|
||||
String get keyboardLayout;
|
||||
@override
|
||||
SlotConfigurationOptions? get options;
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SlotConfigurationStaticPasswordImplCopyWith<
|
||||
_$SlotConfigurationStaticPasswordImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
@ -1284,6 +1351,8 @@ class __$$SlotConfigurationYubiOtpImplCopyWithImpl<$Res>
|
||||
$Res Function(_$SlotConfigurationYubiOtpImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1359,12 +1428,14 @@ class _$SlotConfigurationYubiOtpImpl extends _SlotConfigurationYubiOtp {
|
||||
(identical(other.options, options) || other.options == options));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, publicId, privateId, key, options);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SlotConfigurationYubiOtpImplCopyWith<_$SlotConfigurationYubiOtpImpl>
|
||||
@ -1484,8 +1555,11 @@ abstract class _SlotConfigurationYubiOtp extends SlotConfiguration {
|
||||
String get key;
|
||||
@override
|
||||
SlotConfigurationOptions? get options;
|
||||
|
||||
/// Create a copy of SlotConfiguration
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SlotConfigurationYubiOtpImplCopyWith<_$SlotConfigurationYubiOtpImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -180,13 +180,17 @@ class _OtpScreenState extends ConsumerState<OtpScreen> {
|
||||
return null;
|
||||
}),
|
||||
},
|
||||
child: Column(children: [
|
||||
...otpState.slots.map((e) => _SlotListItem(
|
||||
e,
|
||||
expanded: expanded,
|
||||
selected: e == selected,
|
||||
))
|
||||
]),
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Column(children: [
|
||||
...otpState.slots.map((e) => _SlotListItem(
|
||||
e,
|
||||
expanded: expanded,
|
||||
selected: e == selected,
|
||||
))
|
||||
]),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -270,6 +270,7 @@ class PivState with _$PivState {
|
||||
required bool derivedKey,
|
||||
required bool storedKey,
|
||||
required int pinAttempts,
|
||||
required bool supportsBio,
|
||||
String? chuid,
|
||||
String? ccc,
|
||||
PivStateMetadata? metadata,
|
||||
|
@ -24,8 +24,12 @@ mixin _$PinMetadata {
|
||||
int get totalAttempts => throw _privateConstructorUsedError;
|
||||
int get attemptsRemaining => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this PinMetadata to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PinMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PinMetadataCopyWith<PinMetadata> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -49,6 +53,8 @@ class _$PinMetadataCopyWithImpl<$Res, $Val extends PinMetadata>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PinMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -92,6 +98,8 @@ class __$$PinMetadataImplCopyWithImpl<$Res>
|
||||
_$PinMetadataImpl _value, $Res Function(_$PinMetadataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PinMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -150,12 +158,14 @@ class _$PinMetadataImpl implements _PinMetadata {
|
||||
other.attemptsRemaining == attemptsRemaining));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, defaultValue, totalAttempts, attemptsRemaining);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PinMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PinMetadataImplCopyWith<_$PinMetadataImpl> get copyWith =>
|
||||
@ -182,8 +192,11 @@ abstract class _PinMetadata implements PinMetadata {
|
||||
int get totalAttempts;
|
||||
@override
|
||||
int get attemptsRemaining;
|
||||
|
||||
/// Create a copy of PinMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PinMetadataImplCopyWith<_$PinMetadataImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -247,6 +260,9 @@ class _$PinVerificationStatusCopyWithImpl<$Res,
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PinVerificationStatus
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -263,6 +279,9 @@ class __$$PinSuccessImplCopyWithImpl<$Res>
|
||||
__$$PinSuccessImplCopyWithImpl(
|
||||
_$PinSuccessImpl _value, $Res Function(_$PinSuccessImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PinVerificationStatus
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -370,6 +389,8 @@ class __$$PinFailureImplCopyWithImpl<$Res>
|
||||
_$PinFailureImpl _value, $Res Function(_$PinFailureImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PinVerificationStatus
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -383,6 +404,8 @@ class __$$PinFailureImplCopyWithImpl<$Res>
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of PinVerificationStatus
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$PivPinFailureReasonCopyWith<$Res> get reason {
|
||||
@ -416,7 +439,9 @@ class _$PinFailureImpl implements PinFailure {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, reason);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PinVerificationStatus
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PinFailureImplCopyWith<_$PinFailureImpl> get copyWith =>
|
||||
@ -489,7 +514,10 @@ abstract class PinFailure implements PinVerificationStatus {
|
||||
factory PinFailure(final PivPinFailureReason reason) = _$PinFailureImpl;
|
||||
|
||||
PivPinFailureReason get reason;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PinVerificationStatus
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PinFailureImplCopyWith<_$PinFailureImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -552,6 +580,9 @@ class _$PivPinFailureReasonCopyWithImpl<$Res, $Val extends PivPinFailureReason>
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PivPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -571,6 +602,8 @@ class __$$PivInvalidPinImplCopyWithImpl<$Res>
|
||||
_$PivInvalidPinImpl _value, $Res Function(_$PivInvalidPinImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -610,7 +643,9 @@ class _$PivInvalidPinImpl implements PivInvalidPin {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, attemptsRemaining);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PivInvalidPinImplCopyWith<_$PivInvalidPinImpl> get copyWith =>
|
||||
@ -683,7 +718,10 @@ abstract class PivInvalidPin implements PivPinFailureReason {
|
||||
factory PivInvalidPin(final int attemptsRemaining) = _$PivInvalidPinImpl;
|
||||
|
||||
int get attemptsRemaining;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PivInvalidPinImplCopyWith<_$PivInvalidPinImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -702,6 +740,9 @@ class __$$PivWeakPinImplCopyWithImpl<$Res>
|
||||
__$$PivWeakPinImplCopyWithImpl(
|
||||
_$PivWeakPinImpl _value, $Res Function(_$PivWeakPinImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivPinFailureReason
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -801,8 +842,12 @@ mixin _$ManagementKeyMetadata {
|
||||
bool get defaultValue => throw _privateConstructorUsedError;
|
||||
TouchPolicy get touchPolicy => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ManagementKeyMetadata to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of ManagementKeyMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ManagementKeyMetadataCopyWith<ManagementKeyMetadata> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -828,6 +873,8 @@ class _$ManagementKeyMetadataCopyWithImpl<$Res,
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ManagementKeyMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -874,6 +921,8 @@ class __$$ManagementKeyMetadataImplCopyWithImpl<$Res>
|
||||
$Res Function(_$ManagementKeyMetadataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of ManagementKeyMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -931,12 +980,14 @@ class _$ManagementKeyMetadataImpl implements _ManagementKeyMetadata {
|
||||
other.touchPolicy == touchPolicy));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, keyType, defaultValue, touchPolicy);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of ManagementKeyMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ManagementKeyMetadataImplCopyWith<_$ManagementKeyMetadataImpl>
|
||||
@ -966,8 +1017,11 @@ abstract class _ManagementKeyMetadata implements ManagementKeyMetadata {
|
||||
bool get defaultValue;
|
||||
@override
|
||||
TouchPolicy get touchPolicy;
|
||||
|
||||
/// Create a copy of ManagementKeyMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ManagementKeyMetadataImplCopyWith<_$ManagementKeyMetadataImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -984,8 +1038,12 @@ mixin _$SlotMetadata {
|
||||
bool get generated => throw _privateConstructorUsedError;
|
||||
String get publicKey => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this SlotMetadata to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of SlotMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$SlotMetadataCopyWith<SlotMetadata> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1014,6 +1072,8 @@ class _$SlotMetadataCopyWithImpl<$Res, $Val extends SlotMetadata>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of SlotMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1072,6 +1132,8 @@ class __$$SlotMetadataImplCopyWithImpl<$Res>
|
||||
_$SlotMetadataImpl _value, $Res Function(_$SlotMetadataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of SlotMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1147,12 +1209,14 @@ class _$SlotMetadataImpl implements _SlotMetadata {
|
||||
other.publicKey == publicKey));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, keyType, pinPolicy, touchPolicy, generated, publicKey);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of SlotMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SlotMetadataImplCopyWith<_$SlotMetadataImpl> get copyWith =>
|
||||
@ -1187,8 +1251,11 @@ abstract class _SlotMetadata implements SlotMetadata {
|
||||
bool get generated;
|
||||
@override
|
||||
String get publicKey;
|
||||
|
||||
/// Create a copy of SlotMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SlotMetadataImplCopyWith<_$SlotMetadataImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1204,8 +1271,12 @@ mixin _$PivStateMetadata {
|
||||
PinMetadata get pinMetadata => throw _privateConstructorUsedError;
|
||||
PinMetadata get pukMetadata => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this PivStateMetadata to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivStateMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PivStateMetadataCopyWith<PivStateMetadata> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1236,6 +1307,8 @@ class _$PivStateMetadataCopyWithImpl<$Res, $Val extends PivStateMetadata>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PivStateMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1259,6 +1332,8 @@ class _$PivStateMetadataCopyWithImpl<$Res, $Val extends PivStateMetadata>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of PivStateMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ManagementKeyMetadataCopyWith<$Res> get managementKeyMetadata {
|
||||
@ -1268,6 +1343,8 @@ class _$PivStateMetadataCopyWithImpl<$Res, $Val extends PivStateMetadata>
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of PivStateMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$PinMetadataCopyWith<$Res> get pinMetadata {
|
||||
@ -1276,6 +1353,8 @@ class _$PivStateMetadataCopyWithImpl<$Res, $Val extends PivStateMetadata>
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of PivStateMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$PinMetadataCopyWith<$Res> get pukMetadata {
|
||||
@ -1314,6 +1393,8 @@ class __$$PivStateMetadataImplCopyWithImpl<$Res>
|
||||
$Res Function(_$PivStateMetadataImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivStateMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1374,12 +1455,14 @@ class _$PivStateMetadataImpl implements _PivStateMetadata {
|
||||
other.pukMetadata == pukMetadata));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, managementKeyMetadata, pinMetadata, pukMetadata);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivStateMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PivStateMetadataImplCopyWith<_$PivStateMetadataImpl> get copyWith =>
|
||||
@ -1409,8 +1492,11 @@ abstract class _PivStateMetadata implements PivStateMetadata {
|
||||
PinMetadata get pinMetadata;
|
||||
@override
|
||||
PinMetadata get pukMetadata;
|
||||
|
||||
/// Create a copy of PivStateMetadata
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PivStateMetadataImplCopyWith<_$PivStateMetadataImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1426,12 +1512,17 @@ mixin _$PivState {
|
||||
bool get derivedKey => throw _privateConstructorUsedError;
|
||||
bool get storedKey => throw _privateConstructorUsedError;
|
||||
int get pinAttempts => throw _privateConstructorUsedError;
|
||||
bool get supportsBio => throw _privateConstructorUsedError;
|
||||
String? get chuid => throw _privateConstructorUsedError;
|
||||
String? get ccc => throw _privateConstructorUsedError;
|
||||
PivStateMetadata? get metadata => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this PivState to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PivStateCopyWith<PivState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1447,6 +1538,7 @@ abstract class $PivStateCopyWith<$Res> {
|
||||
bool derivedKey,
|
||||
bool storedKey,
|
||||
int pinAttempts,
|
||||
bool supportsBio,
|
||||
String? chuid,
|
||||
String? ccc,
|
||||
PivStateMetadata? metadata});
|
||||
@ -1465,6 +1557,8 @@ class _$PivStateCopyWithImpl<$Res, $Val extends PivState>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PivState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1473,6 +1567,7 @@ class _$PivStateCopyWithImpl<$Res, $Val extends PivState>
|
||||
Object? derivedKey = null,
|
||||
Object? storedKey = null,
|
||||
Object? pinAttempts = null,
|
||||
Object? supportsBio = null,
|
||||
Object? chuid = freezed,
|
||||
Object? ccc = freezed,
|
||||
Object? metadata = freezed,
|
||||
@ -1498,6 +1593,10 @@ class _$PivStateCopyWithImpl<$Res, $Val extends PivState>
|
||||
? _value.pinAttempts
|
||||
: pinAttempts // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
supportsBio: null == supportsBio
|
||||
? _value.supportsBio
|
||||
: supportsBio // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
chuid: freezed == chuid
|
||||
? _value.chuid
|
||||
: chuid // ignore: cast_nullable_to_non_nullable
|
||||
@ -1513,6 +1612,8 @@ class _$PivStateCopyWithImpl<$Res, $Val extends PivState>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of PivState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$VersionCopyWith<$Res> get version {
|
||||
@ -1521,6 +1622,8 @@ class _$PivStateCopyWithImpl<$Res, $Val extends PivState>
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of PivState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$PivStateMetadataCopyWith<$Res>? get metadata {
|
||||
@ -1548,6 +1651,7 @@ abstract class _$$PivStateImplCopyWith<$Res>
|
||||
bool derivedKey,
|
||||
bool storedKey,
|
||||
int pinAttempts,
|
||||
bool supportsBio,
|
||||
String? chuid,
|
||||
String? ccc,
|
||||
PivStateMetadata? metadata});
|
||||
@ -1566,6 +1670,8 @@ class __$$PivStateImplCopyWithImpl<$Res>
|
||||
_$PivStateImpl _value, $Res Function(_$PivStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1574,6 +1680,7 @@ class __$$PivStateImplCopyWithImpl<$Res>
|
||||
Object? derivedKey = null,
|
||||
Object? storedKey = null,
|
||||
Object? pinAttempts = null,
|
||||
Object? supportsBio = null,
|
||||
Object? chuid = freezed,
|
||||
Object? ccc = freezed,
|
||||
Object? metadata = freezed,
|
||||
@ -1599,6 +1706,10 @@ class __$$PivStateImplCopyWithImpl<$Res>
|
||||
? _value.pinAttempts
|
||||
: pinAttempts // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
supportsBio: null == supportsBio
|
||||
? _value.supportsBio
|
||||
: supportsBio // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
chuid: freezed == chuid
|
||||
? _value.chuid
|
||||
: chuid // ignore: cast_nullable_to_non_nullable
|
||||
@ -1624,6 +1735,7 @@ class _$PivStateImpl extends _PivState {
|
||||
required this.derivedKey,
|
||||
required this.storedKey,
|
||||
required this.pinAttempts,
|
||||
required this.supportsBio,
|
||||
this.chuid,
|
||||
this.ccc,
|
||||
this.metadata})
|
||||
@ -1643,6 +1755,8 @@ class _$PivStateImpl extends _PivState {
|
||||
@override
|
||||
final int pinAttempts;
|
||||
@override
|
||||
final bool supportsBio;
|
||||
@override
|
||||
final String? chuid;
|
||||
@override
|
||||
final String? ccc;
|
||||
@ -1651,7 +1765,7 @@ class _$PivStateImpl extends _PivState {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PivState(version: $version, authenticated: $authenticated, derivedKey: $derivedKey, storedKey: $storedKey, pinAttempts: $pinAttempts, chuid: $chuid, ccc: $ccc, metadata: $metadata)';
|
||||
return 'PivState(version: $version, authenticated: $authenticated, derivedKey: $derivedKey, storedKey: $storedKey, pinAttempts: $pinAttempts, supportsBio: $supportsBio, chuid: $chuid, ccc: $ccc, metadata: $metadata)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -1668,18 +1782,22 @@ class _$PivStateImpl extends _PivState {
|
||||
other.storedKey == storedKey) &&
|
||||
(identical(other.pinAttempts, pinAttempts) ||
|
||||
other.pinAttempts == pinAttempts) &&
|
||||
(identical(other.supportsBio, supportsBio) ||
|
||||
other.supportsBio == supportsBio) &&
|
||||
(identical(other.chuid, chuid) || other.chuid == chuid) &&
|
||||
(identical(other.ccc, ccc) || other.ccc == ccc) &&
|
||||
(identical(other.metadata, metadata) ||
|
||||
other.metadata == metadata));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, version, authenticated,
|
||||
derivedKey, storedKey, pinAttempts, chuid, ccc, metadata);
|
||||
derivedKey, storedKey, pinAttempts, supportsBio, chuid, ccc, metadata);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PivStateImplCopyWith<_$PivStateImpl> get copyWith =>
|
||||
@ -1700,6 +1818,7 @@ abstract class _PivState extends PivState {
|
||||
required final bool derivedKey,
|
||||
required final bool storedKey,
|
||||
required final int pinAttempts,
|
||||
required final bool supportsBio,
|
||||
final String? chuid,
|
||||
final String? ccc,
|
||||
final PivStateMetadata? metadata}) = _$PivStateImpl;
|
||||
@ -1719,13 +1838,18 @@ abstract class _PivState extends PivState {
|
||||
@override
|
||||
int get pinAttempts;
|
||||
@override
|
||||
bool get supportsBio;
|
||||
@override
|
||||
String? get chuid;
|
||||
@override
|
||||
String? get ccc;
|
||||
@override
|
||||
PivStateMetadata? get metadata;
|
||||
|
||||
/// Create a copy of PivState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PivStateImplCopyWith<_$PivStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1744,8 +1868,12 @@ mixin _$CertInfo {
|
||||
String get notValidAfter => throw _privateConstructorUsedError;
|
||||
String get fingerprint => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this CertInfo to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of CertInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$CertInfoCopyWith<CertInfo> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -1775,6 +1903,8 @@ class _$CertInfoCopyWithImpl<$Res, $Val extends CertInfo>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of CertInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1845,6 +1975,8 @@ class __$$CertInfoImplCopyWithImpl<$Res>
|
||||
_$CertInfoImpl _value, $Res Function(_$CertInfoImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of CertInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -1941,12 +2073,14 @@ class _$CertInfoImpl implements _CertInfo {
|
||||
other.fingerprint == fingerprint));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, keyType, subject, issuer, serial,
|
||||
notValidBefore, notValidAfter, fingerprint);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of CertInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$CertInfoImplCopyWith<_$CertInfoImpl> get copyWith =>
|
||||
@ -1987,8 +2121,11 @@ abstract class _CertInfo implements CertInfo {
|
||||
String get notValidAfter;
|
||||
@override
|
||||
String get fingerprint;
|
||||
|
||||
/// Create a copy of CertInfo
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$CertInfoImplCopyWith<_$CertInfoImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -2003,8 +2140,12 @@ mixin _$PivSlot {
|
||||
SlotMetadata? get metadata => throw _privateConstructorUsedError;
|
||||
CertInfo? get certInfo => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this PivSlot to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PivSlotCopyWith<PivSlot> get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
@ -2029,6 +2170,8 @@ class _$PivSlotCopyWithImpl<$Res, $Val extends PivSlot>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PivSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -2052,6 +2195,8 @@ class _$PivSlotCopyWithImpl<$Res, $Val extends PivSlot>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of PivSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SlotMetadataCopyWith<$Res>? get metadata {
|
||||
@ -2064,6 +2209,8 @@ class _$PivSlotCopyWithImpl<$Res, $Val extends PivSlot>
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a copy of PivSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$CertInfoCopyWith<$Res>? get certInfo {
|
||||
@ -2100,6 +2247,8 @@ class __$$PivSlotImplCopyWithImpl<$Res>
|
||||
_$PivSlotImpl _value, $Res Function(_$PivSlotImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -2156,11 +2305,13 @@ class _$PivSlotImpl implements _PivSlot {
|
||||
other.certInfo == certInfo));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, slot, metadata, certInfo);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PivSlotImplCopyWith<_$PivSlotImpl> get copyWith =>
|
||||
@ -2188,8 +2339,11 @@ abstract class _PivSlot implements PivSlot {
|
||||
SlotMetadata? get metadata;
|
||||
@override
|
||||
CertInfo? get certInfo;
|
||||
|
||||
/// Create a copy of PivSlot
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PivSlotImplCopyWith<_$PivSlotImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -2251,6 +2405,8 @@ mixin _$PivExamineResult {
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this PivExamineResult to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
@ -2270,6 +2426,9 @@ class _$PivExamineResultCopyWithImpl<$Res, $Val extends PivExamineResult>
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PivExamineResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -2291,6 +2450,8 @@ class __$$ExamineResultImplCopyWithImpl<$Res>
|
||||
_$ExamineResultImpl _value, $Res Function(_$ExamineResultImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivExamineResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -2314,6 +2475,8 @@ class __$$ExamineResultImplCopyWithImpl<$Res>
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of PivExamineResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$CertInfoCopyWith<$Res>? get certInfo {
|
||||
@ -2367,11 +2530,13 @@ class _$ExamineResultImpl implements _ExamineResult {
|
||||
other.certInfo == certInfo));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, password, keyType, certInfo);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivExamineResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ExamineResultImplCopyWith<_$ExamineResultImpl> get copyWith =>
|
||||
@ -2463,7 +2628,10 @@ abstract class _ExamineResult implements PivExamineResult {
|
||||
bool get password;
|
||||
KeyType? get keyType;
|
||||
CertInfo? get certInfo;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivExamineResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ExamineResultImplCopyWith<_$ExamineResultImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -2482,6 +2650,9 @@ class __$$InvalidPasswordImplCopyWithImpl<$Res>
|
||||
__$$InvalidPasswordImplCopyWithImpl(
|
||||
_$InvalidPasswordImpl _value, $Res Function(_$InvalidPasswordImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivExamineResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -2507,7 +2678,7 @@ class _$InvalidPasswordImpl implements _InvalidPassword {
|
||||
(other.runtimeType == runtimeType && other is _$InvalidPasswordImpl);
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@ -2661,6 +2832,9 @@ class _$PivGenerateParametersCopyWithImpl<$Res,
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PivGenerateParameters
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -2677,6 +2851,9 @@ class __$$GeneratePublicKeyImplCopyWithImpl<$Res>
|
||||
__$$GeneratePublicKeyImplCopyWithImpl(_$GeneratePublicKeyImpl _value,
|
||||
$Res Function(_$GeneratePublicKeyImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivGenerateParameters
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -2792,6 +2969,8 @@ class __$$GenerateCertificateImplCopyWithImpl<$Res>
|
||||
$Res Function(_$GenerateCertificateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivGenerateParameters
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -2848,7 +3027,9 @@ class _$GenerateCertificateImpl implements _GenerateCertificate {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, subject, validFrom, validTo);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivGenerateParameters
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$GenerateCertificateImplCopyWith<_$GenerateCertificateImpl> get copyWith =>
|
||||
@ -2937,7 +3118,10 @@ abstract class _GenerateCertificate implements PivGenerateParameters {
|
||||
String get subject;
|
||||
DateTime get validFrom;
|
||||
DateTime get validTo;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivGenerateParameters
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$GenerateCertificateImplCopyWith<_$GenerateCertificateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -2959,6 +3143,8 @@ class __$$GenerateCsrImplCopyWithImpl<$Res>
|
||||
_$GenerateCsrImpl _value, $Res Function(_$GenerateCsrImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivGenerateParameters
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -2997,7 +3183,9 @@ class _$GenerateCsrImpl implements _GenerateCsr {
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, subject);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivGenerateParameters
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$GenerateCsrImplCopyWith<_$GenerateCsrImpl> get copyWith =>
|
||||
@ -3080,7 +3268,10 @@ abstract class _GenerateCsr implements PivGenerateParameters {
|
||||
factory _GenerateCsr({required final String subject}) = _$GenerateCsrImpl;
|
||||
|
||||
String get subject;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivGenerateParameters
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$GenerateCsrImplCopyWith<_$GenerateCsrImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -3095,8 +3286,12 @@ mixin _$PivGenerateResult {
|
||||
String get publicKey => throw _privateConstructorUsedError;
|
||||
String? get result => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this PivGenerateResult to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivGenerateResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PivGenerateResultCopyWith<PivGenerateResult> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -3120,6 +3315,8 @@ class _$PivGenerateResultCopyWithImpl<$Res, $Val extends PivGenerateResult>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PivGenerateResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -3163,6 +3360,8 @@ class __$$PivGenerateResultImplCopyWithImpl<$Res>
|
||||
$Res Function(_$PivGenerateResultImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivGenerateResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -3220,11 +3419,13 @@ class _$PivGenerateResultImpl implements _PivGenerateResult {
|
||||
(identical(other.result, result) || other.result == result));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, generateType, publicKey, result);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivGenerateResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PivGenerateResultImplCopyWith<_$PivGenerateResultImpl> get copyWith =>
|
||||
@ -3254,8 +3455,11 @@ abstract class _PivGenerateResult implements PivGenerateResult {
|
||||
String get publicKey;
|
||||
@override
|
||||
String? get result;
|
||||
|
||||
/// Create a copy of PivGenerateResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PivGenerateResultImplCopyWith<_$PivGenerateResultImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -3270,8 +3474,12 @@ mixin _$PivImportResult {
|
||||
String? get publicKey => throw _privateConstructorUsedError;
|
||||
String? get certificate => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this PivImportResult to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
|
||||
/// Create a copy of PivImportResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PivImportResultCopyWith<PivImportResult> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -3297,6 +3505,8 @@ class _$PivImportResultCopyWithImpl<$Res, $Val extends PivImportResult>
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PivImportResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -3320,6 +3530,8 @@ class _$PivImportResultCopyWithImpl<$Res, $Val extends PivImportResult>
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of PivImportResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SlotMetadataCopyWith<$Res>? get metadata {
|
||||
@ -3355,6 +3567,8 @@ class __$$PivImportResultImplCopyWithImpl<$Res>
|
||||
_$PivImportResultImpl _value, $Res Function(_$PivImportResultImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of PivImportResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
@ -3415,12 +3629,14 @@ class _$PivImportResultImpl implements _PivImportResult {
|
||||
other.certificate == certificate));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, metadata, publicKey, certificate);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
/// Create a copy of PivImportResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PivImportResultImplCopyWith<_$PivImportResultImpl> get copyWith =>
|
||||
@ -3450,8 +3666,11 @@ abstract class _PivImportResult implements PivImportResult {
|
||||
String? get publicKey;
|
||||
@override
|
||||
String? get certificate;
|
||||
|
||||
/// Create a copy of PivImportResult
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PivImportResultImplCopyWith<_$PivImportResultImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ _$PivStateImpl _$$PivStateImplFromJson(Map<String, dynamic> json) =>
|
||||
derivedKey: json['derived_key'] as bool,
|
||||
storedKey: json['stored_key'] as bool,
|
||||
pinAttempts: (json['pin_attempts'] as num).toInt(),
|
||||
supportsBio: json['supports_bio'] as bool,
|
||||
chuid: json['chuid'] as String?,
|
||||
ccc: json['ccc'] as String?,
|
||||
metadata: json['metadata'] == null
|
||||
@ -128,6 +129,7 @@ Map<String, dynamic> _$$PivStateImplToJson(_$PivStateImpl instance) =>
|
||||
'derived_key': instance.derivedKey,
|
||||
'stored_key': instance.storedKey,
|
||||
'pin_attempts': instance.pinAttempts,
|
||||
'supports_bio': instance.supportsBio,
|
||||
'chuid': instance.chuid,
|
||||
'ccc': instance.ccc,
|
||||
'metadata': instance.metadata,
|
||||
|
@ -310,7 +310,16 @@ class PivActions extends ConsumerWidget {
|
||||
}
|
||||
|
||||
List<ActionItem> buildSlotActions(
|
||||
PivState pivState, PivSlot slot, AppLocalizations l10n) {
|
||||
PivState pivState, PivSlot slot, bool fipsUnready, AppLocalizations l10n) {
|
||||
if (fipsUnready) {
|
||||
// TODO: Decide on final look and move strings to .arb file.
|
||||
return [
|
||||
ActionItem(
|
||||
icon: const Icon(Symbols.add),
|
||||
title: 'Provision slot',
|
||||
subtitle: 'Change from default PIN/PUK/Management key first'),
|
||||
];
|
||||
}
|
||||
final hasCert = slot.certInfo != null;
|
||||
final hasKey = slot.metadata != null;
|
||||
final canDeleteOrMoveKey = hasKey && pivState.version.isAtLeast(5, 7);
|
||||
|
@ -36,8 +36,9 @@ class GenerateKeyDialog extends ConsumerStatefulWidget {
|
||||
final DevicePath devicePath;
|
||||
final PivState pivState;
|
||||
final PivSlot pivSlot;
|
||||
const GenerateKeyDialog(this.devicePath, this.pivState, this.pivSlot,
|
||||
{super.key});
|
||||
final bool showMatch;
|
||||
GenerateKeyDialog(this.devicePath, this.pivState, this.pivSlot, {super.key})
|
||||
: showMatch = pivSlot.slot != SlotId.cardAuth && pivState.supportsBio;
|
||||
|
||||
@override
|
||||
ConsumerState<ConsumerStatefulWidget> createState() =>
|
||||
@ -53,6 +54,7 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
late DateTime _validTo;
|
||||
late DateTime _validToDefault;
|
||||
late DateTime _validToMax;
|
||||
late bool _allowMatch;
|
||||
bool _generating = false;
|
||||
|
||||
@override
|
||||
@ -64,6 +66,8 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
_validToDefault = DateTime.utc(now.year + 1, now.month, now.day);
|
||||
_validTo = _validToDefault;
|
||||
_validToMax = DateTime.utc(now.year + 10, now.month, now.day);
|
||||
|
||||
_allowMatch = widget.showMatch;
|
||||
}
|
||||
|
||||
@override
|
||||
@ -117,6 +121,7 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
final result = await pivNotifier.generate(
|
||||
widget.pivSlot.slot,
|
||||
_keyType,
|
||||
pinPolicy: getPinPolicy(widget.pivSlot.slot, _allowMatch),
|
||||
parameters: switch (_generateType) {
|
||||
GenerateType.publicKey =>
|
||||
PivGenerateParameters.publicKey(),
|
||||
@ -183,7 +188,9 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
l10n.s_options,
|
||||
style: textTheme.bodyLarge,
|
||||
),
|
||||
Text(l10n.p_cert_options_desc),
|
||||
Text(widget.showMatch
|
||||
? l10n.p_cert_options_bio_desc
|
||||
: l10n.p_cert_options_desc),
|
||||
Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: 4.0,
|
||||
@ -238,6 +245,16 @@ class _GenerateKeyDialogState extends ConsumerState<GenerateKeyDialog> {
|
||||
}
|
||||
},
|
||||
),
|
||||
if (widget.showMatch)
|
||||
FilterChip(
|
||||
label: Text(l10n.s_allow_fingerprint),
|
||||
selected: _allowMatch,
|
||||
onSelected: (value) {
|
||||
setState(() {
|
||||
_allowMatch = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
]),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
|
@ -39,9 +39,10 @@ class ImportFileDialog extends ConsumerStatefulWidget {
|
||||
final PivState pivState;
|
||||
final PivSlot pivSlot;
|
||||
final File file;
|
||||
const ImportFileDialog(
|
||||
this.devicePath, this.pivState, this.pivSlot, this.file,
|
||||
{super.key});
|
||||
final bool showMatch;
|
||||
ImportFileDialog(this.devicePath, this.pivState, this.pivSlot, this.file,
|
||||
{super.key})
|
||||
: showMatch = pivSlot.slot != SlotId.cardAuth && pivState.supportsBio;
|
||||
|
||||
@override
|
||||
ConsumerState<ConsumerStatefulWidget> createState() =>
|
||||
@ -50,6 +51,7 @@ class ImportFileDialog extends ConsumerStatefulWidget {
|
||||
|
||||
class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
late String _data;
|
||||
late bool _allowMatch;
|
||||
PivExamineResult? _state;
|
||||
String _password = '';
|
||||
bool _passwordIsWrong = false;
|
||||
@ -59,6 +61,8 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_allowMatch = widget.showMatch;
|
||||
_init();
|
||||
}
|
||||
|
||||
@ -214,9 +218,13 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
));
|
||||
await ref
|
||||
.read(pivSlotsProvider(widget.devicePath).notifier)
|
||||
.import(widget.pivSlot.slot, _data,
|
||||
password:
|
||||
_password.isNotEmpty ? _password : null);
|
||||
.import(
|
||||
widget.pivSlot.slot,
|
||||
_data,
|
||||
password: _password.isNotEmpty ? _password : null,
|
||||
pinPolicy: getPinPolicy(
|
||||
widget.pivSlot.slot, _allowMatch),
|
||||
);
|
||||
await withContext(
|
||||
(context) async {
|
||||
Navigator.of(context).pop(true);
|
||||
@ -284,6 +292,16 @@ class _ImportFileDialogState extends ConsumerState<ImportFileDialog> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!unsupportedKey && widget.showMatch)
|
||||
FilterChip(
|
||||
label: Text(l10n.s_allow_fingerprint),
|
||||
selected: _allowMatch,
|
||||
onSelected: (value) {
|
||||
setState(() {
|
||||
_allowMatch = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
if (certInfo != null) ...[
|
||||
Text(
|
||||
|
@ -25,6 +25,7 @@ import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../core/models.dart';
|
||||
import '../../management/models.dart';
|
||||
import '../../widgets/app_input_decoration.dart';
|
||||
import '../../widgets/app_text_field.dart';
|
||||
import '../../widgets/app_text_form_field.dart';
|
||||
@ -176,6 +177,17 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
? currentKeyOrPin.length >= 4
|
||||
: currentKeyOrPin.length == currentType.keyLength * 2;
|
||||
final newLenOk = _keyController.text.length == hexLength;
|
||||
final (fipsCapable, fipsApproved) = ref
|
||||
.watch(currentDeviceDataProvider)
|
||||
.valueOrNull
|
||||
?.info
|
||||
.getFipsStatus(Capability.piv) ??
|
||||
(false, false);
|
||||
final fipsUnready = fipsCapable && !fipsApproved;
|
||||
final managementKeyTypes = ManagementKeyType.values.toList();
|
||||
if (fipsCapable) {
|
||||
managementKeyTypes.remove(ManagementKeyType.tdes);
|
||||
}
|
||||
|
||||
return ResponsiveDialog(
|
||||
title: Text(l10n.l_change_management_key),
|
||||
@ -334,7 +346,7 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
children: [
|
||||
if (widget.pivState.metadata != null)
|
||||
ChoiceFilterChip<ManagementKeyType>(
|
||||
items: ManagementKeyType.values,
|
||||
items: managementKeyTypes,
|
||||
value: _keyType,
|
||||
selected: _keyType != currentType,
|
||||
itemBuilder: (value) => Text(value.getDisplayName(l10n)),
|
||||
@ -344,16 +356,17 @@ class _ManageKeyDialogState extends ConsumerState<ManageKeyDialog> {
|
||||
});
|
||||
},
|
||||
),
|
||||
FilterChip(
|
||||
key: keys.pinLockManagementKeyChip,
|
||||
label: Text(l10n.s_protect_key),
|
||||
selected: _storeKey,
|
||||
onSelected: (value) {
|
||||
setState(() {
|
||||
_storeKey = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
if (!fipsUnready)
|
||||
FilterChip(
|
||||
key: keys.pinLockManagementKeyChip,
|
||||
label: Text(l10n.s_protect_key),
|
||||
selected: _storeKey,
|
||||
onSelected: (value) {
|
||||
setState(() {
|
||||
_storeKey = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
]),
|
||||
]
|
||||
.map((e) => Padding(
|
||||
|
@ -24,6 +24,7 @@ import 'package:material_symbols_icons/symbols.dart';
|
||||
import '../../app/message.dart';
|
||||
import '../../app/models.dart';
|
||||
import '../../app/shortcuts.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../app/views/action_list.dart';
|
||||
import '../../app/views/app_failure_page.dart';
|
||||
import '../../app/views/app_list_item.dart';
|
||||
@ -57,6 +58,14 @@ class _PivScreenState extends ConsumerState<PivScreen> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final hasFeature = ref.watch(featureProvider);
|
||||
final (fipsCapable, fipsApproved) = ref
|
||||
.watch(currentDeviceDataProvider)
|
||||
.valueOrNull
|
||||
?.info
|
||||
.getFipsStatus(Capability.piv) ??
|
||||
(false, false);
|
||||
final fipsUnready = fipsCapable && !fipsApproved;
|
||||
|
||||
return ref.watch(pivStateProvider(widget.devicePath)).when(
|
||||
loading: () => MessagePage(
|
||||
title: l10n.s_certificates,
|
||||
@ -168,8 +177,8 @@ class _PivScreenState extends ConsumerState<PivScreen> {
|
||||
ActionListSection.fromMenuActions(
|
||||
context,
|
||||
l10n.s_actions,
|
||||
actions:
|
||||
buildSlotActions(pivState, selected, l10n),
|
||||
actions: buildSlotActions(
|
||||
pivState, selected, fipsUnready, l10n),
|
||||
),
|
||||
],
|
||||
)
|
||||
@ -200,25 +209,30 @@ class _PivScreenState extends ConsumerState<PivScreen> {
|
||||
return null;
|
||||
}),
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
...normalSlots.map(
|
||||
(e) => _CertificateListItem(
|
||||
pivState,
|
||||
e,
|
||||
expanded: expanded,
|
||||
selected: e == selected,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Column(
|
||||
children: [
|
||||
...normalSlots.map(
|
||||
(e) => _CertificateListItem(
|
||||
pivState,
|
||||
e,
|
||||
expanded: expanded,
|
||||
selected: e == selected,
|
||||
fipsUnready: fipsUnready,
|
||||
),
|
||||
),
|
||||
),
|
||||
...shownRetiredSlots.map(
|
||||
(e) => _CertificateListItem(
|
||||
pivState,
|
||||
e,
|
||||
expanded: expanded,
|
||||
selected: e == selected,
|
||||
),
|
||||
)
|
||||
],
|
||||
...shownRetiredSlots.map(
|
||||
(e) => _CertificateListItem(
|
||||
pivState,
|
||||
e,
|
||||
expanded: expanded,
|
||||
selected: e == selected,
|
||||
fipsUnready: fipsUnready,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -235,9 +249,12 @@ class _CertificateListItem extends ConsumerWidget {
|
||||
final PivSlot pivSlot;
|
||||
final bool expanded;
|
||||
final bool selected;
|
||||
final bool fipsUnready;
|
||||
|
||||
const _CertificateListItem(this.pivState, this.pivSlot,
|
||||
{required this.expanded, required this.selected});
|
||||
{required this.expanded,
|
||||
required this.selected,
|
||||
required this.fipsUnready});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@ -272,8 +289,8 @@ class _CertificateListItem extends ConsumerWidget {
|
||||
),
|
||||
tapIntent: isDesktop && !expanded ? null : OpenIntent(pivSlot),
|
||||
doubleTapIntent: isDesktop && !expanded ? OpenIntent(pivSlot) : null,
|
||||
buildPopupActions: hasFeature(features.slots)
|
||||
? (context) => buildSlotActions(pivState, pivSlot, l10n)
|
||||
buildPopupActions: hasFeature(features.slots) && !fipsUnready
|
||||
? (context) => buildSlotActions(pivState, pivSlot, fipsUnready, l10n)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import '../../app/shortcuts.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../app/views/action_list.dart';
|
||||
import '../../app/views/fs_dialog.dart';
|
||||
import '../../management/models.dart';
|
||||
import '../models.dart';
|
||||
import '../state.dart';
|
||||
import 'actions.dart';
|
||||
@ -34,12 +35,13 @@ class SlotDialog extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// TODO: Solve this in a cleaner way
|
||||
final node = ref.watch(currentDeviceDataProvider).valueOrNull?.node;
|
||||
if (node == null) {
|
||||
var keyData = ref.watch(currentDeviceDataProvider).valueOrNull;
|
||||
if (keyData == null) {
|
||||
// The rest of this method assumes there is a device, and will throw an exception if not.
|
||||
// This will never be shown, as the dialog will be immediately closed
|
||||
return const SizedBox();
|
||||
}
|
||||
final devicePath = keyData.node.path;
|
||||
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final textTheme = Theme.of(context).textTheme;
|
||||
@ -48,8 +50,11 @@ class SlotDialog extends ConsumerWidget {
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
);
|
||||
|
||||
final pivState = ref.watch(pivStateProvider(node.path)).valueOrNull;
|
||||
final slotData = ref.watch(pivSlotsProvider(node.path).select((value) =>
|
||||
final (fipsCapable, fipsApproved) =
|
||||
keyData.info.getFipsStatus(Capability.piv);
|
||||
|
||||
final pivState = ref.watch(pivStateProvider(devicePath)).valueOrNull;
|
||||
final slotData = ref.watch(pivSlotsProvider(devicePath).select((value) =>
|
||||
value.whenOrNull(
|
||||
data: (data) =>
|
||||
data.firstWhere((element) => element.slot == pivSlot))));
|
||||
@ -61,7 +66,7 @@ class SlotDialog extends ConsumerWidget {
|
||||
final certInfo = slotData.certInfo;
|
||||
final metadata = slotData.metadata;
|
||||
return PivActions(
|
||||
devicePath: node.path,
|
||||
devicePath: devicePath,
|
||||
pivState: pivState,
|
||||
builder: (context) => ItemShortcuts(
|
||||
item: slotData,
|
||||
@ -113,7 +118,8 @@ class SlotDialog extends ConsumerWidget {
|
||||
ActionListSection.fromMenuActions(
|
||||
context,
|
||||
l10n.s_actions,
|
||||
actions: buildSlotActions(pivState, slotData, l10n),
|
||||
actions: buildSlotActions(
|
||||
pivState, slotData, fipsCapable && !fipsApproved, l10n),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -29,3 +29,13 @@ List<KeyType> getSupportedKeyTypes(Version version, bool isFips) => [
|
||||
KeyType.eccp256,
|
||||
KeyType.eccp384,
|
||||
];
|
||||
|
||||
PinPolicy getPinPolicy(SlotId slot, bool match) {
|
||||
if (match) {
|
||||
if (slot == SlotId.signature) {
|
||||
return PinPolicy.matchAlways;
|
||||
}
|
||||
return PinPolicy.matchOnce;
|
||||
}
|
||||
return PinPolicy.dfault;
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Yubico.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
final Widget pushPinStrokeIcon = Builder(builder: (context) {
|
||||
return CustomPaint(
|
||||
painter: _StrikethroughPainter(IconTheme.of(context).color ?? Colors.black),
|
||||
child: ClipPath(
|
||||
clipper: _StrikethroughClipper(), child: const Icon(Symbols.push_pin)),
|
||||
);
|
||||
});
|
||||
|
||||
class _StrikethroughClipper extends CustomClipper<Path> {
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
Path path = Path()
|
||||
..moveTo(0, 2)
|
||||
..lineTo(0, size.height)
|
||||
..lineTo(size.width - 2, size.height)
|
||||
..lineTo(0, 2)
|
||||
..moveTo(2, 0)
|
||||
..lineTo(size.width, size.height - 2)
|
||||
..lineTo(size.width, 0)
|
||||
..lineTo(2, 0)
|
||||
..close();
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class _StrikethroughPainter extends CustomPainter {
|
||||
final Color color;
|
||||
_StrikethroughPainter(this.color);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = color
|
||||
..strokeWidth = 1.3;
|
||||
|
||||
canvas.drawLine(Offset(size.width * 0.15, size.height * 0.15),
|
||||
Offset(size.width * 0.8, size.height * 0.8), paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant CustomPainter oldDelegate) {
|
||||
return false;
|
||||
}
|
||||
}
|
111
lib/widgets/flex_box.dart
Normal file
111
lib/widgets/flex_box.dart
Normal file
@ -0,0 +1,111 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
enum FlexLayout {
|
||||
list,
|
||||
grid;
|
||||
|
||||
IconData get icon => switch (this) {
|
||||
FlexLayout.list => Symbols.list,
|
||||
FlexLayout.grid => Symbols.grid_view
|
||||
};
|
||||
String getDisplayName(AppLocalizations l10n) => switch (this) {
|
||||
FlexLayout.list => l10n.s_list_layout,
|
||||
FlexLayout.grid => l10n.s_grid_layout
|
||||
};
|
||||
}
|
||||
|
||||
class FlexBox<T> extends StatelessWidget {
|
||||
final List<T> items;
|
||||
final Widget Function(T value) itemBuilder;
|
||||
final FlexLayout layout;
|
||||
final double cellMinWidth;
|
||||
final double spacing;
|
||||
final double runSpacing;
|
||||
const FlexBox({
|
||||
super.key,
|
||||
required this.items,
|
||||
required this.itemBuilder,
|
||||
required this.cellMinWidth,
|
||||
this.layout = FlexLayout.list,
|
||||
this.spacing = 0.0,
|
||||
this.runSpacing = 0.0,
|
||||
});
|
||||
|
||||
int _getItemsPerRow(double width) {
|
||||
// Calculate the maximum number of cells that can fit in one row
|
||||
int cellsPerRow = (width / (cellMinWidth + spacing)).floor();
|
||||
|
||||
// Ensure there's at least one cell per row
|
||||
if (cellsPerRow < 1) {
|
||||
cellsPerRow = 1;
|
||||
}
|
||||
|
||||
// Calculate the total width needed for the calculated number of cells and spacing
|
||||
double totalWidthNeeded =
|
||||
cellsPerRow * cellMinWidth + (cellsPerRow - 1) * spacing;
|
||||
|
||||
// Adjust the number of cells per row if the calculated total width exceeds the available width
|
||||
if (totalWidthNeeded > width) {
|
||||
cellsPerRow = cellsPerRow - 1 > 0 ? cellsPerRow - 1 : 1;
|
||||
}
|
||||
|
||||
return cellsPerRow;
|
||||
}
|
||||
|
||||
List<List<T>> getChunks(int itemsPerChunk) {
|
||||
List<List<T>> chunks = [];
|
||||
final numChunks = (items.length / itemsPerChunk).ceil();
|
||||
for (int i = 0; i < numChunks; i++) {
|
||||
final index = i * itemsPerChunk;
|
||||
int endIndex = index + itemsPerChunk;
|
||||
|
||||
if (endIndex > items.length) {
|
||||
endIndex = items.length;
|
||||
}
|
||||
|
||||
chunks.add(items.sublist(index, endIndex));
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final width = constraints.maxWidth;
|
||||
final itemsPerRow =
|
||||
layout == FlexLayout.grid ? _getItemsPerRow(width) : 1;
|
||||
final chunks = getChunks(itemsPerRow);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
for (final c in chunks) ...[
|
||||
if (chunks.indexOf(c) > 0) SizedBox(height: runSpacing),
|
||||
Row(
|
||||
children: [
|
||||
for (final entry in c) ...[
|
||||
Flexible(
|
||||
child: itemBuilder(entry),
|
||||
),
|
||||
if (itemsPerRow != 1 && c.indexOf(entry) != c.length - 1)
|
||||
SizedBox(width: spacing),
|
||||
],
|
||||
if (c.length < itemsPerRow) ...[
|
||||
// Prevents resizing when an item is removed
|
||||
SizedBox(width: 8 * (itemsPerRow - c.length).toDouble()),
|
||||
Spacer(
|
||||
flex: itemsPerRow - c.length,
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
]
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -102,7 +102,7 @@ class _ResponsiveDialogState extends State<ResponsiveDialog> {
|
||||
...widget.actions
|
||||
],
|
||||
),
|
||||
onPopInvoked: (didPop) {
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (didPop) {
|
||||
widget.onCancel?.call();
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
class Toast extends StatefulWidget {
|
||||
final String message;
|
||||
@ -149,5 +150,7 @@ void Function() showToast(
|
||||
Overlay.of(context).insert(entry!);
|
||||
});
|
||||
|
||||
SemanticsService.announce(message, TextDirection.ltr);
|
||||
|
||||
return close;
|
||||
}
|
||||
|
@ -63,4 +63,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7
|
||||
|
||||
COCOAPODS: 1.14.3
|
||||
COCOAPODS: 1.15.2
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Cocoa
|
||||
import FlutterMacOS
|
||||
|
||||
@NSApplicationMain
|
||||
@main
|
||||
class AppDelegate: FlutterAppDelegate {
|
||||
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||
// Keep app running if window closes
|
||||
|
12
macos_assemble.patch
Normal file
12
macos_assemble.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/packages/flutter_tools/bin/macos_assemble.sh b/packages/flutter_tools/bin/macos_assemble.sh
|
||||
index 40c6a5051f..a7f05d9113 100755
|
||||
--- a/packages/flutter_tools/bin/macos_assemble.sh
|
||||
+++ b/packages/flutter_tools/bin/macos_assemble.sh
|
||||
@@ -222,6 +222,7 @@ EmbedFrameworks() {
|
||||
|
||||
# Iterate through all .frameworks in native assets directory.
|
||||
for native_asset in "${native_assets_path}"*.framework; do
|
||||
+ [ -e "$native_asset" ] || continue # Skip when there are no matches.
|
||||
# Codesign the framework inside the app bundle.
|
||||
RunCommand codesign --force --verbose --sign "${EXPANDED_CODE_SIGN_IDENTITY}" -- "${xcode_frameworks_dir}/$(basename "$native_asset")"
|
||||
done
|
179
pubspec.lock
179
pubspec.lock
@ -5,18 +5,23 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
|
||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "67.0.0"
|
||||
version: "72.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.2"
|
||||
analyzer:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
|
||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.4.1"
|
||||
version: "6.7.0"
|
||||
analyzer_plugin:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -101,18 +106,18 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7"
|
||||
sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.11"
|
||||
version: "2.4.12"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe
|
||||
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.3.1"
|
||||
version: "7.3.2"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -197,18 +202,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cross_file
|
||||
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
|
||||
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.4+1"
|
||||
version: "0.3.4+2"
|
||||
crypto:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: crypto
|
||||
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
||||
sha256: "1dceb0cf05cb63a7852c11560060e53ec2f182079a16ced6f4395c5b0875baf8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.0.4"
|
||||
custom_lint:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -261,10 +266,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
||||
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.3"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -277,10 +282,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_picker
|
||||
sha256: "824f5b9f389bfc4dddac3dea76cd70c51092d9dff0b2ece7ef4f53db8547d258"
|
||||
sha256: "1375f8685ca6f0412effecc2db834757e9d0e3e055468053e563794b0755cdcd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.0.6"
|
||||
version: "8.1.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -316,10 +321,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e
|
||||
sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.20"
|
||||
version: "2.0.21"
|
||||
flutter_riverpod:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -342,18 +347,18 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: freezed
|
||||
sha256: a434911f643466d78462625df76fd9eb13e57348ff43fe1f77bbe909522c67a1
|
||||
sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
version: "2.5.7"
|
||||
freezed_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: freezed_annotation
|
||||
sha256: f54946fdb1fa7b01f780841937b1a80783a20b393485f3f6cdf336fd6f4705f2
|
||||
sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
version: "2.4.4"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -379,10 +384,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
|
||||
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
version: "2.3.2"
|
||||
hotreloader:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -395,10 +400,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.2"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -464,18 +469,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.4"
|
||||
version: "10.0.5"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.0.5"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -515,6 +520,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
macros:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2-main.4"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -527,18 +540,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.0"
|
||||
version: "0.11.1"
|
||||
material_symbols_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: material_symbols_icons
|
||||
sha256: a2c78726048c755f0f90fd2b7c8799cd94338e2e9b7ab6498ae56503262c14bc
|
||||
sha256: "8f4abdb6bc714526ccf66e825b7391d7ca65239484ad92be71980fe73a57521c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2762.0"
|
||||
version: "4.2780.0"
|
||||
menu_base:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -551,10 +564,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.0"
|
||||
version: "1.15.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -591,18 +604,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
||||
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "2.1.4"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a
|
||||
sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.6"
|
||||
version: "2.2.10"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -631,10 +644,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
version: "2.3.0"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -647,10 +660,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
version: "3.1.5"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -726,58 +739,58 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
|
||||
sha256: c272f9cabca5a81adc9b0894381e9c1def363e980f960fa903c604c471b22f68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
version: "2.3.1"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577"
|
||||
sha256: a7e8467e9181cef109f601e3f65765685786c1a738a83d7fbbde377589c0d974
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
version: "2.3.1"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
|
||||
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.5.2"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
|
||||
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.4.2"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.4.1"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -899,10 +912,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
version: "0.7.2"
|
||||
test_res:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -946,26 +959,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: ceb2625f0c24ade6ef6778d1de0b2e44f2db71fded235eb52295247feba8c5cf
|
||||
sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.3"
|
||||
version: "6.3.9"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
|
||||
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.0"
|
||||
version: "6.3.1"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
|
||||
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
version: "3.2.0"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -986,26 +999,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
|
||||
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
version: "2.3.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
|
||||
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
version: "3.1.2"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
|
||||
sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.0"
|
||||
version: "4.4.2"
|
||||
vector_graphics:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1042,10 +1055,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.1"
|
||||
version: "14.2.4"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1058,26 +1071,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
version: "1.0.0"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "24301d8c293ce6fe327ffe6f59d8fd8834735f0ec36e4fd383ec7ff8a64aa078"
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
version: "0.1.6"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: a2d56211ee4d35d9b344d9d4ce60f362e4f5d1aafb988302906bd732bc731276
|
||||
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.1"
|
||||
webdriver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1090,10 +1103,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
|
||||
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.5.1"
|
||||
version: "5.5.4"
|
||||
window_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1128,5 +1141,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.4.3 <4.0.0"
|
||||
dart: ">=3.5.0-259.0.dev <4.0.0"
|
||||
flutter: ">=3.22.0"
|
||||
|
@ -70,7 +70,7 @@ dependencies:
|
||||
io: ^1.0.4
|
||||
base32: ^2.1.3
|
||||
convert: ^3.1.1
|
||||
material_symbols_icons: ^4.2719.3
|
||||
material_symbols_icons: ^4.2741.0
|
||||
|
||||
dev_dependencies:
|
||||
integration_test:
|
||||
|
Loading…
Reference in New Issue
Block a user