mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-22 16:32:01 +03:00
Merge PR #1281.
This commit is contained in:
commit
8056c5a370
25
.github/workflows/linux.yml
vendored
25
.github/workflows/linux.yml
vendored
@ -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
|
||||
|
18
.github/workflows/macos.yml
vendored
18
.github/workflows/macos.yml
vendored
@ -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: |
|
||||
|
31
.github/workflows/windows.yml
vendored
31
.github/workflows/windows.yml
vendored
@ -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
41
.pre-commit-config.yaml
Normal 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
|
@ -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}")
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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...")
|
||||
|
@ -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
130
helper/poetry.lock
generated
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
_ => ''
|
||||
};
|
||||
}
|
||||
|
@ -26,4 +26,3 @@ class ApduException implements Exception {
|
||||
return 'ApduException[$message; dec: $sw]';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class CancellationException implements Exception {
|
||||
|
||||
}
|
||||
class CancellationException implements Exception {}
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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": "構成が更新されました",
|
||||
|
@ -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()) {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
@ -15,4 +14,4 @@ class FocusUtils {
|
||||
currentFocus.unfocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
run-mypy.sh
Executable file
13
run-mypy.sh
Executable 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
|
Loading…
Reference in New Issue
Block a user