tba-storage-webauthn 0.4.0.dev2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tba_storage_webauthn/__init__.py +7 -0
- tba_storage_webauthn/component.toml +35 -0
- tba_storage_webauthn/manifest.py +9 -0
- tba_storage_webauthn/migrations/__init__.py +0 -0
- tba_storage_webauthn/migrations/versions/35709893_1208_54c2_ab00_dca4b2e67065_initial_schema.py +23 -0
- tba_storage_webauthn/migrations/versions/__init__.py +0 -0
- tba_storage_webauthn/py.typed +0 -0
- tba_storage_webauthn/tables/__init__.py +18 -0
- tba_storage_webauthn/tables/credential_webauthn_passkey/__init__.py +9 -0
- tba_storage_webauthn/tables/credential_webauthn_passkey/_table.py +42 -0
- tba_storage_webauthn/tables/webauthn_attestation_record/__init__.py +3 -0
- tba_storage_webauthn/tables/webauthn_attestation_record/_table.py +28 -0
- tba_storage_webauthn/tables/webauthn_ceremony/__init__.py +3 -0
- tba_storage_webauthn/tables/webauthn_ceremony/_table.py +43 -0
- tba_storage_webauthn/tables/webauthn_relying_party/__init__.py +3 -0
- tba_storage_webauthn/tables/webauthn_relying_party/_table.py +24 -0
- tba_storage_webauthn-0.4.0.dev2.dist-info/METADATA +22 -0
- tba_storage_webauthn-0.4.0.dev2.dist-info/RECORD +19 -0
- tba_storage_webauthn-0.4.0.dev2.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""Standalone identity storage component."""
|
|
2
|
+
|
|
3
|
+
from .manifest import MANIFEST, load_manifest
|
|
4
|
+
from .tables import * # noqa: F401,F403
|
|
5
|
+
from .tables import TABLE_MODEL_BY_NAME, TABLE_MODEL_BY_TABLENAME, TABLE_MODELS
|
|
6
|
+
|
|
7
|
+
__all__ = ["MANIFEST", "load_manifest", "TABLE_MODELS", "TABLE_MODEL_BY_NAME", "TABLE_MODEL_BY_TABLENAME"] + [model.__name__ for model in TABLE_MODELS]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
manifest_version = "1.0.0"
|
|
2
|
+
|
|
3
|
+
[component]
|
|
4
|
+
id = "tigrbl.identity.storage.webauthn"
|
|
5
|
+
distribution = "tba-storage-webauthn"
|
|
6
|
+
import_root = "tba_storage_webauthn"
|
|
7
|
+
|
|
8
|
+
[schema]
|
|
9
|
+
contract = "1.0.0"
|
|
10
|
+
migration_head = "35709893-1208-54c2-ab00-dca4b2e67065"
|
|
11
|
+
migrations_package = "tba_storage_webauthn.migrations.versions"
|
|
12
|
+
|
|
13
|
+
[[schema.objects]]
|
|
14
|
+
id = "tigrbl.identity.storage.webauthn:table:credential_webauthn_passkeys"
|
|
15
|
+
kind = "table"
|
|
16
|
+
physical_name = "authn.credential_webauthn_passkeys"
|
|
17
|
+
model = "tba_storage_webauthn.tables:CredentialWebAuthnPasskey"
|
|
18
|
+
|
|
19
|
+
[[schema.objects]]
|
|
20
|
+
id = "tigrbl.identity.storage.webauthn:table:webauthn_attestation_records"
|
|
21
|
+
kind = "table"
|
|
22
|
+
physical_name = "authn.webauthn_attestation_records"
|
|
23
|
+
model = "tba_storage_webauthn.tables:WebAuthnAttestationRecord"
|
|
24
|
+
|
|
25
|
+
[[schema.objects]]
|
|
26
|
+
id = "tigrbl.identity.storage.webauthn:table:webauthn_ceremonies"
|
|
27
|
+
kind = "table"
|
|
28
|
+
physical_name = "authn.webauthn_ceremonies"
|
|
29
|
+
model = "tba_storage_webauthn.tables:WebAuthnCeremony"
|
|
30
|
+
|
|
31
|
+
[[schema.objects]]
|
|
32
|
+
id = "tigrbl.identity.storage.webauthn:table:webauthn_relying_parties"
|
|
33
|
+
kind = "table"
|
|
34
|
+
physical_name = "authn.webauthn_relying_parties"
|
|
35
|
+
model = "tba_storage_webauthn.tables:WebAuthnRelyingParty"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Installed component manifest access."""
|
|
2
|
+
from importlib.resources import as_file, files
|
|
3
|
+
from tigrbl_migrations import StorageManifest
|
|
4
|
+
|
|
5
|
+
def load_manifest() -> StorageManifest:
|
|
6
|
+
with as_file(files(__package__).joinpath("component.toml")) as path:
|
|
7
|
+
return StorageManifest.from_toml(path)
|
|
8
|
+
|
|
9
|
+
MANIFEST = load_manifest()
|
|
File without changes
|
tba_storage_webauthn/migrations/versions/35709893_1208_54c2_ab00_dca4b2e67065_initial_schema.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Initial owned schema for tigrbl.identity.storage.webauthn."""
|
|
2
|
+
from tigrbl_migrations import Migration
|
|
3
|
+
from tba_storage_webauthn.tables import TABLE_MODELS
|
|
4
|
+
|
|
5
|
+
REVISION = "35709893-1208-54c2-ab00-dca4b2e67065"
|
|
6
|
+
|
|
7
|
+
def upgrade(connection):
|
|
8
|
+
for model in TABLE_MODELS:
|
|
9
|
+
model.__table__.create(bind=connection, checkfirst=True)
|
|
10
|
+
|
|
11
|
+
def downgrade(connection):
|
|
12
|
+
for model in reversed(TABLE_MODELS):
|
|
13
|
+
model.__table__.drop(bind=connection, checkfirst=True)
|
|
14
|
+
|
|
15
|
+
MIGRATION = Migration(
|
|
16
|
+
component="tigrbl.identity.storage.webauthn",
|
|
17
|
+
revision=REVISION,
|
|
18
|
+
parents=(),
|
|
19
|
+
kind="standard",
|
|
20
|
+
reversible=True,
|
|
21
|
+
upgrade=upgrade,
|
|
22
|
+
downgrade=downgrade,
|
|
23
|
+
)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Owned mapped-table inventory."""
|
|
2
|
+
|
|
3
|
+
from .credential_webauthn_passkey import CredentialWebAuthnPasskey
|
|
4
|
+
from .webauthn_attestation_record import WebAuthnAttestationRecord
|
|
5
|
+
from .webauthn_ceremony import WebAuthnCeremony
|
|
6
|
+
from .webauthn_relying_party import WebAuthnRelyingParty
|
|
7
|
+
|
|
8
|
+
TABLE_MODELS = (
|
|
9
|
+
CredentialWebAuthnPasskey,
|
|
10
|
+
WebAuthnAttestationRecord,
|
|
11
|
+
WebAuthnCeremony,
|
|
12
|
+
WebAuthnRelyingParty,
|
|
13
|
+
)
|
|
14
|
+
TABLE_MODEL_BY_NAME = {model.__name__: model for model in TABLE_MODELS}
|
|
15
|
+
TABLE_MODEL_BY_TABLENAME = {model.__tablename__: model for model in TABLE_MODELS}
|
|
16
|
+
__all__ = [model.__name__ for model in TABLE_MODELS] + [
|
|
17
|
+
"TABLE_MODELS", "TABLE_MODEL_BY_NAME", "TABLE_MODEL_BY_TABLENAME",
|
|
18
|
+
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Durable WebAuthn passkey credential records."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import datetime as dt
|
|
7
|
+
|
|
8
|
+
from tba_primitives_identity.orm import Boolean, GUIDPk, Integer, JSON, LargeBinary, Mapped, RestOltpTable, S, String, TZDateTime, Timestamped, acol
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CredentialWebAuthnPasskey(RestOltpTable, GUIDPk, Timestamped):
|
|
13
|
+
__tablename__ = "credential_webauthn_passkeys"
|
|
14
|
+
__table_args__ = {"extend_existing": True, "schema": "authn"}
|
|
15
|
+
|
|
16
|
+
credential_id: Mapped[str] = acol(storage=S(String(255), nullable=False, unique=True, index=True))
|
|
17
|
+
principal_id: Mapped[str] = acol(storage=S(String(255), nullable=False, index=True))
|
|
18
|
+
webauthn_credential_id: Mapped[str] = acol(storage=S(String(1000), nullable=False, unique=True, index=True))
|
|
19
|
+
public_key: Mapped[str] = acol(storage=S(String(4000), nullable=False))
|
|
20
|
+
rp_id: Mapped[str | None] = acol(storage=S(String(255), nullable=True, index=True))
|
|
21
|
+
algorithm: Mapped[str | None] = acol(storage=S(String(64), nullable=True))
|
|
22
|
+
sign_count: Mapped[int] = acol(storage=S(Integer, nullable=False, default=0))
|
|
23
|
+
transports: Mapped[list | None] = acol(storage=S(JSON, nullable=True))
|
|
24
|
+
status: Mapped[str] = acol(storage=S(String(32), nullable=False, default="active", index=True))
|
|
25
|
+
passkey_metadata: Mapped[dict | None] = acol(storage=S(JSON, nullable=True))
|
|
26
|
+
credential_external_id: Mapped[str | None] = acol(storage=S(String(1000), nullable=True, unique=True, index=True))
|
|
27
|
+
credential_public_key_cose: Mapped[bytes | None] = acol(storage=S(LargeBinary, nullable=True))
|
|
28
|
+
user_handle: Mapped[bytes | None] = acol(storage=S(LargeBinary, nullable=True, index=True))
|
|
29
|
+
cose_algorithm: Mapped[int | None] = acol(storage=S(Integer, nullable=True))
|
|
30
|
+
aaguid: Mapped[bytes | None] = acol(storage=S(LargeBinary, nullable=True, index=True))
|
|
31
|
+
attestation_format: Mapped[str | None] = acol(storage=S(String(64), nullable=True))
|
|
32
|
+
attestation_type: Mapped[str | None] = acol(storage=S(String(64), nullable=True))
|
|
33
|
+
attestation_trust_status: Mapped[str | None] = acol(storage=S(String(32), nullable=True, index=True))
|
|
34
|
+
discoverable: Mapped[bool] = acol(storage=S(Boolean, nullable=False, default=False, index=True))
|
|
35
|
+
backup_eligible: Mapped[bool] = acol(storage=S(Boolean, nullable=False, default=False, index=True))
|
|
36
|
+
backup_state: Mapped[bool] = acol(storage=S(Boolean, nullable=False, default=False, index=True))
|
|
37
|
+
last_used_at: Mapped[dt.datetime | None] = acol(storage=S(TZDateTime, nullable=True, index=True))
|
|
38
|
+
revoked_at: Mapped[dt.datetime | None] = acol(storage=S(TZDateTime, nullable=True, index=True))
|
|
39
|
+
display_name: Mapped[str | None] = acol(storage=S(String(255), nullable=True))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__all__ = ["CredentialWebAuthnPasskey"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Durable result of authenticator attestation appraisal."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import datetime as dt
|
|
6
|
+
|
|
7
|
+
from tba_primitives_identity.orm import GUIDPk, LargeBinary, Mapped, RestOltpTable, S, String, TZDateTime, Timestamped, acol
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class WebAuthnAttestationRecord(RestOltpTable, GUIDPk, Timestamped):
|
|
11
|
+
__tablename__ = "webauthn_attestation_records"
|
|
12
|
+
__table_args__ = {"extend_existing": True, "schema": "authn"}
|
|
13
|
+
|
|
14
|
+
attestation_id: Mapped[str] = acol(storage=S(String(255), nullable=False, unique=True, index=True))
|
|
15
|
+
credential_id: Mapped[str] = acol(storage=S(String(255), nullable=False, index=True))
|
|
16
|
+
format: Mapped[str] = acol(storage=S(String(64), nullable=False, index=True))
|
|
17
|
+
type: Mapped[str] = acol(storage=S(String(64), nullable=False))
|
|
18
|
+
aaguid: Mapped[bytes | None] = acol(storage=S(LargeBinary, nullable=True, index=True))
|
|
19
|
+
statement_digest: Mapped[bytes] = acol(storage=S(LargeBinary, nullable=False))
|
|
20
|
+
certificate_chain_artifact_ref: Mapped[str | None] = acol(storage=S(String(1024), nullable=True))
|
|
21
|
+
trust_anchor_id: Mapped[str | None] = acol(storage=S(String(255), nullable=True, index=True))
|
|
22
|
+
metadata_statement_id: Mapped[str | None] = acol(storage=S(String(255), nullable=True, index=True))
|
|
23
|
+
verification_status: Mapped[str] = acol(storage=S(String(32), nullable=False, index=True))
|
|
24
|
+
verified_at: Mapped[dt.datetime | None] = acol(storage=S(TZDateTime, nullable=True, index=True))
|
|
25
|
+
valid_until: Mapped[dt.datetime | None] = acol(storage=S(TZDateTime, nullable=True, index=True))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = ["WebAuthnAttestationRecord"]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Durable WebAuthn registration and authentication ceremony state."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import datetime as dt
|
|
6
|
+
|
|
7
|
+
from tba_primitives_identity.orm import (
|
|
8
|
+
GUIDPk,
|
|
9
|
+
LargeBinary,
|
|
10
|
+
Mapped,
|
|
11
|
+
RestOltpTable,
|
|
12
|
+
S,
|
|
13
|
+
String,
|
|
14
|
+
TZDateTime,
|
|
15
|
+
Timestamped,
|
|
16
|
+
acol,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class WebAuthnCeremony(RestOltpTable, GUIDPk, Timestamped):
|
|
21
|
+
__tablename__ = "webauthn_ceremonies"
|
|
22
|
+
__table_args__ = {"extend_existing": True, "schema": "authn"}
|
|
23
|
+
|
|
24
|
+
ceremony_id: Mapped[str] = acol(storage=S(String(255), nullable=False, unique=True, index=True))
|
|
25
|
+
tenant_id: Mapped[str] = acol(storage=S(String(255), nullable=False, index=True))
|
|
26
|
+
principal_id: Mapped[str | None] = acol(storage=S(String(255), nullable=True, index=True))
|
|
27
|
+
ceremony_kind: Mapped[str] = acol(storage=S(String(32), nullable=False, index=True))
|
|
28
|
+
rp_id: Mapped[str] = acol(storage=S(String(255), nullable=False, index=True))
|
|
29
|
+
expected_origin: Mapped[str] = acol(storage=S(String(2048), nullable=False))
|
|
30
|
+
challenge_digest: Mapped[bytes] = acol(storage=S(LargeBinary, nullable=False))
|
|
31
|
+
options_digest: Mapped[bytes | None] = acol(storage=S(LargeBinary, nullable=True))
|
|
32
|
+
user_verification_requirement: Mapped[str] = acol(storage=S(String(32), nullable=False, default="preferred"))
|
|
33
|
+
resident_key_requirement: Mapped[str | None] = acol(storage=S(String(32), nullable=True))
|
|
34
|
+
attestation_preference: Mapped[str | None] = acol(storage=S(String(32), nullable=True))
|
|
35
|
+
state: Mapped[str] = acol(storage=S(String(32), nullable=False, default="pending", index=True))
|
|
36
|
+
issued_at: Mapped[dt.datetime] = acol(storage=S(TZDateTime, nullable=False, index=True))
|
|
37
|
+
expires_at: Mapped[dt.datetime] = acol(storage=S(TZDateTime, nullable=False, index=True))
|
|
38
|
+
consumed_at: Mapped[dt.datetime | None] = acol(storage=S(TZDateTime, nullable=True, index=True))
|
|
39
|
+
bound_credential_id: Mapped[str | None] = acol(storage=S(String(255), nullable=True, index=True))
|
|
40
|
+
failure_code: Mapped[str | None] = acol(storage=S(String(128), nullable=True))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
__all__ = ["WebAuthnCeremony"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Tenant-scoped WebAuthn relying-party configuration."""
|
|
2
|
+
|
|
3
|
+
from tba_primitives_identity.orm import Boolean, GUIDPk, JSON, Mapped, RestOltpTable, S, String, Timestamped, acol
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class WebAuthnRelyingParty(RestOltpTable, GUIDPk, Timestamped):
|
|
7
|
+
__tablename__ = "webauthn_relying_parties"
|
|
8
|
+
__table_args__ = {"extend_existing": True, "schema": "authn"}
|
|
9
|
+
|
|
10
|
+
rp_config_id: Mapped[str] = acol(storage=S(String(255), nullable=False, unique=True, index=True))
|
|
11
|
+
tenant_id: Mapped[str] = acol(storage=S(String(255), nullable=False, index=True))
|
|
12
|
+
rp_id: Mapped[str] = acol(storage=S(String(255), nullable=False, index=True))
|
|
13
|
+
display_name: Mapped[str] = acol(storage=S(String(255), nullable=False))
|
|
14
|
+
allowed_origins: Mapped[list] = acol(storage=S(JSON, nullable=False, default=list))
|
|
15
|
+
allowed_algorithms: Mapped[list] = acol(storage=S(JSON, nullable=False, default=list))
|
|
16
|
+
user_verification_policy: Mapped[str] = acol(storage=S(String(32), nullable=False, default="preferred"))
|
|
17
|
+
resident_key_policy: Mapped[str] = acol(storage=S(String(32), nullable=False, default="preferred"))
|
|
18
|
+
attestation_policy: Mapped[str] = acol(storage=S(String(32), nullable=False, default="none"))
|
|
19
|
+
allowed_attestation_formats: Mapped[list | None] = acol(storage=S(JSON, nullable=True))
|
|
20
|
+
related_origins: Mapped[list | None] = acol(storage=S(JSON, nullable=True))
|
|
21
|
+
enabled: Mapped[bool] = acol(storage=S(Boolean, nullable=False, default=True, index=True))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__all__ = ["WebAuthnRelyingParty"]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tba-storage-webauthn
|
|
3
|
+
Version: 0.4.0.dev2
|
|
4
|
+
Summary: Owned webauthn identity database tables and migrations.
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.10,<3.15
|
|
7
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Dist: tba-primitives-identity[storage] (>=0.4.0.dev2)
|
|
15
|
+
Requires-Dist: tigrbl (>=0.4.4.dev1,<0.5)
|
|
16
|
+
Requires-Dist: tigrbl-migrations (>=0.4.5.dev4)
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# tba-storage-webauthn
|
|
20
|
+
|
|
21
|
+
Owns the `tigrbl.identity.storage.webauthn` schema component.
|
|
22
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
tba_storage_webauthn/__init__.py,sha256=HoJ8HOyxQOG9vvo4LEJPfEUW3IDGqZF6ZIgJQ59tK6Q,366
|
|
2
|
+
tba_storage_webauthn/component.toml,sha256=Bi3Qt4JhPZcmTB2I6AGlyGdEfQ8bDGnqaHkF48W6Q2A,1172
|
|
3
|
+
tba_storage_webauthn/manifest.py,sha256=bYZmb6ItB8bRxtuCspB1us5eTvB1RqlTedISJZbws_w,325
|
|
4
|
+
tba_storage_webauthn/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
tba_storage_webauthn/migrations/versions/35709893_1208_54c2_ab00_dca4b2e67065_initial_schema.py,sha256=w40a7CjPAipWcjKYfeE9Fp-kJIRzB3Xl2naHZJM70BI,666
|
|
6
|
+
tba_storage_webauthn/migrations/versions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
tba_storage_webauthn/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
tba_storage_webauthn/tables/__init__.py,sha256=IVinAQ16X-m2FRRHus1Kgo6auafzTPiaLh8wVmDrKFQ,690
|
|
9
|
+
tba_storage_webauthn/tables/credential_webauthn_passkey/__init__.py,sha256=IwChVBciSBL8Hb5BIIxsotAa84PK6hC6qmoqW5rTydc,224
|
|
10
|
+
tba_storage_webauthn/tables/credential_webauthn_passkey/_table.py,sha256=IVX_Vdiuoc8rb68F33YQMtQ-QrZkz0AJ3dDILsA5PM4,2736
|
|
11
|
+
tba_storage_webauthn/tables/webauthn_attestation_record/__init__.py,sha256=sLOPWAmx_KaW34M_R0TCbKzTvv1h-KE-cmz529nvmwU,87
|
|
12
|
+
tba_storage_webauthn/tables/webauthn_attestation_record/_table.py,sha256=ZU9lsexgQDM-LXJBePvv74qJ9T_uMem1PgqdIC-Jh00,1596
|
|
13
|
+
tba_storage_webauthn/tables/webauthn_ceremony/__init__.py,sha256=Eb1zPQEzbucFxYl5ecUmmoqrDmt3Eja0ws5GQXtx3xI,69
|
|
14
|
+
tba_storage_webauthn/tables/webauthn_ceremony/_table.py,sha256=VhshPDNfQD67eTdo020Y4X5-bp-wnj2OcfN4jKZPP5M,2078
|
|
15
|
+
tba_storage_webauthn/tables/webauthn_relying_party/__init__.py,sha256=jFGOSTtOWl7wKc4hgPR1P4X5dBfVv4CdwwOcE1BO0Cc,77
|
|
16
|
+
tba_storage_webauthn/tables/webauthn_relying_party/_table.py,sha256=20iSlNeqtTLxeXKSrrdPeVfy_9qmgKVVUjWAVVQa_VE,1495
|
|
17
|
+
tba_storage_webauthn-0.4.0.dev2.dist-info/METADATA,sha256=XHEILpM4Xbx8AQv5JNUXccSKD5P567qmECCOYv5YtpU,831
|
|
18
|
+
tba_storage_webauthn-0.4.0.dev2.dist-info/WHEEL,sha256=L-WvLdSBvJWHXv5zrQxDvNRnIgoBzLUpcbuiw19KCuQ,88
|
|
19
|
+
tba_storage_webauthn-0.4.0.dev2.dist-info/RECORD,,
|