paskia 0.9.0__py3-none-any.whl → 0.10.0__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.
- paskia/_version.py +2 -2
- paskia/aaguid/__init__.py +5 -4
- paskia/authsession.py +4 -19
- paskia/db/__init__.py +2 -4
- paskia/db/background.py +3 -3
- paskia/db/jsonl.py +99 -111
- paskia/db/logging.py +318 -0
- paskia/db/migrations.py +19 -20
- paskia/db/operations.py +107 -196
- paskia/db/structs.py +236 -46
- paskia/fastapi/__main__.py +13 -6
- paskia/fastapi/admin.py +72 -195
- paskia/fastapi/api.py +56 -58
- paskia/fastapi/authz.py +3 -8
- paskia/fastapi/logging.py +261 -0
- paskia/fastapi/mainapp.py +14 -3
- paskia/fastapi/remote.py +11 -37
- paskia/fastapi/reset.py +0 -2
- paskia/fastapi/response.py +22 -0
- paskia/fastapi/user.py +7 -7
- paskia/fastapi/ws.py +14 -37
- paskia/fastapi/wschat.py +55 -2
- paskia/fastapi/wsutil.py +10 -2
- paskia/frontend-build/auth/admin/index.html +6 -6
- paskia/frontend-build/auth/assets/AccessDenied-C29NZI95.css +1 -0
- paskia/frontend-build/auth/assets/AccessDenied-DAdzg_MJ.js +12 -0
- paskia/frontend-build/auth/assets/{RestrictedAuth-CvR33_Z0.css → RestrictedAuth-BOdNrlQB.css} +1 -1
- paskia/frontend-build/auth/assets/{RestrictedAuth-DsJXicIw.js → RestrictedAuth-BSusdAfp.js} +1 -1
- paskia/frontend-build/auth/assets/_plugin-vue_export-helper-D2l53SUz.js +49 -0
- paskia/frontend-build/auth/assets/_plugin-vue_export-helper-DYJ24FZK.css +1 -0
- paskia/frontend-build/auth/assets/admin-BeFvGyD6.js +1 -0
- paskia/frontend-build/auth/assets/{admin-DzzjSg72.css → admin-CmNtuH3s.css} +1 -1
- paskia/frontend-build/auth/assets/{auth-C7k64Wad.css → auth-BKq4T2K2.css} +1 -1
- paskia/frontend-build/auth/assets/auth-DvHf8hgy.js +1 -0
- paskia/frontend-build/auth/assets/{forward-DmqVHZ7e.js → forward-C86Jm_Uq.js} +1 -1
- paskia/frontend-build/auth/assets/reset-B8PlNXuP.css +1 -0
- paskia/frontend-build/auth/assets/reset-D71FG0VL.js +1 -0
- paskia/frontend-build/auth/assets/{restricted-D3AJx3_6.js → restricted-CW0drE_k.js} +1 -1
- paskia/frontend-build/auth/index.html +6 -6
- paskia/frontend-build/auth/restricted/index.html +5 -5
- paskia/frontend-build/int/forward/index.html +5 -5
- paskia/frontend-build/int/reset/index.html +4 -4
- paskia/migrate/__init__.py +9 -9
- paskia/migrate/sql.py +26 -19
- paskia/remoteauth.py +6 -6
- {paskia-0.9.0.dist-info → paskia-0.10.0.dist-info}/METADATA +1 -1
- paskia-0.10.0.dist-info/RECORD +60 -0
- paskia/frontend-build/auth/assets/AccessDenied-DPkUS8LZ.css +0 -1
- paskia/frontend-build/auth/assets/AccessDenied-Fmeb6EtF.js +0 -8
- paskia/frontend-build/auth/assets/_plugin-vue_export-helper-BTzJAQlS.css +0 -1
- paskia/frontend-build/auth/assets/_plugin-vue_export-helper-nhjnO_bd.js +0 -2
- paskia/frontend-build/auth/assets/admin-CPE1pLMm.js +0 -1
- paskia/frontend-build/auth/assets/auth-YIZvPlW_.js +0 -1
- paskia/frontend-build/auth/assets/reset-Chtv69AT.css +0 -1
- paskia/frontend-build/auth/assets/reset-s20PATTN.js +0 -1
- paskia-0.9.0.dist-info/RECORD +0 -57
- {paskia-0.9.0.dist-info → paskia-0.10.0.dist-info}/WHEEL +0 -0
- {paskia-0.9.0.dist-info → paskia-0.10.0.dist-info}/entry_points.txt +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as p,c as h,o as m,y as l,d as f,J as w,K as k}from"./_plugin-vue_export-helper-
|
|
1
|
+
import{r as p,c as h,o as m,y as l,d as f,J as w,K as k}from"./_plugin-vue_export-helper-D2l53SUz.js";import{R as y}from"./RestrictedAuth-BSusdAfp.js";import"./pow-2N9bxgAo.js";const _={__name:"RestrictedApi",setup(g){const o=p(null);function c(){const e=window.location.pathname.match(/\/auth\/([^/]+)$/);if(e){const r=e[1],s=r.split(".");if(s.length===5&&s.every(d=>d.length>0))return r}return null}const i=h(()=>{const e=new URLSearchParams(window.location.hash.slice(1)).get("mode");return e==="reauth"?"reauth":e==="forbidden"?"forbidden":"login"});function n(t){window.parent&&window.parent!==window&&window.parent.postMessage(t,"*")}function u(t){n({type:"auth-success",authenticated:!0,sessionToken:t.session_token})}function a(){n({type:"auth-back"})}return m(()=>{o.value=c(),n({type:"auth-ready"}),window.addEventListener("keydown",t=>{t.key==="Escape"&&a()})}),(t,e)=>(f(),l(y,{mode:i.value,"remote-auth-token":o.value,onAuthenticated:u,onBack:a},null,8,["mode","remote-auth-token"]))}};w(_).mount("#app");k();
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Auth Profile</title>
|
|
7
|
-
<script type="module" crossorigin src="/auth/assets/auth-
|
|
8
|
-
<link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-
|
|
7
|
+
<script type="module" crossorigin src="/auth/assets/auth-DvHf8hgy.js"></script>
|
|
8
|
+
<link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-D2l53SUz.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/auth/assets/helpers-DzjFIx78.js">
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/auth/assets/AccessDenied-
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/auth/assets/AccessDenied-DAdzg_MJ.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/auth/assets/pow-2N9bxgAo.js">
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-
|
|
13
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/AccessDenied-
|
|
14
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/auth-
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-DYJ24FZK.css">
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/AccessDenied-C29NZI95.css">
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/auth-BKq4T2K2.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
17
17
|
<div id="app"></div>
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<script type="module" crossorigin src="/auth/assets/restricted-
|
|
7
|
-
<link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-
|
|
6
|
+
<script type="module" crossorigin src="/auth/assets/restricted-CW0drE_k.js"></script>
|
|
7
|
+
<link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-D2l53SUz.js">
|
|
8
8
|
<link rel="modulepreload" crossorigin href="/auth/assets/pow-2N9bxgAo.js">
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/auth/assets/RestrictedAuth-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/RestrictedAuth-
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/auth/assets/RestrictedAuth-BSusdAfp.js">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-DYJ24FZK.css">
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/RestrictedAuth-BOdNrlQB.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div id="app"></div>
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Access Restricted</title>
|
|
7
|
-
<script type="module" crossorigin src="/auth/assets/forward-
|
|
8
|
-
<link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-
|
|
7
|
+
<script type="module" crossorigin src="/auth/assets/forward-C86Jm_Uq.js"></script>
|
|
8
|
+
<link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-D2l53SUz.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/auth/assets/pow-2N9bxgAo.js">
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/auth/assets/RestrictedAuth-
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/auth/assets/RestrictedAuth-BSusdAfp.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/auth/assets/helpers-DzjFIx78.js">
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-
|
|
13
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/RestrictedAuth-
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-DYJ24FZK.css">
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/RestrictedAuth-BOdNrlQB.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
16
|
<div id="app"></div>
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Complete Passkey Setup</title>
|
|
7
|
-
<script type="module" crossorigin src="/auth/assets/reset-
|
|
8
|
-
<link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/auth/assets/reset-
|
|
7
|
+
<script type="module" crossorigin src="/auth/assets/reset-D71FG0VL.js"></script>
|
|
8
|
+
<link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-D2l53SUz.js">
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-DYJ24FZK.css">
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/auth/assets/reset-B8PlNXuP.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<div id="app"></div>
|
paskia/migrate/__init__.py
CHANGED
|
@@ -14,7 +14,7 @@ Or via the CLI entry point (if installed):
|
|
|
14
14
|
import argparse
|
|
15
15
|
import asyncio
|
|
16
16
|
import re
|
|
17
|
-
from datetime import
|
|
17
|
+
from datetime import UTC, datetime
|
|
18
18
|
from uuid import UUID
|
|
19
19
|
|
|
20
20
|
import base64url
|
|
@@ -154,7 +154,7 @@ async def migrate_from_sql(
|
|
|
154
154
|
if perm_uuid:
|
|
155
155
|
new_permissions[perm_uuid] = True
|
|
156
156
|
new_role = Role(
|
|
157
|
-
|
|
157
|
+
org_uuid=role.org_uuid,
|
|
158
158
|
display_name=role.display_name,
|
|
159
159
|
permissions=new_permissions,
|
|
160
160
|
)
|
|
@@ -172,8 +172,8 @@ async def migrate_from_sql(
|
|
|
172
172
|
user_key: UUID = legacy_user.uuid
|
|
173
173
|
new_user = User(
|
|
174
174
|
display_name=legacy_user.display_name,
|
|
175
|
-
|
|
176
|
-
created_at=legacy_user.created_at or datetime.now(
|
|
175
|
+
role_uuid=legacy_user.role_uuid,
|
|
176
|
+
created_at=legacy_user.created_at or datetime.now(UTC),
|
|
177
177
|
last_seen=legacy_user.last_seen,
|
|
178
178
|
visits=legacy_user.visits,
|
|
179
179
|
)
|
|
@@ -190,7 +190,7 @@ async def migrate_from_sql(
|
|
|
190
190
|
cred_key: UUID = legacy_cred.uuid
|
|
191
191
|
new_cred = Credential(
|
|
192
192
|
credential_id=legacy_cred.credential_id,
|
|
193
|
-
|
|
193
|
+
user_uuid=legacy_cred.user_uuid,
|
|
194
194
|
aaguid=legacy_cred.aaguid,
|
|
195
195
|
public_key=legacy_cred.public_key,
|
|
196
196
|
sign_count=legacy_cred.sign_count,
|
|
@@ -217,8 +217,8 @@ async def migrate_from_sql(
|
|
|
217
217
|
# Already in new format or unknown - try to use as-is
|
|
218
218
|
session_key = base64url.enc(old_key[:12])
|
|
219
219
|
db.sessions[session_key] = Session(
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
user_uuid=sess.user_uuid,
|
|
221
|
+
credential_uuid=sess.credential_uuid,
|
|
222
222
|
host=sess.host,
|
|
223
223
|
ip=sess.ip,
|
|
224
224
|
user_agent=sess.user_agent,
|
|
@@ -241,14 +241,14 @@ async def migrate_from_sql(
|
|
|
241
241
|
# Already in new format or unknown - truncate to 9 bytes
|
|
242
242
|
token_key = old_key[:9]
|
|
243
243
|
db.reset_tokens[token_key] = ResetToken(
|
|
244
|
-
|
|
244
|
+
user_uuid=token.user_uuid,
|
|
245
245
|
expiry=token.expiry,
|
|
246
246
|
token_type=token.token_type,
|
|
247
247
|
)
|
|
248
248
|
print(f" Migrated {len(token_models)} reset tokens")
|
|
249
249
|
|
|
250
250
|
# Queue and flush all changes using the transaction mechanism
|
|
251
|
-
with db.transaction("migrate"):
|
|
251
|
+
with db.transaction("migrate:sql"):
|
|
252
252
|
pass # All data already added to _data, transaction commits on exit
|
|
253
253
|
|
|
254
254
|
await store.flush()
|
paskia/migrate/sql.py
CHANGED
|
@@ -9,7 +9,7 @@ DO NOT use this module for new code. Use paskia.db instead.
|
|
|
9
9
|
|
|
10
10
|
from contextlib import asynccontextmanager
|
|
11
11
|
from dataclasses import dataclass
|
|
12
|
-
from datetime import
|
|
12
|
+
from datetime import UTC, datetime
|
|
13
13
|
from uuid import UUID
|
|
14
14
|
|
|
15
15
|
from sqlalchemy import (
|
|
@@ -25,11 +25,6 @@ from sqlalchemy.dialects.sqlite import BLOB
|
|
|
25
25
|
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
|
26
26
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
|
27
27
|
|
|
28
|
-
from paskia.db import (
|
|
29
|
-
Org,
|
|
30
|
-
Role,
|
|
31
|
-
)
|
|
32
|
-
|
|
33
28
|
|
|
34
29
|
# Legacy User class for SQL schema (uses 'role_uuid' not 'role')
|
|
35
30
|
@dataclass
|
|
@@ -71,6 +66,17 @@ class _LegacyRole:
|
|
|
71
66
|
permissions: list[str] | None = None
|
|
72
67
|
|
|
73
68
|
|
|
69
|
+
# Legacy Org class for SQL schema (has mutable permissions/roles lists)
|
|
70
|
+
@dataclass
|
|
71
|
+
class _LegacyOrg:
|
|
72
|
+
"""Org as stored in the old SQL schema with mutable permissions/roles."""
|
|
73
|
+
|
|
74
|
+
uuid: UUID
|
|
75
|
+
display_name: str
|
|
76
|
+
permissions: list[str] | None = None
|
|
77
|
+
roles: list[_LegacyRole] | None = None
|
|
78
|
+
|
|
79
|
+
|
|
74
80
|
# Legacy Session class for SQL schema (uses 'key' as field, 'user_uuid', 'credential_uuid')
|
|
75
81
|
@dataclass
|
|
76
82
|
class _LegacySession:
|
|
@@ -112,8 +118,8 @@ def _normalize_dt(value: datetime | None) -> datetime | None:
|
|
|
112
118
|
if value is None:
|
|
113
119
|
return None
|
|
114
120
|
if value.tzinfo is None:
|
|
115
|
-
return value.replace(tzinfo=
|
|
116
|
-
return value.astimezone(
|
|
121
|
+
return value.replace(tzinfo=UTC)
|
|
122
|
+
return value.astimezone(UTC)
|
|
117
123
|
|
|
118
124
|
|
|
119
125
|
class Base(DeclarativeBase):
|
|
@@ -128,12 +134,13 @@ class OrgModel(Base):
|
|
|
128
134
|
|
|
129
135
|
def as_dataclass(self):
|
|
130
136
|
# Base Org without permissions/roles (filled by data accessors)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
return _LegacyOrg(
|
|
138
|
+
uuid=UUID(bytes=self.uuid),
|
|
139
|
+
display_name=self.display_name,
|
|
140
|
+
)
|
|
134
141
|
|
|
135
142
|
@staticmethod
|
|
136
|
-
def from_dataclass(org:
|
|
143
|
+
def from_dataclass(org: _LegacyOrg):
|
|
137
144
|
return OrgModel(uuid=org.uuid.bytes, display_name=org.display_name)
|
|
138
145
|
|
|
139
146
|
|
|
@@ -172,7 +179,7 @@ class UserModel(Base):
|
|
|
172
179
|
LargeBinary(16), ForeignKey("roles.uuid", ondelete="CASCADE"), nullable=False
|
|
173
180
|
)
|
|
174
181
|
created_at: Mapped[datetime] = mapped_column(
|
|
175
|
-
DateTime(timezone=True), default=lambda: datetime.now(
|
|
182
|
+
DateTime(timezone=True), default=lambda: datetime.now(UTC)
|
|
176
183
|
)
|
|
177
184
|
last_seen: Mapped[datetime | None] = mapped_column(
|
|
178
185
|
DateTime(timezone=True), nullable=True
|
|
@@ -195,7 +202,7 @@ class UserModel(Base):
|
|
|
195
202
|
uuid=user.uuid.bytes,
|
|
196
203
|
display_name=user.display_name,
|
|
197
204
|
role_uuid=user.role_uuid.bytes,
|
|
198
|
-
created_at=user.created_at or datetime.now(
|
|
205
|
+
created_at=user.created_at or datetime.now(UTC),
|
|
199
206
|
last_seen=user.last_seen,
|
|
200
207
|
visits=user.visits,
|
|
201
208
|
)
|
|
@@ -215,7 +222,7 @@ class CredentialModel(Base):
|
|
|
215
222
|
public_key: Mapped[bytes] = mapped_column(BLOB, nullable=False)
|
|
216
223
|
sign_count: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
217
224
|
created_at: Mapped[datetime] = mapped_column(
|
|
218
|
-
DateTime(timezone=True), default=lambda: datetime.now(
|
|
225
|
+
DateTime(timezone=True), default=lambda: datetime.now(UTC)
|
|
219
226
|
)
|
|
220
227
|
last_used: Mapped[datetime | None] = mapped_column(
|
|
221
228
|
DateTime(timezone=True), nullable=True
|
|
@@ -255,7 +262,7 @@ class SessionModel(Base):
|
|
|
255
262
|
user_agent: Mapped[str] = mapped_column(String(512), nullable=False)
|
|
256
263
|
renewed: Mapped[datetime] = mapped_column(
|
|
257
264
|
DateTime(timezone=True),
|
|
258
|
-
default=lambda: datetime.now(
|
|
265
|
+
default=lambda: datetime.now(UTC),
|
|
259
266
|
nullable=False,
|
|
260
267
|
)
|
|
261
268
|
|
|
@@ -388,7 +395,7 @@ class DB:
|
|
|
388
395
|
result = await session.execute(select(PermissionModel))
|
|
389
396
|
return [p.as_dataclass() for p in result.scalars().all()]
|
|
390
397
|
|
|
391
|
-
async def list_organizations(self) -> list[
|
|
398
|
+
async def list_organizations(self) -> list[_LegacyOrg]:
|
|
392
399
|
async with self.session() as session:
|
|
393
400
|
# Load all orgs
|
|
394
401
|
orgs_result = await session.execute(select(OrgModel))
|
|
@@ -415,13 +422,13 @@ class DB:
|
|
|
415
422
|
perms_by_role.setdefault(rp.role_uuid, []).append(rp.permission_id)
|
|
416
423
|
|
|
417
424
|
# Build org dataclasses with roles and permission IDs
|
|
418
|
-
roles_by_org: dict[bytes, list[
|
|
425
|
+
roles_by_org: dict[bytes, list[_LegacyRole]] = {}
|
|
419
426
|
for rm in role_models:
|
|
420
427
|
r_dc = rm.as_dataclass()
|
|
421
428
|
r_dc.permissions = perms_by_role.get(rm.uuid, [])
|
|
422
429
|
roles_by_org.setdefault(rm.org_uuid, []).append(r_dc)
|
|
423
430
|
|
|
424
|
-
orgs: list[
|
|
431
|
+
orgs: list[_LegacyOrg] = []
|
|
425
432
|
for om in org_models:
|
|
426
433
|
o_dc = om.as_dataclass()
|
|
427
434
|
o_dc.permissions = perms_by_org.get(om.uuid, [])
|
paskia/remoteauth.py
CHANGED
|
@@ -19,9 +19,9 @@ The first 3 words of the token serve as the pairing code for manual entry.
|
|
|
19
19
|
|
|
20
20
|
import asyncio
|
|
21
21
|
import logging
|
|
22
|
+
from collections.abc import Callable
|
|
22
23
|
from dataclasses import dataclass
|
|
23
|
-
from datetime import datetime, timedelta
|
|
24
|
-
from typing import Callable
|
|
24
|
+
from datetime import UTC, datetime, timedelta
|
|
25
25
|
from uuid import UUID
|
|
26
26
|
|
|
27
27
|
from paskia.util import passphrase, pow
|
|
@@ -94,7 +94,7 @@ class RemoteAuthManager:
|
|
|
94
94
|
|
|
95
95
|
async def _cleanup_expired(self):
|
|
96
96
|
"""Remove expired requests and notify waiting clients."""
|
|
97
|
-
now = datetime.now(
|
|
97
|
+
now = datetime.now(UTC)
|
|
98
98
|
expired_keys = []
|
|
99
99
|
async with self._lock:
|
|
100
100
|
for key, req in self._requests.items():
|
|
@@ -123,7 +123,7 @@ class RemoteAuthManager:
|
|
|
123
123
|
Returns:
|
|
124
124
|
(code, expiry) - The 3-word passphrase code and expiration time
|
|
125
125
|
"""
|
|
126
|
-
now = datetime.now(
|
|
126
|
+
now = datetime.now(UTC)
|
|
127
127
|
expiry = now + REMOTE_AUTH_LIFETIME
|
|
128
128
|
|
|
129
129
|
async with self._lock:
|
|
@@ -160,7 +160,7 @@ class RemoteAuthManager:
|
|
|
160
160
|
req = self._requests.get(normalized)
|
|
161
161
|
if req is None:
|
|
162
162
|
return None
|
|
163
|
-
now = datetime.now(
|
|
163
|
+
now = datetime.now(UTC)
|
|
164
164
|
if now > req.created_at + REMOTE_AUTH_LIFETIME:
|
|
165
165
|
# Expired
|
|
166
166
|
del self._requests[normalized]
|
|
@@ -331,7 +331,7 @@ class RemoteAuthManager:
|
|
|
331
331
|
req = self._requests.get(token)
|
|
332
332
|
if req is None:
|
|
333
333
|
return None
|
|
334
|
-
now = datetime.now(
|
|
334
|
+
now = datetime.now(UTC)
|
|
335
335
|
if now > req.created_at + REMOTE_AUTH_LIFETIME:
|
|
336
336
|
del self._requests[token]
|
|
337
337
|
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: paskia
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Passkey Auth made easy: all sites and APIs can be guarded even without any changes on the protected site.
|
|
5
5
|
Project-URL: Homepage, https://git.zi.fi/LeoVasanko/paskia
|
|
6
6
|
Project-URL: Repository, https://github.com/LeoVasanko/paskia
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
paskia/__init__.py,sha256=6eopO87IOFA2zfOuqt8Jj8Tdtp93HBMOgUBtTzMRweM,57
|
|
2
|
+
paskia/_version.py,sha256=XS8OMho0YiZyQ_qDeRsy__m_nWUzYVEJw-NLk1VtDQU,706
|
|
3
|
+
paskia/authsession.py,sha256=7TGZuJw4RLsRJ-pemii6zRXTR-wdLx3nFVItytKFz5s,1259
|
|
4
|
+
paskia/bootstrap.py,sha256=FShAMvLmLxQ4HfE9yz1ZB6EO9fC-lQroesU4dC58VO8,3875
|
|
5
|
+
paskia/config.py,sha256=BdGzQ3Ja1enSTHmkDkBDGQk_JluT3VaK3Y7AqB5xMlk,723
|
|
6
|
+
paskia/globals.py,sha256=ip03kLoS_27cNIgXTVcXNoeQDjTAC_IILuXaHKShTws,1712
|
|
7
|
+
paskia/remoteauth.py,sha256=IyC1Z9YTYjPi4h8B0UwwoWfxaheEgyfksbKraOrAcqA,12418
|
|
8
|
+
paskia/sansio.py,sha256=LQRdV1kW_aGwDWC8fhyEvqWPwKZVx_8qzQv65et6utg,9727
|
|
9
|
+
paskia/aaguid/__init__.py,sha256=I5HMkAwiyLKKlkZOb9z5s2xGApXIbhbBuuX3IhW2y8E,1047
|
|
10
|
+
paskia/aaguid/combined_aaguid.json,sha256=CaZ96AiwdAjBnyVZnJ1eolAHxUQMB2H6mDgZkorYg_A,4124722
|
|
11
|
+
paskia/db/__init__.py,sha256=BGiCFZFX4xMsFn6aKvuV7X7VL-NoA-URdl2493EfRXE,3220
|
|
12
|
+
paskia/db/background.py,sha256=hj3hXoEpneVWhrAHZvoL09DVVaqOTqe-n9RIJZbbEos,3546
|
|
13
|
+
paskia/db/jsonl.py,sha256=1uHBSTtLEc6CChoRJx2zYjFrMcPkGCZN_8MQpHCohFw,9959
|
|
14
|
+
paskia/db/logging.py,sha256=ENCHdrlUz27hjWPFLezpF9bpO-pnrkgO6bNnfCyHcJ4,11017
|
|
15
|
+
paskia/db/migrations.py,sha256=XHHC0LbxXBN6gldiKm4PhDVqEqroMN1E8tz0LEqGPbQ,957
|
|
16
|
+
paskia/db/operations.py,sha256=rCKDNwEfcQz-5DUtZHZECcE9syX50LOFIrmZw9iUink,26443
|
|
17
|
+
paskia/db/structs.py,sha256=G6udtoomKmB8wijO6x1AObX9Oas66gBmJ_YxIiDLO6E,14060
|
|
18
|
+
paskia/fastapi/__init__.py,sha256=NFsTX1qytoyZKiur7RDTa2fxiOWHrop5CAAx8rqK9E0,58
|
|
19
|
+
paskia/fastapi/__main__.py,sha256=DADaKS27BoDqTtfP_p1qbatUL1URjAy9wyJBgjhAQIA,8032
|
|
20
|
+
paskia/fastapi/admin.py,sha256=8raj__JkNTYuvjdZejnK4BhaZBl219qjobmUafQMRkI,30343
|
|
21
|
+
paskia/fastapi/api.py,sha256=RTRhhn6d44aE3MNrepgLBWIPgDPCNr6dHLKSEja_sgU,9240
|
|
22
|
+
paskia/fastapi/auth_host.py,sha256=Y5w9Mz6jyq0hj7SX8LfwebaesUOLGcWzGW9lsmw5WOo,3242
|
|
23
|
+
paskia/fastapi/authz.py,sha256=ui87Ii4hsy0V8f68wGSYft2D7OHAD2l2tsHqokAgBt8,3322
|
|
24
|
+
paskia/fastapi/logging.py,sha256=xP7dxwy8bfKRft3jZPBdsNQk8eQ3nIHB8BUyz7A7sI0,8840
|
|
25
|
+
paskia/fastapi/mainapp.py,sha256=bW7dVxgZfrPtmASri4X7mD5P4sHOmIq3AmoAj37-e8M,5057
|
|
26
|
+
paskia/fastapi/remote.py,sha256=0hsJj8qK89h1U7-5nJFCk9cTte2tvh02b510v-_TGxU,17789
|
|
27
|
+
paskia/fastapi/reset.py,sha256=MuZqhOF68P9kGq5zKPV19FjTIvhZQ423YowzHKcVjlc,3573
|
|
28
|
+
paskia/fastapi/response.py,sha256=gTPNJtS92HfQYey2DMMN8oM1YazNSj6tjBBuFJuuBhc,611
|
|
29
|
+
paskia/fastapi/session.py,sha256=BRnlgR8pTY7o0f7qFnkdyepS2fKEAgqwT9Hj951sZJM,1479
|
|
30
|
+
paskia/fastapi/user.py,sha256=1vi1usiH8IFqqmLkwq2CLoy-x46VTlUnsiNglndajV8,4599
|
|
31
|
+
paskia/fastapi/ws.py,sha256=iY8CVO0W117Vln0DW2xHxiCk__KI29oTMOB2BZEwv34,3581
|
|
32
|
+
paskia/fastapi/wschat.py,sha256=qbEY6AlDlvjeUoIGac3K3DH41MPxPCYuiaFOnz9gxMU,3699
|
|
33
|
+
paskia/fastapi/wsutil.py,sha256=JMPSSWDzMJr7cVobWTFM0HwJrSj_tfKmoO7JkfewuAE,2898
|
|
34
|
+
paskia/frontend-build/auth/index.html,sha256=FO5wXmc7WTTzOZXOKyvO9XrHsk0c931_j_Z3I2xYLes,936
|
|
35
|
+
paskia/frontend-build/auth/admin/index.html,sha256=XTbO2ag2Sojpx7K49vXjNylKmlj0VrqKbNiIhPt4rWc,862
|
|
36
|
+
paskia/frontend-build/auth/assets/AccessDenied-C29NZI95.css,sha256=lJ7TS_wxvrvF_5I8BIDZ23-A-4iusm6WKF4XseT_zuo,7945
|
|
37
|
+
paskia/frontend-build/auth/assets/AccessDenied-DAdzg_MJ.js,sha256=i0hIbfiTnRmRFFWEW7-vLj7v7IQ_cPcP3sIfZWlNcNQ,51889
|
|
38
|
+
paskia/frontend-build/auth/assets/RestrictedAuth-BOdNrlQB.css,sha256=6r_Kf-Q7sueSICtQt8-zufZc1U6qbs084JW-IxUdOoM,5401
|
|
39
|
+
paskia/frontend-build/auth/assets/RestrictedAuth-BSusdAfp.js,sha256=6d9HZzXsmO93ZSUaPd42jp1zJG5ZsZBc2kcvX9RY7bc,9761
|
|
40
|
+
paskia/frontend-build/auth/assets/_plugin-vue_export-helper-D2l53SUz.js,sha256=kuJt8utYB9pLXerrxDEXc0Ytx9jgoT98p4FcObciLSU,86296
|
|
41
|
+
paskia/frontend-build/auth/assets/_plugin-vue_export-helper-DYJ24FZK.css,sha256=5RqRAI3OVX7hxpNlUQvBqYzARmW2piqbcI2NU_PDW_s,12272
|
|
42
|
+
paskia/frontend-build/auth/assets/admin-BeFvGyD6.js,sha256=UJd2bEl4L0KNslnbM-EEX_6stf9MoZGP7sueZcnjKy4,41123
|
|
43
|
+
paskia/frontend-build/auth/assets/admin-CmNtuH3s.css,sha256=Jg_QeSPAOGf2dFCi7FDe71KQ0qma5Dbom70WEE-mNb0,7601
|
|
44
|
+
paskia/frontend-build/auth/assets/auth-BKq4T2K2.css,sha256=lfYJTjXr3iM8YDMHxtBN4jY6JrLE7yjR1nWEGbN_1uE,4333
|
|
45
|
+
paskia/frontend-build/auth/assets/auth-DvHf8hgy.js,sha256=uQHMfl0n3LbWgyy4ldBSfQnKIW26OdUgxDzb05WFVdI,25267
|
|
46
|
+
paskia/frontend-build/auth/assets/forward-C86Jm_Uq.js,sha256=GeqWr3Z7kDwdgiE5S1ojjjud71bS2TtEdhHoNRIZB2E,782
|
|
47
|
+
paskia/frontend-build/auth/assets/helpers-DzjFIx78.js,sha256=w_IsCBn3QwidsuwQhVRycd8Fa53lvbgRGGojTBXVlUc,940
|
|
48
|
+
paskia/frontend-build/auth/assets/pow-2N9bxgAo.js,sha256=7AfzW5lcTefPI6YGXrYao1b56L7v5Bon9Y9N40yHsaE,9447
|
|
49
|
+
paskia/frontend-build/auth/assets/reset-B8PlNXuP.css,sha256=19f4h_GGjADzWvaYag9lnwrmttNXvwVYYHcGGy5X61E,238
|
|
50
|
+
paskia/frontend-build/auth/assets/reset-D71FG0VL.js,sha256=ZccTsQHP5YMoQznz7JBfO-1sZ3UouiulnzhMaIzsnzs,3981
|
|
51
|
+
paskia/frontend-build/auth/assets/restricted-CW0drE_k.js,sha256=l8Qxc8N6RYlJdHTqOPX9zEdgBs0SR5ou5Y-My-IRCnA,1023
|
|
52
|
+
paskia/frontend-build/auth/restricted/index.html,sha256=N_1KkcLd52Un6pVCVpGeXnsacR5FVU6jjcO9CQ_4zkc,785
|
|
53
|
+
paskia/frontend-build/int/forward/index.html,sha256=ur0I53vLzasQM3KOvmhVEK0SC5stL56p7040Vmmdz5I,870
|
|
54
|
+
paskia/frontend-build/int/reset/index.html,sha256=Jx0m9XzYeEwhNddsJAUihL3JiW_rvRxBixNjfAzcg94,612
|
|
55
|
+
paskia/migrate/__init__.py,sha256=r2s99mbHfvlzQJ1V3xnxZOwIyMEMxEXDtFqFj7sJC2U,9916
|
|
56
|
+
paskia/migrate/sql.py,sha256=5HNEUnPP0kqis69URJ5keE4JNbwqWe8oYXwf-zKheLI,14333
|
|
57
|
+
paskia-0.10.0.dist-info/METADATA,sha256=TNP_cx3lJEFqNg6H-ZQMojA75zJlIa1YJuddqW4RTsY,4262
|
|
58
|
+
paskia-0.10.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
59
|
+
paskia-0.10.0.dist-info/entry_points.txt,sha256=vvx6RYetgd61I2ODqQPHqrKHgCfuo08w_T35yDlHenE,93
|
|
60
|
+
paskia-0.10.0.dist-info/RECORD,,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.breadcrumbs[data-v-6344dbb8]{margin:.25rem 0 .5rem;line-height:1.2;color:var(--color-text-muted)}.breadcrumbs ol[data-v-6344dbb8]{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;align-items:center;gap:.25rem}.breadcrumbs li[data-v-6344dbb8]{display:inline-flex;align-items:center;gap:.25rem;font-size:.9rem}.breadcrumbs a[data-v-6344dbb8]{text-decoration:none;color:var(--color-link);padding:0 .25rem;border-radius:4px;transition:color .2s ease,background .2s ease}.breadcrumbs .sep[data-v-6344dbb8]{color:var(--color-text-muted);margin:0}.btn-card-delete{display:none}.credential-item:focus .btn-card-delete{display:block}.user-info.has-extra[data-v-ce373d6c]{grid-template-columns:auto 1fr 2fr;grid-template-areas:"heading heading extra" "org org extra" "label1 value1 extra" "label2 value2 extra" "label3 value3 extra"}.user-info[data-v-ce373d6c]:not(.has-extra){grid-template-columns:auto 1fr;grid-template-areas:"heading heading" "org org" "label1 value1" "label2 value2" "label3 value3"}@media(max-width:720px){.user-info.has-extra[data-v-ce373d6c]{grid-template-columns:auto 1fr;grid-template-areas:"heading heading" "org org" "label1 value1" "label2 value2" "label3 value3" "extra extra"}}.user-name-heading[data-v-ce373d6c]{grid-area:heading;display:flex;align-items:center;flex-wrap:wrap;margin:0 0 .25rem}.org-role-sub[data-v-ce373d6c]{grid-area:org;display:flex;flex-direction:column;margin:-.15rem 0 .25rem}.org-line[data-v-ce373d6c]{font-size:.7rem;font-weight:600;line-height:1.1;color:var(--color-text-muted);text-transform:uppercase;letter-spacing:.05em}.role-line[data-v-ce373d6c]{font-size:.65rem;color:var(--color-text-muted);line-height:1.1}.info-label[data-v-ce373d6c]:nth-of-type(1){grid-area:label1}.info-value[data-v-ce373d6c]:nth-of-type(2){grid-area:value1}.info-label[data-v-ce373d6c]:nth-of-type(3){grid-area:label2}.info-value[data-v-ce373d6c]:nth-of-type(4){grid-area:value2}.info-label[data-v-ce373d6c]:nth-of-type(5){grid-area:label3}.info-value[data-v-ce373d6c]:nth-of-type(6){grid-area:value3}.user-info-extra[data-v-ce373d6c]{grid-area:extra;padding-left:2rem;border-left:1px solid var(--color-border)}.user-name-row[data-v-ce373d6c]{display:inline-flex;align-items:center;gap:.35rem;max-width:100%}.user-name-row.editing[data-v-ce373d6c]{flex:1 1 auto}.display-name[data-v-ce373d6c]{font-weight:600;font-size:1.05em;line-height:1.2;max-width:14ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.name-input[data-v-ce373d6c]{width:auto;flex:1 1 140px;min-width:120px;padding:6px 8px;font-size:.9em;border:1px solid var(--color-border-strong);border-radius:6px;background:var(--color-surface);color:var(--color-text)}.user-name-heading .name-input[data-v-ce373d6c]{width:auto}.name-input[data-v-ce373d6c]:focus{outline:none;border-color:var(--color-accent);box-shadow:var(--focus-ring)}.mini-btn[data-v-ce373d6c]{width:auto;padding:4px 6px;margin:0;font-size:.75em;line-height:1;cursor:pointer}.mini-btn[data-v-ce373d6c]:hover:not(:disabled){background:var(--color-accent-soft);color:var(--color-accent)}.mini-btn[data-v-ce373d6c]:active:not(:disabled){transform:translateY(1px)}.mini-btn[data-v-ce373d6c]:disabled{opacity:.5;cursor:not-allowed}@media(max-width:720px){.user-info-extra[data-v-ce373d6c]{padding-left:0;padding-top:1rem;margin-top:1rem;border-left:none;border-top:1px solid var(--color-border)}}dialog[data-v-2ebcbb0a]{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-xl);padding:calc(var(--space-lg) - var(--space-xs));max-width:500px;width:min(500px,90vw);max-height:90vh;overflow-y:auto;position:fixed;inset:0;margin:auto;height:fit-content}dialog[data-v-2ebcbb0a]::backdrop{background:transparent;backdrop-filter:blur(.1rem) brightness(.7);-webkit-backdrop-filter:blur(.1rem) brightness(.7)}dialog[data-v-2ebcbb0a] .modal-title,dialog[data-v-2ebcbb0a] h3{margin:0 0 var(--space-md);font-size:1.25rem;font-weight:600;color:var(--color-heading)}dialog[data-v-2ebcbb0a] form{display:flex;flex-direction:column;gap:var(--space-md)}dialog[data-v-2ebcbb0a] .modal-form{display:flex;flex-direction:column;gap:var(--space-md)}dialog[data-v-2ebcbb0a] .modal-form label{display:flex;flex-direction:column;gap:var(--space-xs);font-weight:500}dialog[data-v-2ebcbb0a] .modal-form input,dialog[data-v-2ebcbb0a] .modal-form textarea{padding:var(--space-md);border:1px solid var(--color-border);border-radius:var(--radius-sm);background:var(--color-bg);color:var(--color-text);font-size:1rem;line-height:1.4;min-height:2.5rem}dialog[data-v-2ebcbb0a] .modal-form input:focus,dialog[data-v-2ebcbb0a] .modal-form textarea:focus{outline:none;border-color:var(--color-accent);box-shadow:0 0 0 2px #c7d2fe}dialog[data-v-2ebcbb0a] .modal-actions{display:flex;justify-content:flex-end;gap:var(--space-sm);margin-top:var(--space-md);margin-bottom:var(--space-xs)}.name-edit-form[data-v-b73321cf]{display:flex;flex-direction:column;gap:var(--space-md)}.error[data-v-b73321cf]{color:var(--color-danger-text)}.small[data-v-b73321cf]{font-size:.9rem}.qr-display[data-v-727427c4]{display:flex;flex-direction:column;align-items:center;gap:.75rem}.qr-section[data-v-727427c4]{display:flex;flex-direction:column;align-items:center;gap:.5rem}.qr-link[data-v-727427c4]{display:flex;flex-direction:column;align-items:center;text-decoration:none;color:inherit;border-radius:var(--radius-sm, 6px);overflow:hidden}.qr-code[data-v-727427c4]{display:block;width:200px;height:200px;max-width:100%;object-fit:contain;border-radius:var(--radius-sm, 6px);background:#fff;cursor:pointer}.link-text[data-v-727427c4]{padding:.5rem;font-size:.75rem;color:var(--color-text-muted);font-family:monospace;word-break:break-all;line-height:1.2;transition:color .2s ease}.qr-link:hover .link-text[data-v-727427c4]{color:var(--color-text)}dialog[data-v-e04dd463]{border:none;background:transparent;padding:0;max-width:none;width:fit-content;height:fit-content;position:fixed;inset:0;margin:auto}dialog[data-v-e04dd463]::backdrop{-webkit-backdrop-filter:blur(.2rem) brightness(.5);backdrop-filter:blur(.2rem) brightness(.5)}.icon-btn[data-v-e04dd463]{background:none;border:none;cursor:pointer;font-size:1rem;opacity:.6}.icon-btn[data-v-e04dd463]:hover{opacity:1}.reg-header-row[data-v-e04dd463]{display:flex;justify-content:space-between;align-items:center;gap:.75rem;margin-bottom:.75rem}.reg-title[data-v-e04dd463]{margin:0;font-size:1.25rem;font-weight:600}.device-dialog[data-v-e04dd463]{background:var(--color-surface);padding:1.25rem 1.25rem 1rem;border-radius:var(--radius-md);max-width:480px;width:100%;box-shadow:0 6px 28px #00000040}.reg-help[data-v-e04dd463]{margin:.5rem 0 .75rem;font-size:.85rem;line-height:1.4;text-align:center;color:var(--color-text-muted)}.reg-actions[data-v-e04dd463]{display:flex;justify-content:flex-end;gap:.5rem;margin-top:1rem}.expiry-note[data-v-e04dd463]{font-size:.75rem;color:var(--color-text-muted);text-align:center;margin-top:.75rem}.loading-container[data-v-130f5abf]{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;gap:1rem}.loading-spinner[data-v-130f5abf]{width:40px;height:40px;border:4px solid var(--color-border);border-top:4px solid var(--color-primary);border-radius:50%;animation:spin-130f5abf 1s linear infinite}@keyframes spin-130f5abf{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.loading-container p[data-v-130f5abf]{color:var(--color-text-muted);margin:0}.message-container[data-v-a7b258e7]{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;padding:2rem}.message-content[data-v-a7b258e7]{text-align:center;max-width:480px}.message-content h2[data-v-a7b258e7]{margin:0 0 1rem;color:var(--color-heading)}.message-content .error-detail[data-v-a7b258e7]{margin:0 0 1.5rem;color:var(--color-text-muted)}.message-content .button-row[data-v-a7b258e7]{display:flex;gap:.75rem;justify-content:center}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{M as At,r as F,N as Rt,O as Yt,P as ue,Q as Tt,R as Qt,S as Gt,T as Wt,n as ze,U as Zt,c as x,w as He,V as Xt,W as en,H as Q,m as tn,X as nn,Y as on,b as R,f as L,z as U,d as T,e as v,t as D,g as se,_ as Y,F as oe,i as ce,B as z,D as Mt,l as de,Z as Nt,$ as Pt,a0 as Dt,a1 as Lt,o as qt,a2 as rn,a as Ft,C as sn,k as xe,h as an,a3 as ln,L as un,x as cn}from"./_plugin-vue_export-helper-nhjnO_bd.js";import{f as G,h as ae,g as We}from"./helpers-DzjFIx78.js";let Ut;const fe=e=>Ut=e,Kt=Symbol();function Oe(e){return e&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"&&typeof e.toJSON!="function"}var re;(function(e){e.direct="direct",e.patchObject="patch object",e.patchFunction="patch function"})(re||(re={}));function vr(){const e=At(!0),s=e.run(()=>F({}));let r=[],t=[];const n=Rt({install(o){fe(n),n._a=o,o.provide(Kt,n),o.config.globalProperties.$pinia=n,t.forEach(i=>r.push(i)),t=[]},use(o){return this._a?r.push(o):t.push(o),this},_p:r,_a:null,_e:e,_s:new Map,state:s});return n}const Vt=()=>{};function Ze(e,s,r,t=Vt){e.add(s);const n=()=>{e.delete(s)&&t()};return!r&&Gt()&&Wt(n),n}function ee(e,...s){e.forEach(r=>{r(...s)})}const dn=e=>e(),Xe=Symbol(),pe=Symbol();function je(e,s){e instanceof Map&&s instanceof Map?s.forEach((r,t)=>e.set(t,r)):e instanceof Set&&s instanceof Set&&s.forEach(e.add,e);for(const r in s){if(!s.hasOwnProperty(r))continue;const t=s[r],n=e[r];Oe(n)&&Oe(t)&&e.hasOwnProperty(r)&&!ue(t)&&!Tt(t)?e[r]=je(n,t):e[r]=t}return e}const fn=Symbol();function hn(e){return!Oe(e)||!Object.prototype.hasOwnProperty.call(e,fn)}const{assign:J}=Object;function gn(e){return!!(ue(e)&&e.effect)}function mn(e,s,r,t){const{state:n,actions:o,getters:i}=s,a=r.state.value[e];let l;function u(){a||(r.state.value[e]=n?n():{});const f=Zt(r.state.value[e]);return J(f,o,Object.keys(i||{}).reduce((w,b)=>(w[b]=Rt(x(()=>{fe(r);const h=r._s.get(e);return i[b].call(h,h)})),w),{}))}return l=Ht(e,u,s,r,t,!0),l}function Ht(e,s,r={},t,n,o){let i;const a=J({actions:{}},r),l={deep:!0};let u,f,w=new Set,b=new Set,h;const d=t.state.value[e];!o&&!d&&(t.state.value[e]={}),F({});let g;function N(y){let m;u=f=!1,typeof y=="function"?(y(t.state.value[e]),m={type:re.patchFunction,storeId:e,events:h}):(je(t.state.value[e],y),m={type:re.patchObject,payload:y,storeId:e,events:h});const E=g=Symbol();ze().then(()=>{g===E&&(u=!0)}),f=!0,ee(w,m,t.state.value[e])}const A=o?function(){const{state:m}=r,E=m?m():{};this.$patch(_=>{J(_,E)})}:Vt;function P(){i.stop(),w.clear(),b.clear(),t._s.delete(e)}const c=(y,m="")=>{if(Xe in y)return y[pe]=m,y;const E=function(){fe(t);const _=Array.from(arguments),k=new Set,B=new Set;function M(q){k.add(q)}function V(q){B.add(q)}ee(b,{args:_,name:E[pe],store:I,after:M,onError:V});let K;try{K=y.apply(this&&this.$id===e?this:I,_)}catch(q){throw ee(B,q),q}return K instanceof Promise?K.then(q=>(ee(k,q),q)).catch(q=>(ee(B,q),Promise.reject(q))):(ee(k,K),K)};return E[Xe]=!0,E[pe]=m,E},S={_p:t,$id:e,$onAction:Ze.bind(null,b),$patch:N,$reset:A,$subscribe(y,m={}){const E=Ze(w,y,m.detached,()=>_()),_=i.run(()=>He(()=>t.state.value[e],k=>{(m.flush==="sync"?f:u)&&y({storeId:e,type:re.direct,events:h},k)},J({},l,m)));return E},$dispose:P},I=Yt(S);t._s.set(e,I);const p=(t._a&&t._a.runWithContext||dn)(()=>t._e.run(()=>(i=At()).run(()=>s({action:c}))));for(const y in p){const m=p[y];if(ue(m)&&!gn(m)||Tt(m))o||(d&&hn(m)&&(ue(m)?m.value=d[y]:je(m,d[y])),t.state.value[e][y]=m);else if(typeof m=="function"){const E=c(m,y);p[y]=E,a.actions[y]=m}}return J(I,p),J(Qt(I),p),Object.defineProperty(I,"$state",{get:()=>t.state.value[e],set:y=>{N(m=>{J(m,y)})}}),t._p.forEach(y=>{J(I,i.run(()=>y({store:I,app:t._a,pinia:t,options:a})))}),d&&o&&r.hydrate&&r.hydrate(I.$state,d),u=!0,f=!0,I}function yn(e,s,r){let t;const n=typeof s=="function";t=n?r:s;function o(i,a){const l=en();return i=i||(l?Xt(Kt,null):null),i&&fe(i),i=Ut,i._s.has(e)||(n?Ht(e,s,t,i):mn(e,t,i)),i._s.get(e)}return o.$id=e,o}const $e=yn("auth",{state:()=>({userInfo:null,isLoading:!1,settings:null,currentView:"login",status:{message:"",type:"info",show:!1}}),getters:{},actions:{setLoading(e){this.isLoading=!!e},showMessage(e,s="info",r=null){const t=r??(s==="error"?5e3:3e3);this.status={message:e,type:s,show:!0},t>0&&setTimeout(()=>{this.status.show=!1},t)},async setSessionCookie(e){if(!e?.session_token)throw console.error("setSessionCookie called with missing session_token:",e),new Error("Authentication response missing session_token");return await Q("/auth/api/set-session",{method:"POST",headers:{Authorization:`Bearer ${e.session_token}`}})},async register(){this.isLoading=!0;try{const e=await on();return await this.setSessionCookie(e),await this.loadUserInfo(),this.selectView(),e}finally{this.isLoading=!1}},async authenticate(){this.isLoading=!0;try{const e=await nn();return await this.setSessionCookie(e),await this.loadUserInfo(),this.selectView(),e}finally{this.isLoading=!1}},selectView(){this.userInfo?this.currentView="profile":this.currentView="login"},async loadSettings(){this.settings=await tn()},async loadUserInfo(){try{this.userInfo=await Q("/auth/api/user-info",{method:"POST"}),console.log("User info loaded:",this.userInfo)}catch(e){throw e.status===401||e.status===403?console.log("Authentication required:",e.message):this.showMessage(e.message||"Failed to load user info","error",5e3),e}},async deleteCredential(e){await Q(`/auth/api/user/credential/${e}`,{method:"DELETE"}),await this.loadUserInfo()},async terminateSession(e){try{if((await Q(`/auth/api/user/session/${e}`,{method:"DELETE"}))?.current_session_terminated){sessionStorage.clear(),location.reload();return}await this.loadUserInfo(),this.showMessage("Session terminated","success",2500)}catch(s){throw console.error("Terminate session error:",s),s}},async logout(){try{await Q("/auth/api/logout",{method:"POST"}),sessionStorage.clear(),location.reload()}catch(e){console.error("Logout error:",e),e.status!==401&&e.status!==403&&this.showMessage(e.message,"error")}},async logoutEverywhere(){try{await Q("/auth/api/user/logout-all",{method:"POST"}),sessionStorage.clear(),location.reload()}catch(e){console.error("Logout-all error:",e),e.status!==401&&e.status!==403&&this.showMessage(e.message,"error")}}}}),pn={key:0,class:"global-status",style:{display:"block"}},Cr={__name:"StatusMessage",setup(e){const s=$e();return(r,t)=>U(s).status.show?(T(),R("div",pn,[v("div",{class:se(["status",U(s).status.type])},D(U(s).status.message),3)])):L("",!0)}},wn=["href"],bn={key:0,class:"sep"},vn={__name:"Breadcrumbs",props:{entries:{type:Array,default:()=>[]},showHome:{type:Boolean,default:!0},homeHref:{type:String,default:"/"}},setup(e,{expose:s}){const r=e,t=F(null),n=x(()=>r.showHome&&r.entries.length>0&&r.entries[0].href===r.homeHref?[{label:"🏠 "+r.entries[0].label,href:r.homeHref},...r.entries.slice(1)]:[...r.showHome?[{label:"🏠",href:r.homeHref}]:[],...r.entries]),o=x(()=>{const u=window.location.hash||window.location.pathname;for(let f=n.value.length-1;f>=0;f--){const w=n.value[f].href;if(w===u||w&&u.startsWith(w))return f}return n.value.length-1});function i(u){if(u.target===t.value){const f=t.value.querySelectorAll("a"),w=Math.min(o.value,f.length-1);f[w]&&f[w].focus()}}function a(u){const f=z(u);f&&(f==="left"||f==="right")&&(u.preventDefault(),Mt(t.value,u.target,f,{itemSelector:"a"}))}function l(){const u=t.value?.querySelectorAll("a");if(u?.length){const f=Math.min(o.value,u.length-1);u[f]?.focus()}}return s({focusCurrent:l}),(u,f)=>n.value.length>1?(T(),R("nav",{key:0,ref_key:"navRef",ref:t,class:"breadcrumbs","aria-label":"Breadcrumb",tabindex:"0",onFocusin:i,onKeydown:a},[v("ol",null,[(T(!0),R(oe,null,ce(n.value,(w,b)=>(T(),R("li",{key:b},[v("a",{href:w.href,tabindex:"-1"},D(w.label),9,wn),b<n.value.length-1?(T(),R("span",bn," — ")):L("",!0)]))),128))])],544)):L("",!0)}},Sr=Y(vn,[["__scopeId","data-v-6344dbb8"]]),Cn={key:0},Sn={key:1},En=["onFocusin","onKeydown"],_n={class:"item-top"},kn={class:"item-icon"},Bn=["src","alt"],In={key:1,class:"auth-emoji"},An={class:"item-title"},Rn={class:"item-actions"},Tn={key:0,class:"badge badge-current"},Mn={key:1,class:"badge badge-current"},Nn={key:2,class:"badge badge-current"},Pn=["onClick","disabled","title"],Dn={class:"item-details"},Ln={class:"credential-dates"},qn={class:"date-value"},Fn={class:"date-value"},Un={class:"date-value"},Er={__name:"CredentialList",props:{credentials:{type:Array,default:()=>[]},aaguidInfo:{type:Object,default:()=>({})},loading:{type:Boolean,default:!1},allowDelete:{type:Boolean,default:!1},hoveredCredentialUuid:{type:String,default:null},hoveredSessionCredentialUuid:{type:String,default:null},navigationDisabled:{type:Boolean,default:!1}},emits:["delete","credentialHover","navigate-out"],setup(e,{emit:s}){const r=e,t=s,n=h=>{t("credentialHover",h)},o=h=>{h.currentTarget.contains(h.relatedTarget)||t("credentialHover",null)},i=h=>{h.currentTarget.matches(":focus")||(h.currentTarget.focus(),h.stopPropagation())},a=(h,d)=>{Pt(h,()=>{r.allowDelete&&!d.is_current_session&&t("delete",d)})},l=h=>{if(r.navigationDisabled)return;const d=h.currentTarget;if(h.target===d){const g=d.querySelector(".credential-item");g&&g.focus()}},u=h=>{r.navigationDisabled||Dt(h,d=>t("navigate-out",d))},f=(h,d)=>{if(a(h,d),h.defaultPrevented||r.navigationDisabled)return;const g=z(h);if(g){h.preventDefault();const N=h.currentTarget.closest(".credential-list");Nt(N,h.currentTarget,g,{itemSelector:".credential-item"})==="boundary"&&t("navigate-out",g)}},w=h=>{const d=r.aaguidInfo?.[h.aaguid];return d?d.name:"Unknown Authenticator"},b=h=>{const d=r.aaguidInfo?.[h.aaguid];if(!d)return null;const N=window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"icon_dark":"icon_light";return d[N]||null};return(h,d)=>(T(),R("div",{class:"credential-list",tabindex:"0",onFocusin:l,onKeydown:u},[e.loading?(T(),R("div",Cn,[...d[2]||(d[2]=[v("p",null,"Loading credentials...",-1)])])):e.credentials?.length?(T(!0),R(oe,{key:2},ce(e.credentials,g=>(T(),R("div",{key:g.credential,class:se(["credential-item",{"current-session":g.is_current_session&&!e.hoveredCredentialUuid&&!e.hoveredSessionCredentialUuid,"is-hovered":e.hoveredCredentialUuid===g.credential,"is-linked-session":e.hoveredSessionCredentialUuid===g.credential}]),tabindex:"-1",onMousedown:d[0]||(d[0]=de(()=>{},["prevent"])),onClickCapture:i,onFocusin:N=>n(g.credential),onFocusout:d[1]||(d[1]=N=>o(N)),onKeydown:N=>f(N,g)},[v("div",_n,[v("div",kn,[b(g)?(T(),R("img",{key:0,src:b(g),alt:w(g),class:"auth-icon",width:"32",height:"32"},null,8,Bn)):(T(),R("span",In,"🔑"))]),v("h4",An,D(w(g)),1),v("div",Rn,[g.is_current_session&&!e.hoveredCredentialUuid&&!e.hoveredSessionCredentialUuid?(T(),R("span",Tn,"Current")):e.hoveredCredentialUuid===g.credential?(T(),R("span",Mn,"Selected")):e.hoveredSessionCredentialUuid===g.credential?(T(),R("span",Nn,"Linked")):L("",!0),e.allowDelete?(T(),R("button",{key:3,onClick:N=>h.$emit("delete",g),class:"btn-card-delete",disabled:g.is_current_session,title:g.is_current_session?"Cannot delete current session credential":"Delete passkey and terminate any linked sessions.",tabindex:"-1"},"❌",8,Pn)):L("",!0)])]),v("div",Dn,[v("div",Ln,[d[4]||(d[4]=v("span",{class:"date-label"},"Created:",-1)),v("span",qn,D(U(G)(g.created_at)),1),d[5]||(d[5]=v("span",{class:"date-label"},"Last used:",-1)),v("span",Fn,D(U(G)(g.last_used)),1),d[6]||(d[6]=v("span",{class:"date-label"},"Last verified:",-1)),v("span",Un,D(U(G)(g.last_verified)),1)])])],42,En))),128)):(T(),R("div",Sn,[...d[3]||(d[3]=[v("p",null,"No passkeys found.",-1)])]))],32))}},Kn={class:"user-name-heading"},Vn={class:"user-name-row"},Hn=["title"],On={key:0,class:"org-role-sub"},jn={key:0,class:"org-line"},zn={key:1,class:"role-line"},xn={class:"user-details"},$n={class:"date-value"},Jn={class:"date-value"},Yn={class:"date-value"},Qn={key:1,class:"user-info-extra"},Gn={__name:"UserBasicInfo",props:{name:{type:String,required:!0},visits:{type:[Number,String],default:0},createdAt:{type:[String,Number,Date],default:null},lastSeen:{type:[String,Number,Date],default:null},updateEndpoint:{type:String,default:null},canEdit:{type:Boolean,default:!0},loading:{type:Boolean,default:!1},orgDisplayName:{type:String,default:""},roleName:{type:String,default:""}},emits:["saved","editName"],setup(e,{emit:s}){const r=e,t=s;$e();const n=x(()=>!!r.name);return(o,i)=>n.value?(T(),R("div",{key:0,class:se(["user-info",{"has-extra":o.$slots.default}])},[v("h3",Kn,[i[1]||(i[1]=v("span",{class:"icon"},"👤",-1)),v("span",Vn,[v("span",{class:"display-name",title:e.name},D(e.name),9,Hn),e.canEdit&&e.updateEndpoint?(T(),R("button",{key:0,class:"mini-btn",onClick:i[0]||(i[0]=a=>t("editName")),title:"Edit name"},"✏️")):L("",!0)])]),e.orgDisplayName||e.roleName?(T(),R("div",On,[e.orgDisplayName?(T(),R("div",jn,D(e.orgDisplayName),1)):L("",!0),e.roleName?(T(),R("div",zn,D(e.roleName),1)):L("",!0)])):L("",!0),v("div",xn,[i[2]||(i[2]=v("span",{class:"date-label"},[v("strong",null,"Visits:")],-1)),v("span",$n,D(e.visits||0),1),i[3]||(i[3]=v("span",{class:"date-label"},[v("strong",null,"Registered:")],-1)),v("span",Jn,D(U(G)(e.createdAt)),1),i[4]||(i[4]=v("span",{class:"date-label"},[v("strong",null,"Last seen:")],-1)),v("span",Yn,D(U(G)(e.lastSeen)),1)]),o.$slots.default?(T(),R("div",Qn,[Lt(o.$slots,"default",{},void 0)])):L("",!0)],2)):L("",!0)}},_r=Y(Gn,[["__scopeId","data-v-ce373d6c"]]),Wn={__name:"Modal",props:{focusFallback:{type:[HTMLElement,Object],default:null},focusIndex:{type:Number,default:-1},focusSiblingSelector:{type:String,default:""}},emits:["close"],setup(e){const s=e,r=F(null),t=F(null),n=()=>{const i=t.value;if(!i)return;if(document.body.contains(i)&&!i.disabled){i.focus();return}if(s.focusSiblingSelector&&s.focusIndex>=0){const l=[s.focusFallback?.$el||s.focusFallback,i.closest("[data-nav-group]"),i.parentElement?.closest("section"),document.querySelector(".view-root")].filter(Boolean);for(const u of l){if(!u)continue;const f=u.querySelectorAll(s.focusSiblingSelector);if(f.length>0){const w=Math.min(s.focusIndex,f.length-1),b=f[w];if(b&&!b.disabled){b.focus();return}}}}const a=s.focusFallback?.$el||s.focusFallback;if(a&&document.body.contains(a)){const l=a.querySelector?.('button:not([disabled]), a, [tabindex="0"]')||a;if(l?.focus){l.focus();return}}},o=i=>{const a=z(i);if(!a)return;const l=i.target,u=l.closest(".modal-actions");if(u&&(a==="left"||a==="right"))i.preventDefault(),Mt(u,l,a,{itemSelector:"button"});else if(a==="up"&&u){i.preventDefault();const w=(u.closest("form")||u.closest(".modal-form"))?.querySelectorAll("input, textarea, select, button:not(.modal-actions button)");w&&w.length>0&&w[w.length-1].focus()}else if(a==="down"&&!u){const f=l.closest("form")||l.closest(".modal-form");if(f){i.preventDefault();const w=f.querySelector(".modal-actions");w&&sn(w,{primarySelector:".btn-primary",itemSelector:"button"})}}};return qt(()=>{t.value=document.activeElement,ze(()=>{if(r.value){r.value.showModal();const i=r.value.querySelector(".modal-actions .btn-primary");i&&i.setAttribute("data-nav-primary",""),rn(r.value)}})}),Ft(()=>{n()}),(i,a)=>(T(),R("dialog",{ref_key:"dialog",ref:r,onClose:a[0]||(a[0]=l=>i.$emit("close")),onKeydown:o},[Lt(i.$slots,"default",{},void 0)],544))}},kr=Y(Wn,[["__scopeId","data-v-2ebcbb0a"]]),Zn={class:"name-edit-form"},Xn=["for"],eo=["id","type","placeholder","disabled"],to={key:0,class:"error small"},no=["disabled"],oo=["disabled"],ro={__name:"NameEditForm",props:{modelValue:{type:String,default:""},label:{type:String,default:"Name"},placeholder:{type:String,default:""},submitText:{type:String,default:"Save"},cancelText:{type:String,default:"Cancel"},busy:{type:Boolean,default:!1},error:{type:String,default:""},autoFocus:{type:Boolean,default:!0},autoSelect:{type:Boolean,default:!0},inputId:{type:String,default:null},inputType:{type:String,default:"text"}},emits:["update:modelValue","cancel"],setup(e,{emit:s}){const r=e,t=s,n=F(null),o=`name-edit-${Math.random().toString(36).slice(2,10)}`,i=x({get:()=>r.modelValue,set:f=>t("update:modelValue",f)}),a=x(()=>r.inputId||o),l=f=>{if(z(f)==="up"){f.preventDefault(),n.value?.focus();return}};function u(){t("cancel")}return(f,w)=>(T(),R("div",Zn,[v("label",{for:a.value},[xe(D(e.label)+" ",1),an(v("input",{id:a.value,ref_key:"inputRef",ref:n,type:e.inputType,placeholder:e.placeholder,"onUpdate:modelValue":w[0]||(w[0]=b=>i.value=b),disabled:e.busy,required:""},null,8,eo),[[ln,i.value]])],8,Xn),e.error?(T(),R("div",to,D(e.error),1)):L("",!0),v("div",{class:"modal-actions",onKeydown:l},[v("button",{type:"button",class:"btn-secondary",onClick:u,disabled:e.busy},D(e.cancelText),9,no),v("button",{type:"submit",class:"btn-primary",disabled:e.busy,"data-nav-primary":""},D(e.submitText),9,oo)],32)]))}},Br=Y(ro,[["__scopeId","data-v-b73321cf"]]),so={class:"section-block","data-component":"session-list-section"},io={class:"section-header"},ao={class:"section-description"},lo={class:"section-body"},uo=["onKeydown"],co=["href"],fo={class:"session-list"},ho=["onFocusin","onKeydown"],go={class:"item-top"},mo={class:"item-title"},yo={class:"item-actions"},po={key:0,class:"badge badge-current"},wo={key:1,class:"badge badge-current"},bo={key:2,class:"badge badge-current"},vo={key:3,class:"badge"},Co=["onClick","disabled","title"],So={class:"item-details"},Eo={class:"session-dates"},_o={class:"date-label"},ko=["onClick"],Bo={key:1,class:"empty-state"},Ir={__name:"SessionList",props:{sessions:{type:Array,default:()=>[]},emptyMessage:{type:String,default:"You currently have no other active sessions."},sectionDescription:{type:String,default:"Review where you're signed in and end any sessions you no longer recognize."},terminatingSessions:{type:Object,default:()=>({})},hoveredCredentialUuid:{type:String,default:null},navigationDisabled:{type:Boolean,default:!1}},emits:["terminate","sessionHover","navigate-out"],setup(e,{emit:s}){const r=e,t=s,n=$e(),o=F(null),i=F(null),a=c=>{i.value=c,o.value=c.ip||null,t("sessionHover",c)},l=c=>{c.currentTarget.contains(c.relatedTarget)||(i.value=null,o.value=null,t("sessionHover",null))},u=c=>{c.currentTarget.matches(":focus")||(c.currentTarget.focus(),c.stopPropagation())},f=c=>!!r.terminatingSessions[c],w=(c,S)=>{const I=c.currentTarget,p=I.querySelector(".session-list")?.querySelectorAll(".session-item"),y=Array.from(document.querySelectorAll(".session-group")),m=y.indexOf(I);if(c.key==="Enter"&&c.target===I){S&&I.querySelector("a")?.click();return}if(r.navigationDisabled)return;const E=z(c);if(["down","right"].includes(E)&&c.target===I){c.preventDefault(),p?.[0]?.focus();return}if(["up","left"].includes(E)&&c.target===I){c.preventDefault(),m>0?y[m-1].focus():t("navigate-out","up");return}Dt(c,_=>t("navigate-out",_))},b=(c,S)=>{if(Pt(c,()=>{f(S.id)||t("terminate",S)}),c.defaultPrevented||r.navigationDisabled)return;const I=z(c);if(I){c.preventDefault();const C=c.currentTarget.closest(".session-group"),p=C.querySelector(".session-list");if(Nt(p,c.currentTarget,I,{itemSelector:".session-item"})==="boundary"){if(I==="left"||I==="up")C?.focus();else if(I==="down"||I==="right"){const m=Array.from(document.querySelectorAll(".session-group")),E=m.indexOf(C);E<m.length-1?m[E+1].focus():t("navigate-out","down")}}}c.key==="Escape"&&(c.preventDefault(),c.currentTarget.closest(".session-group")?.focus())},h=c=>`${c.includes(":")?"http":"https"}://${c}`,d=async c=>{if(c)try{await navigator.clipboard.writeText(c),n.showMessage("Full IP copied to clipboard!","success",2e3)}catch(S){console.error("Failed to copy IP:",S),n.showMessage("Failed to copy IP","error",3e3)}},g=c=>ae(c)??c,N=x(()=>{if(o.value)return ae(o.value);const c=r.sessions.find(S=>S.is_current);return c?ae(c.ip):null}),A=c=>N.value&&ae(c)===N.value,P=x(()=>{const c={};for(const p of r.sessions){const y=p.host||"";c[y]||(c[y]={sessions:[],isCurrentSite:!1}),c[y].sessions.push(p),p.is_current_host&&(c[y].isCurrentSite=!0)}for(const p in c)c[p].sessions.sort((y,m)=>new Date(m.last_renewed)-new Date(y.last_renewed));const S=new Intl.Collator(void 0,{numeric:!0,sensitivity:"base"}),I=Object.keys(c).sort(S.compare),C={};for(const p of I)C[p]=c[p];return C});return(c,S)=>(T(),R("section",so,[v("div",io,[S[2]||(S[2]=v("h2",null,"Active Sessions",-1)),v("p",ao,D(e.sectionDescription),1)]),v("div",lo,[v("div",null,[Array.isArray(e.sessions)&&e.sessions.length?(T(!0),R(oe,{key:0},ce(P.value,(I,C)=>(T(),R("div",{key:C,class:"session-group",tabindex:"0",onKeydown:p=>w(p,C)},[v("span",{class:se(["session-group-host",{"is-current-site":I.isCurrentSite}])},[S[3]||(S[3]=v("span",{class:"session-group-icon"},"🌐",-1)),C?(T(),R("a",{key:0,href:h(C),tabindex:"-1",target:"_blank",rel:"noopener noreferrer"},D(C),9,co)):(T(),R(oe,{key:1},[xe("Unbound host")],64))],2),v("div",fo,[(T(!0),R(oe,null,ce(I.sessions,p=>(T(),R("div",{key:p.id,class:se(["session-item",{"is-current":p.is_current&&!o.value&&!e.hoveredCredentialUuid,"is-hovered":i.value?.id===p.id,"is-linked-credential":e.hoveredCredentialUuid===p.credential}]),tabindex:"-1",onMousedown:S[0]||(S[0]=de(()=>{},["prevent"])),onClickCapture:u,onFocusin:y=>a(p),onFocusout:S[1]||(S[1]=y=>l(y)),onKeydown:y=>b(y,p)},[v("div",go,[v("h4",mo,D(p.user_agent),1),v("div",yo,[p.is_current&&!o.value&&!e.hoveredCredentialUuid?(T(),R("span",po,"Current")):i.value?.id===p.id?(T(),R("span",wo,"Selected")):e.hoveredCredentialUuid===p.credential?(T(),R("span",bo,"Linked")):!e.hoveredCredentialUuid&&A(p.ip)?(T(),R("span",vo,"Same IP")):L("",!0),v("button",{onClick:y=>c.$emit("terminate",p),class:"btn-card-delete",disabled:f(p.id),title:f(p.id)?"Terminating...":"Terminate session",tabindex:"-1"},"❌",8,Co)])]),v("div",So,[v("div",Eo,[v("span",_o,D(U(G)(p.last_renewed)),1),v("span",{class:"date-value",onClick:y=>d(p.ip),title:"Click to copy full IP"},D(g(p.ip)),9,ko)])])],42,ho))),128))])],40,uo))),128)):(T(),R("div",Bo,[v("p",null,D(e.emptyMessage),1)]))])])]))}};function Io(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var te={},we,et;function Ao(){return et||(et=1,we=function(){return typeof Promise=="function"&&Promise.prototype&&Promise.prototype.then}),we}var be={},$={},tt;function W(){if(tt)return $;tt=1;let e;const s=[0,26,44,70,100,134,172,196,242,292,346,404,466,532,581,655,733,815,901,991,1085,1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,2611,2761,2876,3034,3196,3362,3532,3706];return $.getSymbolSize=function(t){if(!t)throw new Error('"version" cannot be null or undefined');if(t<1||t>40)throw new Error('"version" should be in range from 1 to 40');return t*4+17},$.getSymbolTotalCodewords=function(t){return s[t]},$.getBCHDigit=function(r){let t=0;for(;r!==0;)t++,r>>>=1;return t},$.setToSJISFunction=function(t){if(typeof t!="function")throw new Error('"toSJISFunc" is not a valid function.');e=t},$.isKanjiModeEnabled=function(){return typeof e<"u"},$.toSJIS=function(t){return e(t)},$}var ve={},nt;function Je(){return nt||(nt=1,(function(e){e.L={bit:1},e.M={bit:0},e.Q={bit:3},e.H={bit:2};function s(r){if(typeof r!="string")throw new Error("Param is not a string");switch(r.toLowerCase()){case"l":case"low":return e.L;case"m":case"medium":return e.M;case"q":case"quartile":return e.Q;case"h":case"high":return e.H;default:throw new Error("Unknown EC Level: "+r)}}e.isValid=function(t){return t&&typeof t.bit<"u"&&t.bit>=0&&t.bit<4},e.from=function(t,n){if(e.isValid(t))return t;try{return s(t)}catch{return n}}})(ve)),ve}var Ce,ot;function Ro(){if(ot)return Ce;ot=1;function e(){this.buffer=[],this.length=0}return e.prototype={get:function(s){const r=Math.floor(s/8);return(this.buffer[r]>>>7-s%8&1)===1},put:function(s,r){for(let t=0;t<r;t++)this.putBit((s>>>r-t-1&1)===1)},getLengthInBits:function(){return this.length},putBit:function(s){const r=Math.floor(this.length/8);this.buffer.length<=r&&this.buffer.push(0),s&&(this.buffer[r]|=128>>>this.length%8),this.length++}},Ce=e,Ce}var Se,rt;function To(){if(rt)return Se;rt=1;function e(s){if(!s||s<1)throw new Error("BitMatrix size must be defined and greater than 0");this.size=s,this.data=new Uint8Array(s*s),this.reservedBit=new Uint8Array(s*s)}return e.prototype.set=function(s,r,t,n){const o=s*this.size+r;this.data[o]=t,n&&(this.reservedBit[o]=!0)},e.prototype.get=function(s,r){return this.data[s*this.size+r]},e.prototype.xor=function(s,r,t){this.data[s*this.size+r]^=t},e.prototype.isReserved=function(s,r){return this.reservedBit[s*this.size+r]},Se=e,Se}var Ee={},st;function Mo(){return st||(st=1,(function(e){const s=W().getSymbolSize;e.getRowColCoords=function(t){if(t===1)return[];const n=Math.floor(t/7)+2,o=s(t),i=o===145?26:Math.ceil((o-13)/(2*n-2))*2,a=[o-7];for(let l=1;l<n-1;l++)a[l]=a[l-1]-i;return a.push(6),a.reverse()},e.getPositions=function(t){const n=[],o=e.getRowColCoords(t),i=o.length;for(let a=0;a<i;a++)for(let l=0;l<i;l++)a===0&&l===0||a===0&&l===i-1||a===i-1&&l===0||n.push([o[a],o[l]]);return n}})(Ee)),Ee}var _e={},it;function No(){if(it)return _e;it=1;const e=W().getSymbolSize,s=7;return _e.getPositions=function(t){const n=e(t);return[[0,0],[n-s,0],[0,n-s]]},_e}var ke={},at;function Po(){return at||(at=1,(function(e){e.Patterns={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};const s={N1:3,N2:3,N3:40,N4:10};e.isValid=function(n){return n!=null&&n!==""&&!isNaN(n)&&n>=0&&n<=7},e.from=function(n){return e.isValid(n)?parseInt(n,10):void 0},e.getPenaltyN1=function(n){const o=n.size;let i=0,a=0,l=0,u=null,f=null;for(let w=0;w<o;w++){a=l=0,u=f=null;for(let b=0;b<o;b++){let h=n.get(w,b);h===u?a++:(a>=5&&(i+=s.N1+(a-5)),u=h,a=1),h=n.get(b,w),h===f?l++:(l>=5&&(i+=s.N1+(l-5)),f=h,l=1)}a>=5&&(i+=s.N1+(a-5)),l>=5&&(i+=s.N1+(l-5))}return i},e.getPenaltyN2=function(n){const o=n.size;let i=0;for(let a=0;a<o-1;a++)for(let l=0;l<o-1;l++){const u=n.get(a,l)+n.get(a,l+1)+n.get(a+1,l)+n.get(a+1,l+1);(u===4||u===0)&&i++}return i*s.N2},e.getPenaltyN3=function(n){const o=n.size;let i=0,a=0,l=0;for(let u=0;u<o;u++){a=l=0;for(let f=0;f<o;f++)a=a<<1&2047|n.get(u,f),f>=10&&(a===1488||a===93)&&i++,l=l<<1&2047|n.get(f,u),f>=10&&(l===1488||l===93)&&i++}return i*s.N3},e.getPenaltyN4=function(n){let o=0;const i=n.data.length;for(let l=0;l<i;l++)o+=n.data[l];return Math.abs(Math.ceil(o*100/i/5)-10)*s.N4};function r(t,n,o){switch(t){case e.Patterns.PATTERN000:return(n+o)%2===0;case e.Patterns.PATTERN001:return n%2===0;case e.Patterns.PATTERN010:return o%3===0;case e.Patterns.PATTERN011:return(n+o)%3===0;case e.Patterns.PATTERN100:return(Math.floor(n/2)+Math.floor(o/3))%2===0;case e.Patterns.PATTERN101:return n*o%2+n*o%3===0;case e.Patterns.PATTERN110:return(n*o%2+n*o%3)%2===0;case e.Patterns.PATTERN111:return(n*o%3+(n+o)%2)%2===0;default:throw new Error("bad maskPattern:"+t)}}e.applyMask=function(n,o){const i=o.size;for(let a=0;a<i;a++)for(let l=0;l<i;l++)o.isReserved(l,a)||o.xor(l,a,r(n,l,a))},e.getBestMask=function(n,o){const i=Object.keys(e.Patterns).length;let a=0,l=1/0;for(let u=0;u<i;u++){o(u),e.applyMask(u,n);const f=e.getPenaltyN1(n)+e.getPenaltyN2(n)+e.getPenaltyN3(n)+e.getPenaltyN4(n);e.applyMask(u,n),f<l&&(l=f,a=u)}return a}})(ke)),ke}var le={},lt;function Ot(){if(lt)return le;lt=1;const e=Je(),s=[1,1,1,1,1,1,1,1,1,1,2,2,1,2,2,4,1,2,4,4,2,4,4,4,2,4,6,5,2,4,6,6,2,5,8,8,4,5,8,8,4,5,8,11,4,8,10,11,4,9,12,16,4,9,16,16,6,10,12,18,6,10,17,16,6,11,16,19,6,13,18,21,7,14,21,25,8,16,20,25,8,17,23,25,9,17,23,34,9,18,25,30,10,20,27,32,12,21,29,35,12,23,34,37,12,25,34,40,13,26,35,42,14,28,38,45,15,29,40,48,16,31,43,51,17,33,45,54,18,35,48,57,19,37,51,60,19,38,53,63,20,40,56,66,21,43,59,70,22,45,62,74,24,47,65,77,25,49,68,81],r=[7,10,13,17,10,16,22,28,15,26,36,44,20,36,52,64,26,48,72,88,36,64,96,112,40,72,108,130,48,88,132,156,60,110,160,192,72,130,192,224,80,150,224,264,96,176,260,308,104,198,288,352,120,216,320,384,132,240,360,432,144,280,408,480,168,308,448,532,180,338,504,588,196,364,546,650,224,416,600,700,224,442,644,750,252,476,690,816,270,504,750,900,300,560,810,960,312,588,870,1050,336,644,952,1110,360,700,1020,1200,390,728,1050,1260,420,784,1140,1350,450,812,1200,1440,480,868,1290,1530,510,924,1350,1620,540,980,1440,1710,570,1036,1530,1800,570,1064,1590,1890,600,1120,1680,1980,630,1204,1770,2100,660,1260,1860,2220,720,1316,1950,2310,750,1372,2040,2430];return le.getBlocksCount=function(n,o){switch(o){case e.L:return s[(n-1)*4+0];case e.M:return s[(n-1)*4+1];case e.Q:return s[(n-1)*4+2];case e.H:return s[(n-1)*4+3];default:return}},le.getTotalCodewordsCount=function(n,o){switch(o){case e.L:return r[(n-1)*4+0];case e.M:return r[(n-1)*4+1];case e.Q:return r[(n-1)*4+2];case e.H:return r[(n-1)*4+3];default:return}},le}var Be={},ne={},ut;function Do(){if(ut)return ne;ut=1;const e=new Uint8Array(512),s=new Uint8Array(256);return(function(){let t=1;for(let n=0;n<255;n++)e[n]=t,s[t]=n,t<<=1,t&256&&(t^=285);for(let n=255;n<512;n++)e[n]=e[n-255]})(),ne.log=function(t){if(t<1)throw new Error("log("+t+")");return s[t]},ne.exp=function(t){return e[t]},ne.mul=function(t,n){return t===0||n===0?0:e[s[t]+s[n]]},ne}var ct;function Lo(){return ct||(ct=1,(function(e){const s=Do();e.mul=function(t,n){const o=new Uint8Array(t.length+n.length-1);for(let i=0;i<t.length;i++)for(let a=0;a<n.length;a++)o[i+a]^=s.mul(t[i],n[a]);return o},e.mod=function(t,n){let o=new Uint8Array(t);for(;o.length-n.length>=0;){const i=o[0];for(let l=0;l<n.length;l++)o[l]^=s.mul(n[l],i);let a=0;for(;a<o.length&&o[a]===0;)a++;o=o.slice(a)}return o},e.generateECPolynomial=function(t){let n=new Uint8Array([1]);for(let o=0;o<t;o++)n=e.mul(n,new Uint8Array([1,s.exp(o)]));return n}})(Be)),Be}var Ie,dt;function qo(){if(dt)return Ie;dt=1;const e=Lo();function s(r){this.genPoly=void 0,this.degree=r,this.degree&&this.initialize(this.degree)}return s.prototype.initialize=function(t){this.degree=t,this.genPoly=e.generateECPolynomial(this.degree)},s.prototype.encode=function(t){if(!this.genPoly)throw new Error("Encoder not initialized");const n=new Uint8Array(t.length+this.degree);n.set(t);const o=e.mod(n,this.genPoly),i=this.degree-o.length;if(i>0){const a=new Uint8Array(this.degree);return a.set(o,i),a}return o},Ie=s,Ie}var Ae={},Re={},Te={},ft;function jt(){return ft||(ft=1,Te.isValid=function(s){return!isNaN(s)&&s>=1&&s<=40}),Te}var H={},ht;function zt(){if(ht)return H;ht=1;const e="[0-9]+",s="[A-Z $%*+\\-./:]+";let r="(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";r=r.replace(/u/g,"\\u");const t="(?:(?![A-Z0-9 $%*+\\-./:]|"+r+`)(?:.|[\r
|
|
2
|
-
]))+`;H.KANJI=new RegExp(r,"g"),H.BYTE_KANJI=new RegExp("[^A-Z0-9 $%*+\\-./:]+","g"),H.BYTE=new RegExp(t,"g"),H.NUMERIC=new RegExp(e,"g"),H.ALPHANUMERIC=new RegExp(s,"g");const n=new RegExp("^"+r+"$"),o=new RegExp("^"+e+"$"),i=new RegExp("^[A-Z0-9 $%*+\\-./:]+$");return H.testKanji=function(l){return n.test(l)},H.testNumeric=function(l){return o.test(l)},H.testAlphanumeric=function(l){return i.test(l)},H}var gt;function Z(){return gt||(gt=1,(function(e){const s=jt(),r=zt();e.NUMERIC={id:"Numeric",bit:1,ccBits:[10,12,14]},e.ALPHANUMERIC={id:"Alphanumeric",bit:2,ccBits:[9,11,13]},e.BYTE={id:"Byte",bit:4,ccBits:[8,16,16]},e.KANJI={id:"Kanji",bit:8,ccBits:[8,10,12]},e.MIXED={bit:-1},e.getCharCountIndicator=function(o,i){if(!o.ccBits)throw new Error("Invalid mode: "+o);if(!s.isValid(i))throw new Error("Invalid version: "+i);return i>=1&&i<10?o.ccBits[0]:i<27?o.ccBits[1]:o.ccBits[2]},e.getBestModeForData=function(o){return r.testNumeric(o)?e.NUMERIC:r.testAlphanumeric(o)?e.ALPHANUMERIC:r.testKanji(o)?e.KANJI:e.BYTE},e.toString=function(o){if(o&&o.id)return o.id;throw new Error("Invalid mode")},e.isValid=function(o){return o&&o.bit&&o.ccBits};function t(n){if(typeof n!="string")throw new Error("Param is not a string");switch(n.toLowerCase()){case"numeric":return e.NUMERIC;case"alphanumeric":return e.ALPHANUMERIC;case"kanji":return e.KANJI;case"byte":return e.BYTE;default:throw new Error("Unknown mode: "+n)}}e.from=function(o,i){if(e.isValid(o))return o;try{return t(o)}catch{return i}}})(Re)),Re}var mt;function Fo(){return mt||(mt=1,(function(e){const s=W(),r=Ot(),t=Je(),n=Z(),o=jt(),i=7973,a=s.getBCHDigit(i);function l(b,h,d){for(let g=1;g<=40;g++)if(h<=e.getCapacity(g,d,b))return g}function u(b,h){return n.getCharCountIndicator(b,h)+4}function f(b,h){let d=0;return b.forEach(function(g){const N=u(g.mode,h);d+=N+g.getBitsLength()}),d}function w(b,h){for(let d=1;d<=40;d++)if(f(b,d)<=e.getCapacity(d,h,n.MIXED))return d}e.from=function(h,d){return o.isValid(h)?parseInt(h,10):d},e.getCapacity=function(h,d,g){if(!o.isValid(h))throw new Error("Invalid QR Code version");typeof g>"u"&&(g=n.BYTE);const N=s.getSymbolTotalCodewords(h),A=r.getTotalCodewordsCount(h,d),P=(N-A)*8;if(g===n.MIXED)return P;const c=P-u(g,h);switch(g){case n.NUMERIC:return Math.floor(c/10*3);case n.ALPHANUMERIC:return Math.floor(c/11*2);case n.KANJI:return Math.floor(c/13);case n.BYTE:default:return Math.floor(c/8)}},e.getBestVersionForData=function(h,d){let g;const N=t.from(d,t.M);if(Array.isArray(h)){if(h.length>1)return w(h,N);if(h.length===0)return 1;g=h[0]}else g=h;return l(g.mode,g.getLength(),N)},e.getEncodedBits=function(h){if(!o.isValid(h)||h<7)throw new Error("Invalid QR Code version");let d=h<<12;for(;s.getBCHDigit(d)-a>=0;)d^=i<<s.getBCHDigit(d)-a;return h<<12|d}})(Ae)),Ae}var Me={},yt;function Uo(){if(yt)return Me;yt=1;const e=W(),s=1335,r=21522,t=e.getBCHDigit(s);return Me.getEncodedBits=function(o,i){const a=o.bit<<3|i;let l=a<<10;for(;e.getBCHDigit(l)-t>=0;)l^=s<<e.getBCHDigit(l)-t;return(a<<10|l)^r},Me}var Ne={},Pe,pt;function Ko(){if(pt)return Pe;pt=1;const e=Z();function s(r){this.mode=e.NUMERIC,this.data=r.toString()}return s.getBitsLength=function(t){return 10*Math.floor(t/3)+(t%3?t%3*3+1:0)},s.prototype.getLength=function(){return this.data.length},s.prototype.getBitsLength=function(){return s.getBitsLength(this.data.length)},s.prototype.write=function(t){let n,o,i;for(n=0;n+3<=this.data.length;n+=3)o=this.data.substr(n,3),i=parseInt(o,10),t.put(i,10);const a=this.data.length-n;a>0&&(o=this.data.substr(n),i=parseInt(o,10),t.put(i,a*3+1))},Pe=s,Pe}var De,wt;function Vo(){if(wt)return De;wt=1;const e=Z(),s=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"," ","$","%","*","+","-",".","/",":"];function r(t){this.mode=e.ALPHANUMERIC,this.data=t}return r.getBitsLength=function(n){return 11*Math.floor(n/2)+6*(n%2)},r.prototype.getLength=function(){return this.data.length},r.prototype.getBitsLength=function(){return r.getBitsLength(this.data.length)},r.prototype.write=function(n){let o;for(o=0;o+2<=this.data.length;o+=2){let i=s.indexOf(this.data[o])*45;i+=s.indexOf(this.data[o+1]),n.put(i,11)}this.data.length%2&&n.put(s.indexOf(this.data[o]),6)},De=r,De}var Le,bt;function Ho(){if(bt)return Le;bt=1;const e=Z();function s(r){this.mode=e.BYTE,typeof r=="string"?this.data=new TextEncoder().encode(r):this.data=new Uint8Array(r)}return s.getBitsLength=function(t){return t*8},s.prototype.getLength=function(){return this.data.length},s.prototype.getBitsLength=function(){return s.getBitsLength(this.data.length)},s.prototype.write=function(r){for(let t=0,n=this.data.length;t<n;t++)r.put(this.data[t],8)},Le=s,Le}var qe,vt;function Oo(){if(vt)return qe;vt=1;const e=Z(),s=W();function r(t){this.mode=e.KANJI,this.data=t}return r.getBitsLength=function(n){return n*13},r.prototype.getLength=function(){return this.data.length},r.prototype.getBitsLength=function(){return r.getBitsLength(this.data.length)},r.prototype.write=function(t){let n;for(n=0;n<this.data.length;n++){let o=s.toSJIS(this.data[n]);if(o>=33088&&o<=40956)o-=33088;else if(o>=57408&&o<=60351)o-=49472;else throw new Error("Invalid SJIS character: "+this.data[n]+`
|
|
3
|
-
Make sure your charset is UTF-8`);o=(o>>>8&255)*192+(o&255),t.put(o,13)}},qe=r,qe}var Fe={exports:{}},Ct;function jo(){return Ct||(Ct=1,(function(e){var s={single_source_shortest_paths:function(r,t,n){var o={},i={};i[t]=0;var a=s.PriorityQueue.make();a.push(t,0);for(var l,u,f,w,b,h,d,g,N;!a.empty();){l=a.pop(),u=l.value,w=l.cost,b=r[u]||{};for(f in b)b.hasOwnProperty(f)&&(h=b[f],d=w+h,g=i[f],N=typeof i[f]>"u",(N||g>d)&&(i[f]=d,a.push(f,d),o[f]=u))}if(typeof n<"u"&&typeof i[n]>"u"){var A=["Could not find a path from ",t," to ",n,"."].join("");throw new Error(A)}return o},extract_shortest_path_from_predecessor_list:function(r,t){for(var n=[],o=t;o;)n.push(o),r[o],o=r[o];return n.reverse(),n},find_path:function(r,t,n){var o=s.single_source_shortest_paths(r,t,n);return s.extract_shortest_path_from_predecessor_list(o,n)},PriorityQueue:{make:function(r){var t=s.PriorityQueue,n={},o;r=r||{};for(o in t)t.hasOwnProperty(o)&&(n[o]=t[o]);return n.queue=[],n.sorter=r.sorter||t.default_sorter,n},default_sorter:function(r,t){return r.cost-t.cost},push:function(r,t){var n={value:r,cost:t};this.queue.push(n),this.queue.sort(this.sorter)},pop:function(){return this.queue.shift()},empty:function(){return this.queue.length===0}}};e.exports=s})(Fe)),Fe.exports}var St;function zo(){return St||(St=1,(function(e){const s=Z(),r=Ko(),t=Vo(),n=Ho(),o=Oo(),i=zt(),a=W(),l=jo();function u(A){return unescape(encodeURIComponent(A)).length}function f(A,P,c){const S=[];let I;for(;(I=A.exec(c))!==null;)S.push({data:I[0],index:I.index,mode:P,length:I[0].length});return S}function w(A){const P=f(i.NUMERIC,s.NUMERIC,A),c=f(i.ALPHANUMERIC,s.ALPHANUMERIC,A);let S,I;return a.isKanjiModeEnabled()?(S=f(i.BYTE,s.BYTE,A),I=f(i.KANJI,s.KANJI,A)):(S=f(i.BYTE_KANJI,s.BYTE,A),I=[]),P.concat(c,S,I).sort(function(p,y){return p.index-y.index}).map(function(p){return{data:p.data,mode:p.mode,length:p.length}})}function b(A,P){switch(P){case s.NUMERIC:return r.getBitsLength(A);case s.ALPHANUMERIC:return t.getBitsLength(A);case s.KANJI:return o.getBitsLength(A);case s.BYTE:return n.getBitsLength(A)}}function h(A){return A.reduce(function(P,c){const S=P.length-1>=0?P[P.length-1]:null;return S&&S.mode===c.mode?(P[P.length-1].data+=c.data,P):(P.push(c),P)},[])}function d(A){const P=[];for(let c=0;c<A.length;c++){const S=A[c];switch(S.mode){case s.NUMERIC:P.push([S,{data:S.data,mode:s.ALPHANUMERIC,length:S.length},{data:S.data,mode:s.BYTE,length:S.length}]);break;case s.ALPHANUMERIC:P.push([S,{data:S.data,mode:s.BYTE,length:S.length}]);break;case s.KANJI:P.push([S,{data:S.data,mode:s.BYTE,length:u(S.data)}]);break;case s.BYTE:P.push([{data:S.data,mode:s.BYTE,length:u(S.data)}])}}return P}function g(A,P){const c={},S={start:{}};let I=["start"];for(let C=0;C<A.length;C++){const p=A[C],y=[];for(let m=0;m<p.length;m++){const E=p[m],_=""+C+m;y.push(_),c[_]={node:E,lastCount:0},S[_]={};for(let k=0;k<I.length;k++){const B=I[k];c[B]&&c[B].node.mode===E.mode?(S[B][_]=b(c[B].lastCount+E.length,E.mode)-b(c[B].lastCount,E.mode),c[B].lastCount+=E.length):(c[B]&&(c[B].lastCount=E.length),S[B][_]=b(E.length,E.mode)+4+s.getCharCountIndicator(E.mode,P))}}I=y}for(let C=0;C<I.length;C++)S[I[C]].end=0;return{map:S,table:c}}function N(A,P){let c;const S=s.getBestModeForData(A);if(c=s.from(P,S),c!==s.BYTE&&c.bit<S.bit)throw new Error('"'+A+'" cannot be encoded with mode '+s.toString(c)+`.
|
|
4
|
-
Suggested mode is: `+s.toString(S));switch(c===s.KANJI&&!a.isKanjiModeEnabled()&&(c=s.BYTE),c){case s.NUMERIC:return new r(A);case s.ALPHANUMERIC:return new t(A);case s.KANJI:return new o(A);case s.BYTE:return new n(A)}}e.fromArray=function(P){return P.reduce(function(c,S){return typeof S=="string"?c.push(N(S,null)):S.data&&c.push(N(S.data,S.mode)),c},[])},e.fromString=function(P,c){const S=w(P,a.isKanjiModeEnabled()),I=d(S),C=g(I,c),p=l.find_path(C.map,"start","end"),y=[];for(let m=1;m<p.length-1;m++)y.push(C.table[p[m]].node);return e.fromArray(h(y))},e.rawSplit=function(P){return e.fromArray(w(P,a.isKanjiModeEnabled()))}})(Ne)),Ne}var Et;function xo(){if(Et)return be;Et=1;const e=W(),s=Je(),r=Ro(),t=To(),n=Mo(),o=No(),i=Po(),a=Ot(),l=qo(),u=Fo(),f=Uo(),w=Z(),b=zo();function h(C,p){const y=C.size,m=o.getPositions(p);for(let E=0;E<m.length;E++){const _=m[E][0],k=m[E][1];for(let B=-1;B<=7;B++)if(!(_+B<=-1||y<=_+B))for(let M=-1;M<=7;M++)k+M<=-1||y<=k+M||(B>=0&&B<=6&&(M===0||M===6)||M>=0&&M<=6&&(B===0||B===6)||B>=2&&B<=4&&M>=2&&M<=4?C.set(_+B,k+M,!0,!0):C.set(_+B,k+M,!1,!0))}}function d(C){const p=C.size;for(let y=8;y<p-8;y++){const m=y%2===0;C.set(y,6,m,!0),C.set(6,y,m,!0)}}function g(C,p){const y=n.getPositions(p);for(let m=0;m<y.length;m++){const E=y[m][0],_=y[m][1];for(let k=-2;k<=2;k++)for(let B=-2;B<=2;B++)k===-2||k===2||B===-2||B===2||k===0&&B===0?C.set(E+k,_+B,!0,!0):C.set(E+k,_+B,!1,!0)}}function N(C,p){const y=C.size,m=u.getEncodedBits(p);let E,_,k;for(let B=0;B<18;B++)E=Math.floor(B/3),_=B%3+y-8-3,k=(m>>B&1)===1,C.set(E,_,k,!0),C.set(_,E,k,!0)}function A(C,p,y){const m=C.size,E=f.getEncodedBits(p,y);let _,k;for(_=0;_<15;_++)k=(E>>_&1)===1,_<6?C.set(_,8,k,!0):_<8?C.set(_+1,8,k,!0):C.set(m-15+_,8,k,!0),_<8?C.set(8,m-_-1,k,!0):_<9?C.set(8,15-_-1+1,k,!0):C.set(8,15-_-1,k,!0);C.set(m-8,8,1,!0)}function P(C,p){const y=C.size;let m=-1,E=y-1,_=7,k=0;for(let B=y-1;B>0;B-=2)for(B===6&&B--;;){for(let M=0;M<2;M++)if(!C.isReserved(E,B-M)){let V=!1;k<p.length&&(V=(p[k]>>>_&1)===1),C.set(E,B-M,V),_--,_===-1&&(k++,_=7)}if(E+=m,E<0||y<=E){E-=m,m=-m;break}}}function c(C,p,y){const m=new r;y.forEach(function(M){m.put(M.mode.bit,4),m.put(M.getLength(),w.getCharCountIndicator(M.mode,C)),M.write(m)});const E=e.getSymbolTotalCodewords(C),_=a.getTotalCodewordsCount(C,p),k=(E-_)*8;for(m.getLengthInBits()+4<=k&&m.put(0,4);m.getLengthInBits()%8!==0;)m.putBit(0);const B=(k-m.getLengthInBits())/8;for(let M=0;M<B;M++)m.put(M%2?17:236,8);return S(m,C,p)}function S(C,p,y){const m=e.getSymbolTotalCodewords(p),E=a.getTotalCodewordsCount(p,y),_=m-E,k=a.getBlocksCount(p,y),B=m%k,M=k-B,V=Math.floor(m/k),K=Math.floor(_/k),q=K+1,Ye=V-K,$t=new l(Ye);let he=0;const ie=new Array(k),Qe=new Array(k);let ge=0;const Jt=new Uint8Array(C.buffer);for(let X=0;X<k;X++){const ye=X<M?K:q;ie[X]=Jt.slice(he,he+ye),Qe[X]=$t.encode(ie[X]),he+=ye,ge=Math.max(ge,ye)}const me=new Uint8Array(m);let Ge=0,O,j;for(O=0;O<ge;O++)for(j=0;j<k;j++)O<ie[j].length&&(me[Ge++]=ie[j][O]);for(O=0;O<Ye;O++)for(j=0;j<k;j++)me[Ge++]=Qe[j][O];return me}function I(C,p,y,m){let E;if(Array.isArray(C))E=b.fromArray(C);else if(typeof C=="string"){let V=p;if(!V){const K=b.rawSplit(C);V=u.getBestVersionForData(K,y)}E=b.fromString(C,V||40)}else throw new Error("Invalid data");const _=u.getBestVersionForData(E,y);if(!_)throw new Error("The amount of data is too big to be stored in a QR Code");if(!p)p=_;else if(p<_)throw new Error(`
|
|
5
|
-
The chosen QR Code version cannot contain this amount of data.
|
|
6
|
-
Minimum version required to store current data is: `+_+`.
|
|
7
|
-
`);const k=c(p,y,E),B=e.getSymbolSize(p),M=new t(B);return h(M,p),d(M),g(M,p),A(M,y,0),p>=7&&N(M,p),P(M,k),isNaN(m)&&(m=i.getBestMask(M,A.bind(null,M,y))),i.applyMask(m,M),A(M,y,m),{modules:M,version:p,errorCorrectionLevel:y,maskPattern:m,segments:E}}return be.create=function(p,y){if(typeof p>"u"||p==="")throw new Error("No input text");let m=s.M,E,_;return typeof y<"u"&&(m=s.from(y.errorCorrectionLevel,s.M),E=u.from(y.version),_=i.from(y.maskPattern),y.toSJISFunc&&e.setToSJISFunction(y.toSJISFunc)),I(p,E,m,_)},be}var Ue={},Ke={},_t;function xt(){return _t||(_t=1,(function(e){function s(r){if(typeof r=="number"&&(r=r.toString()),typeof r!="string")throw new Error("Color should be defined as hex string");let t=r.slice().replace("#","").split("");if(t.length<3||t.length===5||t.length>8)throw new Error("Invalid hex color: "+r);(t.length===3||t.length===4)&&(t=Array.prototype.concat.apply([],t.map(function(o){return[o,o]}))),t.length===6&&t.push("F","F");const n=parseInt(t.join(""),16);return{r:n>>24&255,g:n>>16&255,b:n>>8&255,a:n&255,hex:"#"+t.slice(0,6).join("")}}e.getOptions=function(t){t||(t={}),t.color||(t.color={});const n=typeof t.margin>"u"||t.margin===null||t.margin<0?4:t.margin,o=t.width&&t.width>=21?t.width:void 0,i=t.scale||4;return{width:o,scale:o?4:i,margin:n,color:{dark:s(t.color.dark||"#000000ff"),light:s(t.color.light||"#ffffffff")},type:t.type,rendererOpts:t.rendererOpts||{}}},e.getScale=function(t,n){return n.width&&n.width>=t+n.margin*2?n.width/(t+n.margin*2):n.scale},e.getImageWidth=function(t,n){const o=e.getScale(t,n);return Math.floor((t+n.margin*2)*o)},e.qrToImageData=function(t,n,o){const i=n.modules.size,a=n.modules.data,l=e.getScale(i,o),u=Math.floor((i+o.margin*2)*l),f=o.margin*l,w=[o.color.light,o.color.dark];for(let b=0;b<u;b++)for(let h=0;h<u;h++){let d=(b*u+h)*4,g=o.color.light;if(b>=f&&h>=f&&b<u-f&&h<u-f){const N=Math.floor((b-f)/l),A=Math.floor((h-f)/l);g=w[a[N*i+A]?1:0]}t[d++]=g.r,t[d++]=g.g,t[d++]=g.b,t[d]=g.a}}})(Ke)),Ke}var kt;function $o(){return kt||(kt=1,(function(e){const s=xt();function r(n,o,i){n.clearRect(0,0,o.width,o.height),o.style||(o.style={}),o.height=i,o.width=i,o.style.height=i+"px",o.style.width=i+"px"}function t(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}e.render=function(o,i,a){let l=a,u=i;typeof l>"u"&&(!i||!i.getContext)&&(l=i,i=void 0),i||(u=t()),l=s.getOptions(l);const f=s.getImageWidth(o.modules.size,l),w=u.getContext("2d"),b=w.createImageData(f,f);return s.qrToImageData(b.data,o,l),r(w,u,f),w.putImageData(b,0,0),u},e.renderToDataURL=function(o,i,a){let l=a;typeof l>"u"&&(!i||!i.getContext)&&(l=i,i=void 0),l||(l={});const u=e.render(o,i,l),f=l.type||"image/png",w=l.rendererOpts||{};return u.toDataURL(f,w.quality)}})(Ue)),Ue}var Ve={},Bt;function Jo(){if(Bt)return Ve;Bt=1;const e=xt();function s(n,o){const i=n.a/255,a=o+'="'+n.hex+'"';return i<1?a+" "+o+'-opacity="'+i.toFixed(2).slice(1)+'"':a}function r(n,o,i){let a=n+o;return typeof i<"u"&&(a+=" "+i),a}function t(n,o,i){let a="",l=0,u=!1,f=0;for(let w=0;w<n.length;w++){const b=Math.floor(w%o),h=Math.floor(w/o);!b&&!u&&(u=!0),n[w]?(f++,w>0&&b>0&&n[w-1]||(a+=u?r("M",b+i,.5+h+i):r("m",l,0),l=0,u=!1),b+1<o&&n[w+1]||(a+=r("h",f),f=0)):l++}return a}return Ve.render=function(o,i,a){const l=e.getOptions(i),u=o.modules.size,f=o.modules.data,w=u+l.margin*2,b=l.color.light.a?"<path "+s(l.color.light,"fill")+' d="M0 0h'+w+"v"+w+'H0z"/>':"",h="<path "+s(l.color.dark,"stroke")+' d="'+t(f,u,l.margin)+'"/>',d='viewBox="0 0 '+w+" "+w+'"',N='<svg xmlns="http://www.w3.org/2000/svg" '+(l.width?'width="'+l.width+'" height="'+l.width+'" ':"")+d+' shape-rendering="crispEdges">'+b+h+`</svg>
|
|
8
|
-
`;return typeof a=="function"&&a(null,N),N},Ve}var It;function Yo(){if(It)return te;It=1;const e=Ao(),s=xo(),r=$o(),t=Jo();function n(o,i,a,l,u){const f=[].slice.call(arguments,1),w=f.length,b=typeof f[w-1]=="function";if(!b&&!e())throw new Error("Callback required as last argument");if(b){if(w<2)throw new Error("Too few arguments provided");w===2?(u=a,a=i,i=l=void 0):w===3&&(i.getContext&&typeof u>"u"?(u=l,l=void 0):(u=l,l=a,a=i,i=void 0))}else{if(w<1)throw new Error("Too few arguments provided");return w===1?(a=i,i=l=void 0):w===2&&!i.getContext&&(l=a,a=i,i=void 0),new Promise(function(h,d){try{const g=s.create(a,l);h(o(g,i,l))}catch(g){d(g)}})}try{const h=s.create(a,l);u(null,o(h,i,l))}catch(h){u(h)}}return te.create=s.create,te.toCanvas=n.bind(null,r.render),te.toDataURL=n.bind(null,r.renderToDataURL),te.toString=n.bind(null,function(o,i,a){return t.render(o,a)}),te}var Qo=Yo();const Go=Io(Qo),Wo={class:"qr-display"},Zo={class:"qr-section"},Xo=["href","onKeydown"],er={key:0,class:"link-text"},tr={__name:"QRCodeDisplay",props:{url:{type:String,required:!0},showLink:{type:Boolean,default:!1}},emits:["copied"],setup(e,{emit:s}){const r=e,t=s,n=F(null),o=x(()=>r.url?r.url.replace(/^https?:\/\//,""):"");function i(){if(!(!r.url||!n.value))try{n.value.getContext("2d").clearRect(0,0,n.value.width,n.value.height),Go.toCanvas(n.value,r.url,{scale:6,margin:0,color:{dark:"#000000",light:"#FFFFFF"}}),n.value.removeAttribute("style")}catch(l){console.error("QR code generation failed:",l)}}async function a(){if(r.url)try{await navigator.clipboard.writeText(r.url),t("copied")}catch(l){console.error("Failed to copy link:",l)}}return He(()=>r.url,()=>{i()},{immediate:!0}),He(n,()=>{n.value&&r.url&&i()},{immediate:!0}),(l,u)=>(T(),R("div",Wo,[v("div",Zo,[v("a",{href:e.url,onClick:de(a,["prevent"]),class:"qr-link",title:"Click to copy link",tabindex:"0",onKeydown:un(de(a,["prevent"]),["enter"])},[v("canvas",{ref_key:"qrCanvas",ref:n,class:"qr-code"},null,512),e.showLink&&e.url?(T(),R("div",er,D(o.value),1)):L("",!0)],40,Xo)])]))}},nr=Y(tr,[["__scopeId","data-v-727427c4"]]),or={class:"device-dialog",role:"dialog","aria-modal":"true","aria-labelledby":"regTitle"},rr={class:"reg-header-row"},sr={id:"regTitle",class:"reg-title"},ir={key:0},ar={key:1},lr={class:"device-link-section"},ur={key:0,class:"expiry-note"},cr={__name:"RegistrationLinkModal",props:{endpoint:{type:String,required:!0},userName:{type:String,default:""}},emits:["close","copied"],setup(e,{emit:s}){const r=e,t=s,n=F(null),o=F(null),i=F(null),a=F(null),l=F(null);async function u(){try{const d=await Q(r.endpoint,{method:"POST"});if(d.url){if(o.value=d.url,i.value=d.expires?new Date(d.expires):null,await ze(),n.value){n.value.showModal();const g=a.value;(g?.querySelector(".btn-primary")||g?.querySelector("button"))?.focus()}}else t("close")}catch{t("close")}}function f(){t("copied")}const w=d=>{const g=z(d)},b=d=>{const g=z(d);g&&(d.preventDefault(),(g==="down"||g==="up")&&a.value?.querySelector("button")?.focus())},h=d=>{const g=z(d);g&&(d.preventDefault(),(g==="up"||g==="down")&&document.querySelector(".qr-link")?.focus())};return qt(()=>{l.value=document.activeElement,u()}),Ft(()=>{const d=l.value;d&&document.body.contains(d)&&!d.disabled&&d.focus()}),(d,g)=>(T(),R("dialog",{ref_key:"dialog",ref:n,onClose:g[2]||(g[2]=N=>d.$emit("close")),onKeydown:w},[v("div",or,[v("div",rr,[v("h2",sr,[g[3]||(g[3]=xe(" 📱 ",-1)),e.userName?(T(),R("span",ir,"Registration for "+D(e.userName),1)):(T(),R("span",ar,"Add Another Device"))]),v("button",{class:"icon-btn",onClick:g[0]||(g[0]=N=>d.$emit("close")),"aria-label":"Close",tabindex:"-1"},"✕")]),v("div",lr,[g[4]||(g[4]=v("p",{class:"reg-help"}," Scan this QR code on the new device, or copy the link and open it there. ",-1)),cn(nr,{url:o.value,"show-link":!0,onCopied:f,onKeydown:b},null,8,["url"]),i.value?(T(),R("p",ur," This link expires "+D(U(G)(i.value).toLowerCase())+". ",1)):L("",!0)]),v("div",{class:"reg-actions",ref_key:"actionsRow",ref:a,onKeydown:h},[v("button",{class:"btn-secondary",onClick:g[1]||(g[1]=N=>d.$emit("close"))},"Close")],544)])],544))}},Ar=Y(cr,[["__scopeId","data-v-e04dd463"]]),dr={class:"loading-container"},fr={__name:"LoadingView",props:{message:{type:String,default:"Loading..."}},setup(e){return(s,r)=>(T(),R("div",dr,[r[0]||(r[0]=v("div",{class:"loading-spinner"},null,-1)),v("p",null,D(e.message),1)]))}},Rr=Y(fr,[["__scopeId","data-v-130f5abf"]]),hr={class:"message-container"},gr={class:"message-content"},mr={key:0,class:"error-detail"},yr={class:"button-row"},pr={__name:"AccessDenied",props:{title:{type:String,default:"Access Denied"},icon:{type:String,default:"🔒"},message:{type:String,default:null}},setup(e){function s(){window.location.reload()}return(r,t)=>(T(),R("div",hr,[v("div",gr,[v("h2",null,D(e.icon)+" "+D(e.title),1),e.message?(T(),R("p",mr,D(e.message),1)):L("",!0),v("div",yr,[v("button",{class:"btn-secondary",onClick:t[0]||(t[0]=(...n)=>U(We)&&U(We)(...n))},"Back"),v("button",{class:"btn-primary",onClick:s},"Reload Page")])])]))}},Tr=Y(pr,[["__scopeId","data-v-a7b258e7"]]);export{Tr as A,Sr as B,Rr as L,kr as M,Br as N,Ar as R,_r as U,Er as _,Ir as a,Cr as b,vr as c,$e as u};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{--font-sans: "Inter", "Inter var", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", sans-serif;--font-mono: "DM Mono", "JetBrains Mono", "SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", monospace;--color-canvas: #ffffff;--color-surface: #eff6ff;--color-surface-subtle: #dbeafe;--color-border: #2563eb;--color-border-strong: #1e40af;--color-heading: #1e3a8a;--color-text: #1e293b;--color-text-muted: #475569;--color-link: #1d4ed8;--color-link-hover: #1e40af;--color-accent: #2563eb;--color-accent-strong: #1e40af;--color-accent-contrast: #ffffff;--color-success-text: #166534;--color-success-bg: #dcfce7;--color-error-text: #b91c1c;--color-error-bg: #fee2e2;--color-info-text: #1e40af;--color-info-bg: #dbeafe;--color-danger: #dc2626;--shadow-soft: 0 10px 30px rgba(30, 64, 175, .15);--radius-none: 0;--radius-sm: 4px;--radius-md: 6px;--radius-lg: 10px;--space-xxs: .25rem;--space-xs: .5rem;--space-sm: .75rem;--space-md: 1rem;--space-lg: 1.5rem;--space-xl: 2.25rem;--space-xxl: 3.5rem;--layout-padding: clamp(1.5rem, 3vw + 1rem, 3.25rem);--transition-base: .16s ease;--focus-ring: 0 0 0 2px var(--color-accent)}@media(prefers-color-scheme:dark){:root{--color-canvas: #0f172a;--color-surface: #141b2f;--color-surface-subtle: #1b243b;--color-border: #25304a;--color-border-strong: #3d4d6b;--color-heading: #fff;--color-text: #e2e8f0;--color-text-muted: #94a3b8;--color-link: #60a5fa;--color-link-hover: #93c5fd;--color-accent: #60a5fa;--color-accent-strong: #3b82f6;--color-accent-contrast: #0b1120;--color-success-text: #34d399;--color-success-bg: #1a4d2e;--color-error-text: #fca5a5;--color-error-bg: #4a1f1f;--color-info-text: #bae6fd;--color-info-bg: #1e3a5f;--color-danger: #f87171;--shadow-soft: 0 0 0 #000000}}*,*:before,*:after{box-sizing:border-box}html{overflow:clip;height:100%;background:var(--color-canvas)}body{color-scheme:light dark;overflow:auto;scrollbar-gutter:stable;height:100%;margin:0;font-family:var(--font-sans);background:none;color:var(--color-text);line-height:1.55;-webkit-font-smoothing:antialiased;text-align:justify;hyphens:auto;-webkit-hyphens:auto;-moz-hyphens:auto}body,#app,#admin-app{display:flex;flex-direction:column;min-height:100vh}#app,#admin-app{flex:1}a,a:visited{color:var(--color-link);text-decoration:none}a:hover,a:focus-visible{color:var(--color-link-hover)}.app-shell{flex:1;display:flex;flex-direction:column;min-height:100vh}.app-main{flex:1;display:flex;flex-direction:column}.view-root{flex:1;width:100%;display:flex;flex-direction:column;gap:2rem;padding:var(--layout-padding);box-sizing:border-box;margin:0 auto}.view-root--wide{width:min(100%,1200px)}.view-root--narrow{max-width:540px}.view-header{display:flex;flex-direction:column;gap:.75rem}.view-header h1{margin:0;font-weight:600;color:var(--color-heading)}.view-lede{margin:0;color:var(--color-text-muted);font-size:1rem}.section-block{display:flex;flex-direction:column;gap:1rem}.section-block h2{margin:0;font-size:clamp(1.25rem,1.5vw + 1rem,1.65rem);font-weight:600;color:var(--color-heading)}.section-body{display:flex;flex-direction:column;gap:1rem}.section-description{margin:0;color:var(--color-text-muted)}.button-row{display:flex;flex-wrap:nowrap;gap:.75rem;justify-content:flex-start}.button-row button{min-width:0}.surface{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:var(--space-lg);box-shadow:var(--shadow-soft)}.surface--tight{padding:var(--space-md)}button{font-family:inherit;font-size:1rem;font-weight:500;border-radius:var(--radius-sm);border:1px solid transparent;padding:.65rem 1.1rem;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:.4rem;background:var(--color-surface);color:var(--color-text)}button:disabled{cursor:not-allowed;filter:opacity(.6)}.btn-primary{background:var(--color-accent);color:var(--color-accent-contrast);border-color:var(--color-accent);box-shadow:var(--shadow-soft)}.btn-primary:hover:not(:disabled){background:var(--color-accent-strong);border-color:var(--color-accent-strong)}.btn-secondary{background:transparent;color:var(--color-text);border-color:var(--color-border)}.btn-secondary:hover:not(:disabled){border-color:var(--color-border-strong);background:var(--color-surface-subtle)}.btn-danger{background:var(--color-danger);color:var(--color-accent-contrast);border-color:transparent}.btn-danger:hover:not(:disabled){filter:brightness(.92)}.btn-primary:focus-visible,.btn-secondary:focus-visible,.btn-danger:focus-visible{outline:1px solid var(-webkit-focus-ring-color)}input[type=text],input[type=search],input[type=email],textarea,select{font:inherit;width:100%;padding:.65rem .75rem;border-radius:var(--radius-sm);border:1px solid var(--color-border);background:var(--color-surface);color:var(--color-text);transition:border-color var(--transition-base),box-shadow var(--transition-base)}label{display:flex;flex-direction:column;gap:.5rem;color:var(--color-text)}p{margin:0;color:var(--color-text)}small{color:var(--color-text-muted)}.table-wrapper{overflow-x:auto;background:var(--color-surface);border:1px solid var(--color-border)}table{width:100%;border-collapse:collapse;font-size:.95rem}thead tr{background:var(--color-surface-subtle);color:var(--color-text-muted)}td,th{padding:.65rem .75rem;border-bottom:1px solid var(--color-border);text-align:left}.center{text-align:center}.badge{display:inline-flex;align-items:center;gap:.35rem;padding:.2rem .6rem;border-radius:var(--radius-sm);background:var(--color-surface-subtle);border:1px solid var(--color-border);color:var(--color-text-muted);font-size:.75rem}.global-status{position:fixed;top:1.5rem;left:0;right:0;margin:0 auto;z-index:1200;width:fit-content;min-width:min(520px,calc(100% - 2rem));max-width:calc(100% - 2rem);display:none}.global-status .status{display:flex;align-items:center;justify-content:center;padding:.85rem 1.25rem;border-radius:var(--radius-sm);border-width:1px;border-style:solid;background:var(--color-surface);box-shadow:var(--shadow-soft);font-weight:550}.status.info{border-color:#3b82f6;color:var(--color-info-text);background:var(--color-info-bg)}.status.success{border-color:#16a34a;color:var(--color-success-text);background:var(--color-success-bg)}.status.error{border-color:#dc2626;color:var(--color-error-text);background:var(--color-error-bg)}.dialog-overlay{position:fixed;inset:0;background:transparent;z-index:1100;display:flex;align-items:center;justify-content:center;padding:1.5rem}.device-dialog,.modal{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);width:min(520px,100%);max-height:calc(100vh - 3rem);overflow-y:auto;padding:1.75rem;box-shadow:var(--shadow-soft);color:var(--color-text)}.qr-container{display:flex;flex-direction:column;align-items:center;gap:.75rem;text-align:center;color:var(--color-text-muted)}.qr-code{padding:1rem;background:#fff;box-shadow:var(--shadow-soft)}.link-container,.token-display,.token-info{background:var(--color-surface-subtle);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:.75rem;color:var(--color-text)}:root{--card-width: 16rem}.record-list,.credential-list,.session-list{width:100%;display:grid;grid-auto-flow:row;grid-template-columns:repeat(auto-fill,minmax(var(--card-width),1fr));justify-content:start;gap:.5rem;align-items:stretch;margin:0 auto;outline:none}@media(max-width:720px){.record-list{display:flex;flex-direction:column;max-width:100%}}.record-item,.credential-item,.session-item{display:flex;flex-direction:column;padding:.5rem;border-radius:var(--radius-md);background:var(--color-surface);height:100%;transition:border-color .2s ease,box-shadow .2s ease,transform .2s ease;position:relative;cursor:pointer}.record-item:hover,.credential-item:hover,.session-item:hover{border-color:var(--color-border-strong);box-shadow:0 10px 24px #0f172a1f;transform:translateY(-1px)}.record-item.is-current,.credential-item.current-session,.credential-item.is-hovered,.session-item.is-current,.session-item.is-hovered,.credential-item.is-linked-session,.session-item.is-linked-credential{border-color:var(--color-accent);background-color:var(--color-surface-subtle)}.credential-item:focus,.session-item:focus{outline:1px solid var(-webkit-focus-ring-color)}.item-top{display:flex;align-items:center;height:2.5rem}.item-icon{width:40px;height:40px;display:grid;place-items:center;flex-shrink:0}.auth-icon{border-radius:var(--radius-sm)}.icon{flex:0 0 auto;font-size:1.5em;width:40px}.item-title{flex:1;margin:0;font-size:1rem;font-weight:600;color:var(--color-heading);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-actions{flex-shrink:0;display:flex;align-items:center}.item-actions .badge+.btn-card-delete{margin-left:.25rem}.item-actions .badge+.badge{margin-left:.25rem}.item-details{margin-left:40px}.credential-dates,.session-dates{display:grid;grid-auto-flow:row;grid-template-columns:8em 1fr;font-size:.75rem;align-items:center}.date-label{font-weight:500;color:var(--color-text-muted);overflow:hidden;text-overflow:ellipsis}.date-value{color:var(--color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.btn-card-delete{background:transparent;border:none;color:var(--color-danger);padding:.35rem .5rem;font-size:1.05rem;line-height:1;border-radius:var(--radius-sm);cursor:pointer;display:inline-flex;align-items:center;justify-content:center}.btn-card-delete:hover:not(:disabled){background:#fee}.btn-card-delete:disabled{filter:opacity(.4);cursor:not-allowed}.session-emoji{font-size:1.2rem}.session-group{position:relative}.session-group:focus-visible{outline:1px solid var(-webkit-focus-ring-color)}.session-group-host{display:flex;align-items:center;font-size:1.5rem;font-weight:600;margin:.5rem 0}.session-group-icon{margin-left:-1.5rem}.session-group-host a{color:var(--color-text);text-decoration:none}.session-group:focus-visible .session-group-host,.session-group:focus-visible .session-group-host a{color:var(--color-heading)}.btn-card-delete{display:none}.session-item:focus .btn-card-delete{display:block}.badge{padding:.2rem .5rem;border-radius:var(--radius-sm);font-size:.8rem;font-weight:500;white-space:nowrap}.badge-current{background:var(--color-accent);color:var(--color-accent-contrast);box-shadow:0 0 0 1px var(--color-accent) inset}.badge:not(.badge-current){background:var(--color-surface-subtle);color:var(--color-text-muted);border:1px solid var(--color-border)}.session-meta-info{font-size:.75rem;color:var(--color-text-muted);font-family:monospace}.empty-state{text-align:center;padding:var(--space-lg);color:var(--color-text-muted)}.empty-state p{margin:0}.user-info{display:grid;border-radius:var(--radius-md);background:var(--color-surface);padding:1.1rem 1.25rem}.user-details{display:grid;grid-template-columns:7em 1fr;gap:0 .5rem;padding-left:40px;font-size:.75rem}.toggle-link{color:var(--color-link);cursor:pointer}.toggle-link:hover{color:var(--color-link-hover)}.token-info code{font-family:var(--font-mono)}@media(max-width:720px){.view-root{padding:clamp(1rem,3vw + .75rem,2rem);gap:1.75rem}.global-status{top:1rem}}.dialog-backdrop{position:fixed;top:0;left:0;width:100vw;height:100vh;background:transparent;backdrop-filter:blur(.1rem) brightness(.7);-webkit-backdrop-filter:blur(.1rem) brightness(.7);display:flex;align-items:center;justify-content:center;z-index:1000}.dialog-container{max-width:90vw;max-height:90vh;overflow-y:auto}.dialog-content{flex:none;width:100%;max-width:480px;padding:2rem;background:var(--color-surface);border-radius:var(--radius-lg);box-shadow:0 20px 60px #1e293b;border:1px solid var(--color-border)}.dialog-content--wide{max-width:540px}.dialog-content--narrow{max-width:420px}@media(max-width:720px){.dialog-content{padding:1.5rem}}body:before{content:"";position:fixed;inset:0;z-index:1099;background:transparent;backdrop-filter:blur(0) brightness(1);-webkit-backdrop-filter:blur(0) brightness(1);pointer-events:none;visibility:hidden;transition:all .2s ease-out}body.has-backdrop:before{-webkit-backdrop-filter:blur(.2rem) brightness(.5);backdrop-filter:blur(.2rem) brightness(.5);visibility:visible}body.has-backdrop{overflow:auto}#auth-iframe{border:none;position:fixed;top:0;left:0;width:100%;height:100%;z-index:9999;color-scheme:auto;background:transparent}.slot-machine{padding:.875rem 1rem;background:var(--color-surface-hover, rgba(0, 0, 0, .03));border:1px solid var(--color-border);border-radius:var(--radius-sm);font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;display:flex;align-items:center;-webkit-user-select:none;user-select:none;pointer-events:none;white-space:nowrap;overflow:hidden}.slot-reel{display:inline-flex;align-items:center;justify-content:center;flex:1;min-width:0;height:1.8em;position:relative}
|