This commit is contained in:
Dain Nilsson 2023-12-01 09:41:51 +01:00
commit 8056c5a370
No known key found for this signature in database
GPG Key ID: F04367096FBA95E8
21 changed files with 276 additions and 107 deletions

View File

@ -34,6 +34,8 @@ jobs:
export PYVERINST=${PYVER_TEMP#* }
echo "PYVERINST=$PYVERINST" >> $GITHUB_ENV
echo "Installed python version: $PYVERINST"
python -m ensurepip --user
python -m pip install -U pip pipx
- name: Verify Python version
if: ${{ env.PYVERINST != env.PYVER }}
@ -59,21 +61,12 @@ jobs:
assets/licenses/helper.json
key: ${{ runner.os }}-py${{ env.PYVER }}-${{ hashFiles('helper/**') }}
- name: Install helper dependencies
if: steps.cache-helper.outputs.cache-hit != 'true'
run: |
apt-get install -qq swig libpcsclite-dev build-essential cmake
python -m ensurepip --user
python -m pip install -U pip pipx
# pipx ensurepath
echo "export PATH=$PATH:$HOME/.local/bin" >> ~/.bashrc
. ~/.bashrc # Needed to ensure poetry on PATH
pipx install poetry
- name: Build the Helper
if: steps.cache-helper.outputs.cache-hit != 'true'
run: |
. ~/.bashrc # Needed to ensure poetry on PATH
apt-get install -qq swig libpcsclite-dev build-essential cmake
export PATH=$PATH:$HOME/.local/bin # Needed to ensure pipx/poetry on PATH
pipx install poetry
./build-helper.sh
- name: Install Flutter dependencies
@ -91,10 +84,14 @@ jobs:
flutter config --enable-linux-desktop
flutter --version
- name: Run tests
- name: Run lints/tests
env:
SKIP: ${{ steps.cache-helper.outputs.cache-hit == 'true' && 'mypy,flake8,black,bandit' || ''}}
run: |
export PATH=$PATH:$HOME/.local/bin # Needed to ensure pip/pre-commit on PATH
pipx install pre-commit
pre-commit run --all-files
flutter test
flutter analyze
- name: Build the app
run: flutter build linux

View File

@ -18,6 +18,11 @@ jobs:
python3 set-version.py
git diff --exit-code
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYVER }}
- name: Cache helper
id: cache-helper
uses: actions/cache@v3
@ -27,12 +32,6 @@ jobs:
assets/licenses/helper.json
key: ${{ runner.os }}-py${{ env.PYVER }}-${{ hashFiles('helper/**') }}
- name: Set up Python
if: steps.cache-helper.outputs.cache-hit != 'true'
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYVER }}
- name: Install dependencies
if: steps.cache-helper.outputs.cache-hit != 'true'
run: |
@ -53,10 +52,13 @@ jobs:
- run: flutter config --enable-macos-desktop
- run: flutter --version
- name: Run tests
- name: Run lints/tests
env:
SKIP: ${{ steps.cache-helper.outputs.cache-hit == 'true' && 'mypy,flake8,black,bandit' || ''}}
run: |
pip install pre-commit
pre-commit run --all-files
flutter test
flutter analyze
- name: Build the app
run: |

View File

@ -19,6 +19,14 @@ jobs:
python set-version.py
git diff --exit-code
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYVER }}
- name: Update pip
run: python -m pip install --upgrade pip
- name: Cache helper
id: cache-helper
uses: actions/cache@v3
@ -28,21 +36,11 @@ jobs:
assets/licenses/helper.json
key: ${{ runner.os }}-py${{ env.PYVER }}-${{ hashFiles('helper/**') }}
- name: Set up Python
if: steps.cache-helper.outputs.cache-hit != 'true'
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYVER }}
- name: Install dependencies
if: steps.cache-helper.outputs.cache-hit != 'true'
run: |
python -m pip install --upgrade pip
pip install poetry
- name: Build the Helper
if: steps.cache-helper.outputs.cache-hit != 'true'
run: .\build-helper.bat
run: |
pip install poetry
.\build-helper.bat
- uses: subosito/flutter-action@v2
with:
@ -51,10 +49,13 @@ jobs:
- run: flutter config --enable-windows-desktop
- run: flutter --version
- name: Run tests
- name: Run lints/tests
env:
SKIP: ${{ steps.cache-helper.outputs.cache-hit == 'true' && 'mypy,flake8,black,bandit' || ''}}
run: |
pip install pre-commit
pre-commit run --all-files
flutter test
flutter analyze
- name: Build the app
run: |

41
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,41 @@
repos:
# Flutter
- repo: https://github.com/dluksza/flutter-analyze-pre-commit
rev: "4afcaa82fc368d40d486256bf4edba329bf667bb"
hooks:
- id: dart-format
files: \.dart$
require_serial: true
- id: flutter-analyze
require_serial: true
- repo: local
hooks:
- id: arb-reformatter
name: reformat-strings
files: \.arb$
language: script
entry: arb_reformatter.py
require_serial: true
# Python
- repo: local
hooks:
- id: mypy
name: mypy
files: helper/
language: script
entry: run-mypy.sh
require_serial: true
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
- repo: https://github.com/psf/black
rev: 23.11.0
hooks:
- id: black
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
- id: bandit
files: helper/ # keep in sync with .bandit file

View File

@ -5,24 +5,33 @@ import os
def read_file_lines(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
with open(file_path, "r", encoding="utf-8") as file:
return file.readlines()
def read_file_json(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
with open(file_path, "r", encoding="utf-8") as file:
return json.load(file)
def write_to_file(file_path, text):
with open(file_path, 'w', encoding='utf-8') as file:
with open(file_path, "r", encoding="utf-8") as file:
if file.read() == text:
return False
with open(file_path, "w", encoding="utf-8") as file:
file.write(text)
return True
# Translation table for unicode characters we want to keep in escaped form.
trans = str.maketrans({
'\u00a0': r"\u00a0", # No-Break Space (NBSP)
'\u2026': r"\u2026" # Horizontal Ellipsis
})
trans = str.maketrans(
{
"\u00a0": r"\u00a0", # No-Break Space (NBSP)
"\u2026": r"\u2026", # Horizontal Ellipsis
}
)
# Move keys in target into same order as in source.
# Keys not present in source are removed from target.
@ -68,16 +77,16 @@ def update_arb_file(source_path, target_path, language_code):
if line.strip() == "":
target_lines.insert(i, "")
write_to_file(target_path, "\n".join(target_lines).strip() + "\n")
return write_to_file(target_path, "\n".join(target_lines).strip() + "\n")
if __name__ == "__main__":
source_file_path = 'lib/l10n/app_en.arb'
target_directory = 'lib/l10n'
source_file_path = "lib/l10n/app_en.arb"
target_directory = "lib/l10n"
for file_name in os.listdir(target_directory):
if file_name.startswith('app_') and file_name.endswith('.arb'):
if file_name.startswith("app_") and file_name.endswith(".arb"):
target_file_path = os.path.join(target_directory, file_name)
language_code = file_name.split('_')[1].split('.')[0]
update_arb_file(source_file_path, target_file_path, language_code)
print(f'File updated: {file_name}')
language_code = file_name.split("_")[1].split(".")[0]
if update_arb_file(source_file_path, target_file_path, language_code):
print(f"File updated: {file_name}")

View File

@ -106,7 +106,7 @@ if len(sys.argv) != 2:
target = sys.argv[1]
with open(target, encoding='utf-8') as f:
with open(target, encoding="utf-8") as f:
values = json.load(f, object_pairs_hook=check_duplicate_keys)
strings = {k: v for k, v in values.items() if not k.startswith("@")}
@ -115,7 +115,7 @@ print(target, f"- checking {len(strings)} strings")
lint_strings(strings, values.get("@_lint_rules", {}))
check_duplicate_values(strings)
with open(os.path.join(os.path.dirname(target), 'app_en.arb'), encoding='utf-8') as f:
with open(os.path.join(os.path.dirname(target), "app_en.arb"), encoding="utf-8") as f:
reference_values = json.load(f)
errors.extend(check_keys_exist_in_reference(reference_values, values))

View File

@ -15,9 +15,11 @@
# limitations under the License.
from helper import run_rpc_pipes, run_rpc_socket
from typing import cast
import socket
import sys
import io
if __name__ == "__main__":
@ -32,8 +34,8 @@ if __name__ == "__main__":
run_rpc_socket(sock)
else:
sys.stdin.reconfigure(encoding="utf-8")
sys.stdout.reconfigure(encoding="utf-8")
sys.stderr.reconfigure(encoding="utf-8")
cast(io.TextIOWrapper, sys.stdin).reconfigure(encoding="utf-8")
cast(io.TextIOWrapper, sys.stdout).reconfigure(encoding="utf-8")
cast(io.TextIOWrapper, sys.stderr).reconfigure(encoding="utf-8")
run_rpc_pipes(sys.stdout, sys.stdin)

View File

@ -25,6 +25,7 @@ from fido2.ctap2 import Ctap2, ClientPin
from fido2.ctap2.credman import CredentialManagement
from fido2.ctap2.bio import BioEnrollment, FPBioEnrollment, CaptureError
from fido2.pcsc import CtapPcscDevice
from fido2.hid import CtapHidDevice
from yubikit.core.fido import FidoConnection
from ykman.hid import list_ctap_devices as list_ctap
from ykman.pcsc import list_devices as list_ccid
@ -94,8 +95,10 @@ class Ctap2Node(RpcNode):
data.update(uv_retries=uv_retries)
return data
def _prepare_reset_nfc(self, event, signal):
reader_name = self.ctap.device._name
@staticmethod
def _prepare_reset_nfc(device, event, signal):
# TODO: Don't use private member _name.
reader_name = device._name
devices = list_ccid(reader_name)
if not devices or devices[0].reader.name != reader_name:
raise ValueError("Unable to isolate NFC reader")
@ -119,8 +122,9 @@ class Ctap2Node(RpcNode):
raise TimeoutException()
def _prepare_reset_usb(self, event, signal):
dev_path = self.ctap.device.descriptor.path
@staticmethod
def _prepare_reset_usb(device, event, signal):
dev_path = device.descriptor.path
logger.debug(f"Reset over USB: {dev_path}")
signal("reset", dict(state="remove"))
@ -148,10 +152,13 @@ class Ctap2Node(RpcNode):
@action
def reset(self, params, event, signal):
target = _ctap_id(self.ctap)
if isinstance(self.ctap.device, CtapPcscDevice):
connection = self._prepare_reset_nfc(event, signal)
device = self.ctap.device
if isinstance(device, CtapPcscDevice):
connection = self._prepare_reset_nfc(device, event, signal)
elif isinstance(device, CtapHidDevice):
connection = self._prepare_reset_usb(device, event, signal)
else:
connection = self._prepare_reset_usb(event, signal)
raise TypeError("Unsupported connection type")
logger.debug("Performing reset...")
self.ctap = Ctap2(connection)
@ -166,7 +173,7 @@ class Ctap2Node(RpcNode):
@action(condition=lambda self: self._info.options["clientPin"])
def unlock(self, params, event, signal):
pin = params.pop("pin")
permissions = 0
permissions = ClientPin.PERMISSION(0)
if CredentialManagement.is_supported(self._info):
permissions |= ClientPin.PERMISSION.CREDENTIAL_MGMT
if BioEnrollment.is_supported(self._info):

View File

@ -13,7 +13,7 @@
# limitations under the License.
from .base import RpcNode, action
from yubikit.core import require_version, NotSupportedError, TRANSPORT
from yubikit.core import require_version, NotSupportedError, TRANSPORT, Connection
from yubikit.core.smartcard import SmartCardConnection
from yubikit.core.otp import OtpConnection
from yubikit.core.fido import FidoConnection
@ -21,6 +21,7 @@ from yubikit.management import ManagementSession, DeviceConfig, Mode, CAPABILITY
from ykman.device import list_all_devices
from dataclasses import asdict
from time import sleep
from typing import Type
import logging
logger = logging.getLogger(__name__)
@ -29,7 +30,7 @@ logger = logging.getLogger(__name__)
class ManagementNode(RpcNode):
def __init__(self, connection):
super().__init__()
self._connection_type = type(connection)
self._connection_type: Type[Connection] = type(connection)
self.session = ManagementSession(connection)
def get_data(self):
@ -54,11 +55,13 @@ class ManagementNode(RpcNode):
if self._connection_type.usb_interface in ifaces:
connection_types = [self._connection_type]
else:
connection_types = [
t
for t in [SmartCardConnection, OtpConnection, FidoConnection]
if t.usb_interface in ifaces
types: list[Type[Connection]] = [
SmartCardConnection,
OtpConnection,
# mypy doesn't support ABC.register()
FidoConnection, # type: ignore
]
connection_types = [t for t in types if t.usb_interface in ifaces]
self.session.close()
logger.debug("Waiting for device to re-appear...")

View File

@ -166,6 +166,7 @@ class PivNode(RpcNode):
key = None
if self._pivman_data.has_derived_key:
assert self._pivman_data.salt # nosec
key = derive_management_key(pin, self._pivman_data.salt)
elif self._pivman_data.has_stored_key:
pivman_prot = get_pivman_protected_data(self.session)
@ -452,13 +453,14 @@ class SlotNode(RpcNode):
signal("touch")
if generate_type == GENERATE_TYPE.CSR:
result = generate_csr(self.session, self.slot, public_key, subject)
csr = generate_csr(self.session, self.slot, public_key, subject)
result = csr.public_bytes(encoding=Encoding.PEM).decode()
elif generate_type == GENERATE_TYPE.CERTIFICATE:
now = datetime.datetime.utcnow()
then = now + datetime.timedelta(days=365)
valid_from = params.pop("valid_from", now.strftime(_date_format))
valid_to = params.pop("valid_to", then.strftime(_date_format))
result = generate_self_signed_certificate(
cert = generate_self_signed_certificate(
self.session,
self.slot,
public_key,
@ -466,7 +468,8 @@ class SlotNode(RpcNode):
datetime.datetime.strptime(valid_from, _date_format),
datetime.datetime.strptime(valid_to, _date_format),
)
self.session.put_certificate(self.slot, result)
result = cert.public_bytes(encoding=Encoding.PEM).decode()
self.session.put_certificate(self.slot, cert)
self.session.put_object(OBJECT_ID.CHUID, generate_chuid())
else:
raise ValueError("Unsupported GENERATE_TYPE")
@ -477,5 +480,5 @@ class SlotNode(RpcNode):
public_key=public_key.public_bytes(
encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo
).decode(),
result=result.public_bytes(encoding=Encoding.PEM).decode(),
result=result,
)

130
helper/poetry.lock generated
View File

@ -102,34 +102,34 @@ files = [
[[package]]
name = "cryptography"
version = "41.0.5"
version = "41.0.7"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = ">=3.7"
files = [
{file = "cryptography-41.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797"},
{file = "cryptography-41.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5"},
{file = "cryptography-41.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147"},
{file = "cryptography-41.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696"},
{file = "cryptography-41.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da"},
{file = "cryptography-41.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20"},
{file = "cryptography-41.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548"},
{file = "cryptography-41.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d"},
{file = "cryptography-41.0.5-cp37-abi3-win32.whl", hash = "sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936"},
{file = "cryptography-41.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81"},
{file = "cryptography-41.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1"},
{file = "cryptography-41.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72"},
{file = "cryptography-41.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88"},
{file = "cryptography-41.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf"},
{file = "cryptography-41.0.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e"},
{file = "cryptography-41.0.5-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8"},
{file = "cryptography-41.0.5-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179"},
{file = "cryptography-41.0.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d"},
{file = "cryptography-41.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1"},
{file = "cryptography-41.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86"},
{file = "cryptography-41.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723"},
{file = "cryptography-41.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84"},
{file = "cryptography-41.0.5.tar.gz", hash = "sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7"},
{file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"},
{file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"},
{file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"},
{file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"},
{file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"},
{file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"},
{file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"},
{file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"},
{file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"},
{file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"},
{file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"},
]
[package.dependencies]
@ -317,6 +317,64 @@ files = [
{file = "mss-9.0.1.tar.gz", hash = "sha256:6eb7b9008cf27428811fa33aeb35f3334db81e3f7cc2dd49ec7c6e5a94b39f12"},
]
[[package]]
name = "mypy"
version = "1.7.1"
description = "Optional static typing for Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"},
{file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"},
{file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"},
{file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"},
{file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"},
{file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"},
{file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"},
{file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"},
{file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"},
{file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"},
{file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"},
{file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"},
{file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"},
{file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"},
{file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"},
{file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"},
{file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"},
{file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"},
{file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"},
{file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"},
{file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"},
{file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"},
{file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"},
{file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"},
{file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"},
{file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"},
{file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"},
]
[package.dependencies]
mypy-extensions = ">=1.0.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing-extensions = ">=4.1.0"
[package.extras]
dmypy = ["psutil (>=4.0)"]
install-types = ["pip"]
mypyc = ["setuptools (>=50)"]
reports = ["lxml"]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
[[package]]
name = "packaging"
version = "23.2"
@ -601,6 +659,28 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "types-pillow"
version = "10.1.0.2"
description = "Typing stubs for Pillow"
optional = false
python-versions = ">=3.7"
files = [
{file = "types-Pillow-10.1.0.2.tar.gz", hash = "sha256:525c1c5ee67b0ac1721c40d2bc618226ef2123c347e527e14e05b920721a13b9"},
{file = "types_Pillow-10.1.0.2-py3-none-any.whl", hash = "sha256:131078ffa547bf9a201d39ffcdc65633e108148085f4f1b07d4647fcfec6e923"},
]
[[package]]
name = "typing-extensions"
version = "4.8.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
]
[[package]]
name = "yubikey-manager"
version = "5.2.0"
@ -668,4 +748,4 @@ subdirectory = "wrappers/python"
[metadata]
lock-version = "2.0"
python-versions = "^3.8"
content-hash = "325c73ad318593a1d3f4d0511d7ebfb2d4d3a022e1716dc82d3dd5e4471708bb"
content-hash = "536b00ea0443a4fb0b7e1293758b14021f9ee68699acf7e621d094339417624c"

View File

@ -21,6 +21,8 @@ Pillow = "^10.0.0"
[tool.poetry.dev-dependencies]
pyinstaller = {version = "^6.0", python = "<3.13"}
pytest = "^7.4.0"
mypy = "^1.7.1"
types-Pillow = "^10.0.0.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
@ -28,3 +30,11 @@ build-backend = "poetry.core.masonry.api"
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.mypy]
files = "."
check_untyped_defs = true
[[tool.mypy.overrides]]
module = ["smartcard.*", "zxingcpp"]
ignore_missing_imports = true

View File

@ -160,7 +160,8 @@ class _DialogProvider {
_DDesc.oathDeleteAccount => l10n.s_nfc_dialog_oath_delete_account,
_DDesc.oathCalculateCode => l10n.s_nfc_dialog_oath_calculate_code,
_DDesc.oathActionFailure => l10n.s_nfc_dialog_oath_failure,
_DDesc.oathAddMultipleAccounts => l10n.s_nfc_dialog_oath_add_multiple_accounts,
_DDesc.oathAddMultipleAccounts =>
l10n.s_nfc_dialog_oath_add_multiple_accounts,
_ => ''
};
}

View File

@ -26,4 +26,3 @@ class ApduException implements Exception {
return 'ApduException[$message; dec: $sw]';
}
}

View File

@ -14,6 +14,4 @@
* limitations under the License.
*/
class CancellationException implements Exception {
}
class CancellationException implements Exception {}

View File

@ -136,6 +136,7 @@
"@_app_configuration": {},
"s_toggle_applications": "Anwendungen umschalten",
"s_toggle_interfaces": null,
"l_min_one_interface": "Mindestens ein Interface muss aktiviert sein",
"s_reconfiguring_yk": "YubiKey wird neu konfiguriert\u2026",
"s_config_updated": "Konfiguration aktualisiert",

View File

@ -136,6 +136,7 @@
"@_app_configuration": {},
"s_toggle_applications": "Changer les applications",
"s_toggle_interfaces": null,
"l_min_one_interface": "Au moins une interface doit être activée",
"s_reconfiguring_yk": "Reconfiguration de la YubiKey\u2026",
"s_config_updated": "Configuration mise à jour",

View File

@ -136,6 +136,7 @@
"@_app_configuration": {},
"s_toggle_applications": "アプリケーションの切替え",
"s_toggle_interfaces": null,
"l_min_one_interface": "少なくとも 1 つのインターフェイスを有効にする必要があります",
"s_reconfiguring_yk": "YubiKeyを再構成しています\u2026",
"s_config_updated": "構成が更新されました",

View File

@ -61,7 +61,8 @@ class IconPack {
element.issuer.any((element) => element == issuer.toUpperCase()));
final issuerImageFile = matching.isNotEmpty
? File(join(directory.path, getLocalIconFileName(matching.first.filename)))
? File(
join(directory.path, getLocalIconFileName(matching.first.filename)))
: null;
if (issuerImageFile != null && !issuerImageFile.existsSync()) {

View File

@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:logging/logging.dart';

13
run-mypy.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
# Runs mypy from poetry in the helper directory.
set -e
cd helper
if [ "$(poetry env list)" = "" ]; then
echo "Initializing poetry env..."
poetry install
fi
poetry run mypy