paskia 0.9.1__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.
Files changed (46) hide show
  1. paskia/_version.py +2 -2
  2. paskia/db/jsonl.py +2 -2
  3. paskia/db/logging.py +130 -45
  4. paskia/db/operations.py +8 -4
  5. paskia/fastapi/__main__.py +12 -6
  6. paskia/fastapi/admin.py +2 -2
  7. paskia/fastapi/api.py +7 -3
  8. paskia/fastapi/authz.py +3 -8
  9. paskia/fastapi/logging.py +64 -21
  10. paskia/fastapi/mainapp.py +2 -1
  11. paskia/fastapi/remote.py +11 -37
  12. paskia/fastapi/ws.py +12 -35
  13. paskia/fastapi/wschat.py +55 -2
  14. paskia/fastapi/wsutil.py +2 -7
  15. paskia/frontend-build/auth/admin/index.html +6 -6
  16. paskia/frontend-build/auth/assets/AccessDenied-C29NZI95.css +1 -0
  17. paskia/frontend-build/auth/assets/AccessDenied-DAdzg_MJ.js +12 -0
  18. paskia/frontend-build/auth/assets/{RestrictedAuth-CvR33_Z0.css → RestrictedAuth-BOdNrlQB.css} +1 -1
  19. paskia/frontend-build/auth/assets/{RestrictedAuth-DsJXicIw.js → RestrictedAuth-BSusdAfp.js} +1 -1
  20. paskia/frontend-build/auth/assets/_plugin-vue_export-helper-D2l53SUz.js +49 -0
  21. paskia/frontend-build/auth/assets/_plugin-vue_export-helper-DYJ24FZK.css +1 -0
  22. paskia/frontend-build/auth/assets/admin-BeFvGyD6.js +1 -0
  23. paskia/frontend-build/auth/assets/{admin-DzzjSg72.css → admin-CmNtuH3s.css} +1 -1
  24. paskia/frontend-build/auth/assets/{auth-C7k64Wad.css → auth-BKq4T2K2.css} +1 -1
  25. paskia/frontend-build/auth/assets/auth-DvHf8hgy.js +1 -0
  26. paskia/frontend-build/auth/assets/{forward-DmqVHZ7e.js → forward-C86Jm_Uq.js} +1 -1
  27. paskia/frontend-build/auth/assets/reset-B8PlNXuP.css +1 -0
  28. paskia/frontend-build/auth/assets/reset-D71FG0VL.js +1 -0
  29. paskia/frontend-build/auth/assets/{restricted-D3AJx3_6.js → restricted-CW0drE_k.js} +1 -1
  30. paskia/frontend-build/auth/index.html +6 -6
  31. paskia/frontend-build/auth/restricted/index.html +5 -5
  32. paskia/frontend-build/int/forward/index.html +5 -5
  33. paskia/frontend-build/int/reset/index.html +4 -4
  34. {paskia-0.9.1.dist-info → paskia-0.10.0.dist-info}/METADATA +1 -1
  35. paskia-0.10.0.dist-info/RECORD +60 -0
  36. paskia/frontend-build/auth/assets/AccessDenied-DPkUS8LZ.css +0 -1
  37. paskia/frontend-build/auth/assets/AccessDenied-Fmeb6EtF.js +0 -8
  38. paskia/frontend-build/auth/assets/_plugin-vue_export-helper-BTzJAQlS.css +0 -1
  39. paskia/frontend-build/auth/assets/_plugin-vue_export-helper-nhjnO_bd.js +0 -2
  40. paskia/frontend-build/auth/assets/admin-CPE1pLMm.js +0 -1
  41. paskia/frontend-build/auth/assets/auth-YIZvPlW_.js +0 -1
  42. paskia/frontend-build/auth/assets/reset-Chtv69AT.css +0 -1
  43. paskia/frontend-build/auth/assets/reset-s20PATTN.js +0 -1
  44. paskia-0.9.1.dist-info/RECORD +0 -60
  45. {paskia-0.9.1.dist-info → paskia-0.10.0.dist-info}/WHEEL +0 -0
  46. {paskia-0.9.1.dist-info → paskia-0.10.0.dist-info}/entry_points.txt +0 -0
paskia/fastapi/remote.py CHANGED
@@ -17,10 +17,10 @@ from fastapi import FastAPI, WebSocket, WebSocketDisconnect
17
17
 
18
18
  from paskia import db, remoteauth
19
19
  from paskia.authsession import expires
20
- from paskia.fastapi.session import infodict
21
- from paskia.fastapi.wschat import authenticate_chat
20
+ from paskia.fastapi.session import AUTH_COOKIE, infodict
21
+ from paskia.fastapi.wschat import authenticate_and_login
22
22
  from paskia.fastapi.wsutil import validate_origin, websocket_error_handler
23
- from paskia.util import hostutil, passphrase, pow, useragent
23
+ from paskia.util import passphrase, pow, useragent
24
24
 
25
25
  # Create a FastAPI subapp for remote auth WebSocket endpoints
26
26
  app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
@@ -252,7 +252,7 @@ async def websocket_remote_auth_request(ws: WebSocket):
252
252
 
253
253
  @app.websocket("/permit")
254
254
  @websocket_error_handler
255
- async def websocket_remote_auth_permit(ws: WebSocket):
255
+ async def websocket_remote_auth_permit(ws: WebSocket, auth=AUTH_COOKIE):
256
256
  """Complete a remote authentication request using a 3-word pairing code.
257
257
 
258
258
  This endpoint is called from the user's profile on the authenticating device.
@@ -270,7 +270,7 @@ async def websocket_remote_auth_permit(ws: WebSocket):
270
270
  7. Server sends {status: "success", message: "..."}
271
271
  """
272
272
 
273
- origin = validate_origin(ws)
273
+ validate_origin(ws)
274
274
 
275
275
  if remoteauth.instance is None:
276
276
  raise ValueError("Remote authentication is not available")
@@ -310,56 +310,30 @@ async def websocket_remote_auth_permit(ws: WebSocket):
310
310
 
311
311
  # Handle authenticate request (no PoW needed - already validated during lookup)
312
312
  if msg.get("authenticate") and request is not None:
313
- cred, new_sign_count = await authenticate_chat(ws, origin)
314
-
315
- # Create a session for the REQUESTING device
316
- assert cred.uuid is not None
313
+ ctx = await authenticate_and_login(ws, auth)
317
314
 
318
- session_token = None
315
+ session_token = ctx.session.key
319
316
  reset_token = None
320
317
 
321
318
  if request.action == "register":
322
319
  # For registration, create a reset token for device addition
323
-
324
320
  token_str = passphrase.generate()
325
321
  expiry = expires()
326
322
  db.create_reset_token(
327
- user_uuid=cred.user_uuid,
323
+ user_uuid=ctx.user.uuid,
328
324
  passphrase=token_str,
329
325
  expiry=expiry,
330
326
  token_type="device addition",
327
+ user=str(ctx.user.uuid),
331
328
  )
332
329
  reset_token = token_str
333
- # Also create a session so the device is logged in
334
- normalized_host = hostutil.normalize_host(request.host)
335
- session_token = db.login(
336
- user_uuid=cred.user_uuid,
337
- credential_uuid=cred.uuid,
338
- sign_count=new_sign_count,
339
- host=normalized_host,
340
- ip=request.ip,
341
- user_agent=request.user_agent,
342
- expiry=expires(),
343
- )
344
- else:
345
- # Default login action
346
-
347
- normalized_host = hostutil.normalize_host(request.host)
348
- session_token = db.login(
349
- user_uuid=cred.user_uuid,
350
- credential_uuid=cred.uuid,
351
- sign_count=new_sign_count,
352
- host=normalized_host,
353
- ip=request.ip,
354
- user_agent=request.user_agent,
355
- expiry=expires(),
356
- )
357
330
 
358
331
  # Complete the remote auth request (notifies the waiting device)
332
+ cred = db.data().credentials[ctx.session.credential_uuid]
359
333
  completed = await remoteauth.instance.complete_request(
360
334
  token=request.key,
361
335
  session_token=session_token,
362
- user_uuid=cred.user_uuid,
336
+ user_uuid=ctx.user.uuid,
363
337
  credential_uuid=cred.uuid,
364
338
  reset_token=reset_token,
365
339
  )
paskia/fastapi/ws.py CHANGED
@@ -1,13 +1,13 @@
1
1
  from fastapi import FastAPI, WebSocket
2
2
 
3
3
  from paskia import db
4
- from paskia.authsession import expires, get_reset
4
+ from paskia.authsession import get_reset
5
5
  from paskia.fastapi import authz, remote
6
6
  from paskia.fastapi.session import AUTH_COOKIE, infodict
7
- from paskia.fastapi.wschat import authenticate_chat, register_chat
7
+ from paskia.fastapi.wschat import authenticate_and_login, register_chat
8
8
  from paskia.fastapi.wsutil import validate_origin, websocket_error_handler
9
9
  from paskia.globals import passkey
10
- from paskia.util import hostutil, passphrase
10
+ from paskia.util import passphrase
11
11
 
12
12
  # Create a FastAPI subapp for WebSocket endpoints
13
13
  app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
@@ -46,7 +46,7 @@ async def websocket_register_add(
46
46
  s = ctx.session
47
47
 
48
48
  # Get user information and determine effective user_name for this registration
49
- user = db.data().users.get(user_uuid)
49
+ user = db.data().users[user_uuid]
50
50
  user_name = user.display_name
51
51
  if name is not None:
52
52
  stripped = name.strip()
@@ -59,7 +59,7 @@ async def websocket_register_add(
59
59
 
60
60
  # Create a new session and store everything in database
61
61
  metadata = infodict(ws, "authenticated")
62
- token = db.create_credential_session( # type: ignore[attr-defined]
62
+ token = db.create_credential_session(
63
63
  user_uuid=user_uuid,
64
64
  credential=credential,
65
65
  reset_key=(s.key if reset is not None else None),
@@ -89,43 +89,20 @@ async def websocket_authenticate(ws: WebSocket, auth=AUTH_COOKIE):
89
89
 
90
90
  # If there's an existing session, restrict to that user's credentials (reauth)
91
91
  session_user_uuid = None
92
- credential_ids = None
93
92
  if auth:
94
- ctx = db.data().session_ctx(auth, host)
95
- if ctx:
96
- session_user_uuid = ctx.user.uuid
97
- credential_ids = db.get_user_credential_ids(session_user_uuid) or None
93
+ existing_ctx = db.data().session_ctx(auth, host)
94
+ if existing_ctx:
95
+ session_user_uuid = existing_ctx.user.uuid
98
96
 
99
- cred, new_sign_count = await authenticate_chat(ws, origin, credential_ids)
97
+ ctx = await authenticate_and_login(ws, auth)
100
98
 
101
99
  # If reauth mode, verify the credential belongs to the session's user
102
- if session_user_uuid and cred.user_uuid != session_user_uuid:
100
+ if session_user_uuid and ctx.user.uuid != session_user_uuid:
103
101
  raise ValueError("This passkey belongs to a different account")
104
102
 
105
- # Create session and update user/credential in a single transaction
106
- assert cred.uuid is not None
107
- metadata = infodict(ws, "auth")
108
- normalized_host = hostutil.normalize_host(host)
109
- if not normalized_host:
110
- raise ValueError("Host required for session creation")
111
- hostname = normalized_host.split(":")[0]
112
- rp_id = passkey.instance.rp_id
113
- if not (hostname == rp_id or hostname.endswith(f".{rp_id}")):
114
- raise ValueError(f"Host must be the same as or a subdomain of {rp_id}")
115
-
116
- token = db.login(
117
- user_uuid=cred.user_uuid,
118
- credential_uuid=cred.uuid,
119
- sign_count=new_sign_count,
120
- host=normalized_host,
121
- ip=metadata["ip"],
122
- user_agent=metadata["user_agent"],
123
- expiry=expires(),
124
- )
125
-
126
103
  await ws.send_json(
127
104
  {
128
- "user": str(cred.user_uuid),
129
- "session_token": token,
105
+ "user": str(ctx.user.uuid),
106
+ "session_token": ctx.session.key,
130
107
  }
131
108
  )
paskia/fastapi/wschat.py CHANGED
@@ -7,8 +7,12 @@ from uuid import UUID
7
7
  from fastapi import WebSocket
8
8
 
9
9
  from paskia import db
10
- from paskia.db import Credential
10
+ from paskia.authsession import expires
11
+ from paskia.db import Credential, SessionContext
12
+ from paskia.fastapi.session import infodict
13
+ from paskia.fastapi.wsutil import validate_origin
11
14
  from paskia.globals import passkey
15
+ from paskia.util import hostutil
12
16
 
13
17
 
14
18
  async def register_chat(
@@ -31,7 +35,6 @@ async def register_chat(
31
35
 
32
36
  async def authenticate_chat(
33
37
  ws: WebSocket,
34
- origin: str,
35
38
  credential_ids: list[bytes] | None = None,
36
39
  ) -> tuple[Credential, int]:
37
40
  """Run WebAuthn authentication flow and return the credential and new sign count.
@@ -39,6 +42,7 @@ async def authenticate_chat(
39
42
  Returns:
40
43
  tuple of (credential, new_sign_count) where new_sign_count comes from WebAuthn verification
41
44
  """
45
+ origin = validate_origin(ws)
42
46
  options, challenge = passkey.instance.auth_generate_options(
43
47
  credential_ids=credential_ids
44
48
  )
@@ -60,3 +64,52 @@ async def authenticate_chat(
60
64
 
61
65
  verification = passkey.instance.auth_verify(authcred, challenge, cred, origin)
62
66
  return cred, verification.new_sign_count
67
+
68
+
69
+ async def authenticate_and_login(
70
+ ws: WebSocket,
71
+ auth: str | None = None,
72
+ ) -> SessionContext:
73
+ """Run WebAuthn authentication flow, create session, and return the session context.
74
+
75
+ If auth is provided, restrict authentication to credentials of that session's user.
76
+
77
+ Returns:
78
+ SessionContext for the authenticated session
79
+ """
80
+ origin = validate_origin(ws)
81
+ host = origin.split("://", 1)[1]
82
+ normalized_host = hostutil.normalize_host(host)
83
+ if not normalized_host:
84
+ raise ValueError("Host required for session creation")
85
+ hostname = normalized_host.split(":")[0]
86
+ rp_id = passkey.instance.rp_id
87
+ if not (hostname == rp_id or hostname.endswith(f".{rp_id}")):
88
+ raise ValueError(f"Host must be the same as or a subdomain of {rp_id}")
89
+ metadata = infodict(ws, "auth")
90
+
91
+ # Get credential IDs if restricting to a user's credentials
92
+ credential_ids = None
93
+ if auth:
94
+ existing_ctx = db.data().session_ctx(auth, host)
95
+ if existing_ctx:
96
+ credential_ids = db.get_user_credential_ids(existing_ctx.user.uuid) or None
97
+
98
+ cred, new_sign_count = await authenticate_chat(ws, credential_ids)
99
+
100
+ # Create session and update user/credential
101
+ token = db.login(
102
+ user_uuid=cred.user_uuid,
103
+ credential_uuid=cred.uuid,
104
+ sign_count=new_sign_count,
105
+ host=normalized_host,
106
+ ip=metadata["ip"],
107
+ user_agent=metadata["user_agent"],
108
+ expiry=expires(),
109
+ )
110
+
111
+ # Fetch and return the full session context
112
+ ctx = db.data().session_ctx(token, normalized_host)
113
+ if not ctx:
114
+ raise ValueError("Failed to create session context")
115
+ return ctx
paskia/fastapi/wsutil.py CHANGED
@@ -21,12 +21,8 @@ def websocket_error_handler(func):
21
21
 
22
22
  @wraps(func)
23
23
  async def wrapper(ws: WebSocket, *args, **kwargs):
24
- client = ws.client.host if ws.client else "-"
25
- host = ws.headers.get("host", "-")
26
- path = ws.url.path
27
-
28
24
  start = time.perf_counter()
29
- ws_id = log_ws_open(client, host, path)
25
+ ws_id = log_ws_open(ws)
30
26
  close_code = None
31
27
 
32
28
  try:
@@ -47,8 +43,7 @@ def websocket_error_handler(func):
47
43
  logging.exception("Internal Server Error")
48
44
  await ws.send_json({"status": 500, "detail": "Internal Server Error"})
49
45
  finally:
50
- duration_ms = (time.perf_counter() - start) * 1000
51
- log_ws_close(client, ws_id, close_code, duration_ms)
46
+ log_ws_close(ws_id, close_code, time.perf_counter() - start)
52
47
 
53
48
  return wrapper
54
49
 
@@ -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>Admin</title>
7
- <script type="module" crossorigin src="/auth/assets/admin-CPE1pLMm.js"></script>
8
- <link rel="modulepreload" crossorigin href="/auth/assets/_plugin-vue_export-helper-nhjnO_bd.js">
7
+ <script type="module" crossorigin src="/auth/assets/admin-BeFvGyD6.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-Fmeb6EtF.js">
11
- <link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-BTzJAQlS.css">
12
- <link rel="stylesheet" crossorigin href="/auth/assets/AccessDenied-DPkUS8LZ.css">
13
- <link rel="stylesheet" crossorigin href="/auth/assets/admin-DzzjSg72.css">
10
+ <link rel="modulepreload" crossorigin href="/auth/assets/AccessDenied-DAdzg_MJ.js">
11
+ <link rel="stylesheet" crossorigin href="/auth/assets/_plugin-vue_export-helper-DYJ24FZK.css">
12
+ <link rel="stylesheet" crossorigin href="/auth/assets/AccessDenied-C29NZI95.css">
13
+ <link rel="stylesheet" crossorigin href="/auth/assets/admin-CmNtuH3s.css">
14
14
  </head>
15
15
  <body>
16
16
  <div id="admin-app"></div>
@@ -0,0 +1 @@
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-26360b56]{border:none;background:transparent;padding:0;max-width:none;width:fit-content;height:fit-content;position:fixed;inset:0;margin:auto}dialog[data-v-26360b56]::backdrop{-webkit-backdrop-filter:blur(.2rem) brightness(.5);backdrop-filter:blur(.2rem) brightness(.5)}.icon-btn[data-v-26360b56]{background:none;border:none;cursor:pointer;font-size:1rem;opacity:.6}.icon-btn[data-v-26360b56]:hover{opacity:1}.reg-header-row[data-v-26360b56]{display:flex;justify-content:space-between;align-items:center;gap:.75rem;margin-bottom:.75rem}.reg-title[data-v-26360b56]{margin:0;font-size:1.25rem;font-weight:600}.device-dialog[data-v-26360b56]{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-26360b56]{margin:.5rem 0 .75rem;font-size:.85rem;line-height:1.4;text-align:center;color:var(--color-text-muted)}.reg-actions[data-v-26360b56]{display:flex;justify-content:flex-end;gap:.5rem;margin-top:1rem}.expiry-note[data-v-26360b56]{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}
@@ -0,0 +1,12 @@
1
+ import{M as At,r as q,P as Rt,Q as Yt,R as ue,S as Tt,T as Qt,U as Gt,V as Wt,n as xe,W as Zt,c as x,w as He,X as Xt,Y as en,H as Q,m as tn,Z as nn,$ as on,b as T,f as L,z as F,d as M,e as v,t as D,g as se,_ as Y,F as oe,i as ce,B as j,D as Mt,l as de,a0 as Nt,a1 as Pt,a2 as Dt,a3 as Lt,o as $t,a4 as rn,a as qt,C as sn,k as ze,h as an,a5 as ln,L as un,x as cn}from"./_plugin-vue_export-helper-D2l53SUz.js";import{f as G,h as ae,g as We}from"./helpers-DzjFIx78.js";/*!
2
+ * pinia v3.0.3
3
+ * (c) 2025 Eduardo San Martin Morote
4
+ * @license MIT
5
+ */let Ft;const fe=e=>Ft=e,Ut=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(()=>q({}));let r=[],t=[];const n=Rt({install(o){fe(n),n._a=o,o.provide(Ut,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 Kt=()=>{};function Ze(e,s,r,t=Kt){e.push(s);const n=()=>{const o=e.indexOf(s);o>-1&&(e.splice(o,1),t())};return!r&&Gt()&&Wt(n),n}function ee(e,...s){e.slice().forEach(r=>{r(...s)})}const dn=e=>e(),Xe=Symbol(),we=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,l=r.state.value[e];let a;function u(){l||(r.state.value[e]=n?n():{});const d=Zt(r.state.value[e]);return J(d,o,Object.keys(i||{}).reduce((p,b)=>(p[b]=Rt(x(()=>{fe(r);const f=r._s.get(e);return i[b].call(f,f)})),p),{}))}return a=Vt(e,u,s,r,t,!0),a}function Vt(e,s,r={},t,n,o){let i;const l=J({actions:{}},r),a={deep:!0};let u,d,p=[],b=[],f;const w=t.state.value[e];!o&&!w&&(t.state.value[e]={}),q({});let h;function _(m){let g;u=d=!1,typeof m=="function"?(m(t.state.value[e]),g={type:re.patchFunction,storeId:e,events:f}):(je(t.state.value[e],m),g={type:re.patchObject,payload:m,storeId:e,events:f});const E=h=Symbol();xe().then(()=>{h===E&&(u=!0)}),d=!0,ee(p,g,t.state.value[e])}const A=o?function(){const{state:g}=r,E=g?g():{};this.$patch(k=>{J(k,E)})}:Kt;function P(){i.stop(),p=[],b=[],t._s.delete(e)}const c=(m,g="")=>{if(Xe in m)return m[we]=g,m;const E=function(){fe(t);const k=Array.from(arguments),B=[],I=[];function N($){B.push($)}function K($){I.push($)}ee(b,{args:k,name:E[we],store:R,after:N,onError:K});let U;try{U=m.apply(this&&this.$id===e?this:R,k)}catch($){throw ee(I,$),$}return U instanceof Promise?U.then($=>(ee(B,$),$)).catch($=>(ee(I,$),Promise.reject($))):(ee(B,U),U)};return E[Xe]=!0,E[we]=g,E},S={_p:t,$id:e,$onAction:Ze.bind(null,b),$patch:_,$reset:A,$subscribe(m,g={}){const E=Ze(p,m,g.detached,()=>k()),k=i.run(()=>He(()=>t.state.value[e],B=>{(g.flush==="sync"?d:u)&&m({storeId:e,type:re.direct,events:f},B)},J({},a,g)));return E},$dispose:P},R=Yt(S);t._s.set(e,R);const y=(t._a&&t._a.runWithContext||dn)(()=>t._e.run(()=>(i=At()).run(()=>s({action:c}))));for(const m in y){const g=y[m];if(ue(g)&&!gn(g)||Tt(g))o||(w&&hn(g)&&(ue(g)?g.value=w[m]:je(g,w[m])),t.state.value[e][m]=g);else if(typeof g=="function"){const E=c(g,m);y[m]=E,l.actions[m]=g}}return J(R,y),J(Qt(R),y),Object.defineProperty(R,"$state",{get:()=>t.state.value[e],set:m=>{_(g=>{J(g,m)})}}),t._p.forEach(m=>{J(R,i.run(()=>m({store:R,app:t._a,pinia:t,options:l})))}),w&&o&&r.hydrate&&r.hydrate(R.$state,w),u=!0,d=!0,R}/*! #__NO_SIDE_EFFECTS__ */function yn(e,s,r){let t;const n=typeof s=="function";t=n?r:s;function o(i,l){const a=en();return i=i||(a?Xt(Ut,null):null),i&&fe(i),i=Ft,i._s.has(e)||(n?Vt(e,s,t,i):mn(e,t,i)),i._s.get(e)}return o.$id=e,o}const he=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=he();return(r,t)=>F(s).status.show?(M(),T("div",pn,[v("div",{class:se(["status",F(s).status.type])},D(F(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=q(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 d=n.value.length-1;d>=0;d--){const p=n.value[d].href;if(p===u||p&&u.startsWith(p))return d}return n.value.length-1});function i(u){if(u.target===t.value){const d=t.value.querySelectorAll("a"),p=Math.min(o.value,d.length-1);d[p]&&d[p].focus()}}function l(u){const d=j(u);d&&(d==="left"||d==="right")&&(u.preventDefault(),Mt(t.value,u.target,d,{itemSelector:"a"}))}function a(){const u=t.value?.querySelectorAll("a");if(u?.length){const d=Math.min(o.value,u.length-1);u[d]?.focus()}}return s({focusCurrent:a}),(u,d)=>n.value.length>1?(M(),T("nav",{key:0,ref_key:"navRef",ref:t,class:"breadcrumbs","aria-label":"Breadcrumb",tabindex:"0",onFocusin:i,onKeydown:l},[v("ol",null,[(M(!0),T(oe,null,ce(n.value,(p,b)=>(M(),T("li",{key:b},[v("a",{href:p.href,tabindex:"-1"},D(p.label),9,wn),b<n.value.length-1?(M(),T("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"},$n={class:"date-value"},qn={class:"date-value"},Fn={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=f=>{t("credentialHover",f)},o=f=>{f.currentTarget.contains(f.relatedTarget)||t("credentialHover",null)},i=f=>{f.currentTarget.matches(":focus")||(f.currentTarget.focus(),f.stopPropagation())},l=(f,w)=>{Pt(f,()=>{r.allowDelete&&!w.is_current_session&&t("delete",w)})},a=f=>{if(r.navigationDisabled)return;const w=f.currentTarget;if(f.target===w){const h=w.querySelector(".credential-item");h&&h.focus()}},u=f=>{r.navigationDisabled||Dt(f,w=>t("navigate-out",w))},d=(f,w)=>{if(l(f,w),f.defaultPrevented||r.navigationDisabled)return;const h=j(f);if(h){f.preventDefault();const _=f.currentTarget.closest(".credential-list");Nt(_,f.currentTarget,h,{itemSelector:".credential-item"})==="boundary"&&t("navigate-out",h)}},p=f=>{const w=r.aaguidInfo?.[f.aaguid];return w?w.name:"Unknown Authenticator"},b=f=>{const w=r.aaguidInfo?.[f.aaguid];if(!w)return null;const _=window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"icon_dark":"icon_light";return w[_]||null};return(f,w)=>(M(),T("div",{class:"credential-list",tabindex:"0",onFocusin:a,onKeydown:u},[e.loading?(M(),T("div",Cn,[...w[2]||(w[2]=[v("p",null,"Loading credentials...",-1)])])):e.credentials?.length?(M(!0),T(oe,{key:2},ce(e.credentials,h=>(M(),T("div",{key:h.credential,class:se(["credential-item",{"current-session":h.is_current_session&&!e.hoveredCredentialUuid&&!e.hoveredSessionCredentialUuid,"is-hovered":e.hoveredCredentialUuid===h.credential,"is-linked-session":e.hoveredSessionCredentialUuid===h.credential}]),tabindex:"-1",onMousedown:w[0]||(w[0]=de(()=>{},["prevent"])),onClickCapture:i,onFocusin:_=>n(h.credential),onFocusout:w[1]||(w[1]=_=>o(_)),onKeydown:_=>d(_,h)},[v("div",_n,[v("div",kn,[b(h)?(M(),T("img",{key:0,src:b(h),alt:p(h),class:"auth-icon",width:"32",height:"32"},null,8,Bn)):(M(),T("span",In,"🔑"))]),v("h4",An,D(p(h)),1),v("div",Rn,[h.is_current_session&&!e.hoveredCredentialUuid&&!e.hoveredSessionCredentialUuid?(M(),T("span",Tn,"Current")):e.hoveredCredentialUuid===h.credential?(M(),T("span",Mn,"Selected")):e.hoveredSessionCredentialUuid===h.credential?(M(),T("span",Nn,"Linked")):L("",!0),e.allowDelete?(M(),T("button",{key:3,onClick:_=>f.$emit("delete",h),class:"btn-card-delete",disabled:h.is_current_session,title:h.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,[w[4]||(w[4]=v("span",{class:"date-label"},"Created:",-1)),v("span",$n,D(F(G)(h.created_at)),1),w[5]||(w[5]=v("span",{class:"date-label"},"Last used:",-1)),v("span",qn,D(F(G)(h.last_used)),1),w[6]||(w[6]=v("span",{class:"date-label"},"Last verified:",-1)),v("span",Fn,D(F(G)(h.last_verified)),1)])])],42,En))),128)):(M(),T("div",Sn,[...w[3]||(w[3]=[v("p",null,"No passkeys found.",-1)])]))],32))}},Un={class:"user-name-heading"},Kn={class:"user-name-row"},Vn=["title"],Hn={key:0,class:"org-role-sub"},On={key:0,class:"org-line"},jn={key:1,class:"role-line"},xn={class:"user-details"},zn={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;he();const n=x(()=>!!r.name);return(o,i)=>n.value?(M(),T("div",{key:0,class:se(["user-info",{"has-extra":o.$slots.default}])},[v("h3",Un,[i[1]||(i[1]=v("span",{class:"icon"},"👤",-1)),v("span",Kn,[v("span",{class:"display-name",title:e.name},D(e.name),9,Vn),e.canEdit&&e.updateEndpoint?(M(),T("button",{key:0,class:"mini-btn",onClick:i[0]||(i[0]=l=>t("editName")),title:"Edit name"},"✏️")):L("",!0)])]),e.orgDisplayName||e.roleName?(M(),T("div",Hn,[e.orgDisplayName?(M(),T("div",On,D(e.orgDisplayName),1)):L("",!0),e.roleName?(M(),T("div",jn,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",zn,D(e.visits||0),1),i[3]||(i[3]=v("span",{class:"date-label"},[v("strong",null,"Registered:")],-1)),v("span",Jn,D(F(G)(e.createdAt)),1),i[4]||(i[4]=v("span",{class:"date-label"},[v("strong",null,"Last seen:")],-1)),v("span",Yn,D(F(G)(e.lastSeen)),1)]),o.$slots.default?(M(),T("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=q(null),t=q(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 a=[s.focusFallback?.$el||s.focusFallback,i.closest("[data-nav-group]"),i.parentElement?.closest("section"),document.querySelector(".view-root")].filter(Boolean);for(const u of a){if(!u)continue;const d=u.querySelectorAll(s.focusSiblingSelector);if(d.length>0){const p=Math.min(s.focusIndex,d.length-1),b=d[p];if(b&&!b.disabled){b.focus();return}}}}const l=s.focusFallback?.$el||s.focusFallback;if(l&&document.body.contains(l)){const a=l.querySelector?.('button:not([disabled]), a, [tabindex="0"]')||l;if(a?.focus){a.focus();return}}},o=i=>{const l=j(i);if(!l)return;const a=i.target,u=a.closest(".modal-actions");if(u&&(l==="left"||l==="right"))i.preventDefault(),Mt(u,a,l,{itemSelector:"button"});else if(l==="up"&&u){i.preventDefault();const p=(u.closest("form")||u.closest(".modal-form"))?.querySelectorAll("input, textarea, select, button:not(.modal-actions button)");p&&p.length>0&&p[p.length-1].focus()}else if(l==="down"&&!u){const d=a.closest("form")||a.closest(".modal-form");if(d){i.preventDefault();const p=d.querySelector(".modal-actions");p&&sn(p,{primarySelector:".btn-primary",itemSelector:"button"})}}};return $t(()=>{t.value=document.activeElement,xe(()=>{if(r.value){r.value.showModal();const i=r.value.querySelector(".modal-actions .btn-primary");i&&i.setAttribute("data-nav-primary",""),rn(r.value)}})}),qt(()=>{n()}),(i,l)=>(M(),T("dialog",{ref_key:"dialog",ref:r,onClose:l[0]||(l[0]=a=>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=q(null),o=`name-edit-${Math.random().toString(36).slice(2,10)}`,i=x({get:()=>r.modelValue,set:d=>t("update:modelValue",d)}),l=x(()=>r.inputId||o),a=d=>{if(j(d)==="up"){d.preventDefault(),n.value?.focus();return}};function u(){t("cancel")}return(d,p)=>(M(),T("div",Zn,[v("label",{for:l.value},[ze(D(e.label)+" ",1),an(v("input",{id:l.value,ref_key:"inputRef",ref:n,type:e.inputType,placeholder:e.placeholder,"onUpdate:modelValue":p[0]||(p[0]=b=>i.value=b),disabled:e.busy,required:""},null,8,eo),[[ln,i.value]])],8,Xn),e.error?(M(),T("div",to,D(e.error),1)):L("",!0),v("div",{class:"modal-actions",onKeydown:a},[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=he(),o=q(null),i=q(null),l=c=>{i.value=c,o.value=c.ip||null,t("sessionHover",c)},a=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())},d=c=>!!r.terminatingSessions[c],p=(c,S)=>{const R=c.currentTarget,y=R.querySelector(".session-list")?.querySelectorAll(".session-item"),m=Array.from(document.querySelectorAll(".session-group")),g=m.indexOf(R);if(c.key==="Enter"&&c.target===R){S&&R.querySelector("a")?.click();return}if(r.navigationDisabled)return;const E=j(c);if(["down","right"].includes(E)&&c.target===R){c.preventDefault(),y?.[0]?.focus();return}if(["up","left"].includes(E)&&c.target===R){c.preventDefault(),g>0?m[g-1].focus():t("navigate-out","up");return}Dt(c,k=>t("navigate-out",k))},b=(c,S)=>{if(Pt(c,()=>{d(S.id)||t("terminate",S)}),c.defaultPrevented||r.navigationDisabled)return;const R=j(c);if(R){c.preventDefault();const C=c.currentTarget.closest(".session-group"),y=C.querySelector(".session-list");if(Nt(y,c.currentTarget,R,{itemSelector:".session-item"})==="boundary"){if(R==="left"||R==="up")C?.focus();else if(R==="down"||R==="right"){const g=Array.from(document.querySelectorAll(".session-group")),E=g.indexOf(C);E<g.length-1?g[E+1].focus():t("navigate-out","down")}}}c.key==="Escape"&&(c.preventDefault(),c.currentTarget.closest(".session-group")?.focus())},f=c=>`${c.includes(":")?"http":"https"}://${c}`,w=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)}},h=c=>ae(c)??c,_=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=>_.value&&ae(c)===_.value,P=x(()=>{const c={};for(const y of r.sessions){const m=y.host||"";c[m]||(c[m]={sessions:[],isCurrentSite:!1}),c[m].sessions.push(y),y.is_current_host&&(c[m].isCurrentSite=!0)}for(const y in c)c[y].sessions.sort((m,g)=>new Date(g.last_renewed)-new Date(m.last_renewed));const S=new Intl.Collator(void 0,{numeric:!0,sensitivity:"base"}),R=Object.keys(c).sort(S.compare),C={};for(const y of R)C[y]=c[y];return C});return(c,S)=>(M(),T("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?(M(!0),T(oe,{key:0},ce(P.value,(R,C)=>(M(),T("div",{key:C,class:"session-group",tabindex:"0",onKeydown:y=>p(y,C)},[v("span",{class:se(["session-group-host",{"is-current-site":R.isCurrentSite}])},[S[3]||(S[3]=v("span",{class:"session-group-icon"},"🌐",-1)),C?(M(),T("a",{key:0,href:f(C),tabindex:"-1",target:"_blank",rel:"noopener noreferrer"},D(C),9,co)):(M(),T(oe,{key:1},[ze("Unbound host")],64))],2),v("div",fo,[(M(!0),T(oe,null,ce(R.sessions,y=>(M(),T("div",{key:y.id,class:se(["session-item",{"is-current":y.is_current&&!o.value&&!e.hoveredCredentialUuid,"is-hovered":i.value?.id===y.id,"is-linked-credential":e.hoveredCredentialUuid===y.credential}]),tabindex:"-1",onMousedown:S[0]||(S[0]=de(()=>{},["prevent"])),onClickCapture:u,onFocusin:m=>l(y),onFocusout:S[1]||(S[1]=m=>a(m)),onKeydown:m=>b(m,y)},[v("div",go,[v("h4",mo,D(y.user_agent),1),v("div",yo,[y.is_current&&!o.value&&!e.hoveredCredentialUuid?(M(),T("span",po,"Current")):i.value?.id===y.id?(M(),T("span",wo,"Selected")):e.hoveredCredentialUuid===y.credential?(M(),T("span",bo,"Linked")):!e.hoveredCredentialUuid&&A(y.ip)?(M(),T("span",vo,"Same IP")):L("",!0),v("button",{onClick:m=>c.$emit("terminate",y),class:"btn-card-delete",disabled:d(y.id),title:d(y.id)?"Terminating...":"Terminate session",tabindex:"-1"},"❌",8,Co)])]),v("div",So,[v("div",Eo,[v("span",_o,D(F(G)(y.last_renewed)),1),v("span",{class:"date-value",onClick:m=>w(y.ip),title:"Click to copy full IP"},D(h(y.ip)),9,ko)])])],42,ho))),128))])],40,uo))),128)):(M(),T("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={},be,et;function Ao(){return et||(et=1,be=function(){return typeof Promise=="function"&&Promise.prototype&&Promise.prototype.then}),be}var ve={},z={},tt;function W(){if(tt)return z;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 z.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},z.getSymbolTotalCodewords=function(t){return s[t]},z.getBCHDigit=function(r){let t=0;for(;r!==0;)t++,r>>>=1;return t},z.setToSJISFunction=function(t){if(typeof t!="function")throw new Error('"toSJISFunc" is not a valid function.');e=t},z.isKanjiModeEnabled=function(){return typeof e<"u"},z.toSJIS=function(t){return e(t)},z}var Ce={},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}}})(Ce)),Ce}var Se,ot;function Ro(){if(ot)return Se;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++}},Se=e,Se}var Ee,rt;function To(){if(rt)return Ee;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]},Ee=e,Ee}var _e={},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,l=[o-7];for(let a=1;a<n-1;a++)l[a]=l[a-1]-i;return l.push(6),l.reverse()},e.getPositions=function(t){const n=[],o=e.getRowColCoords(t),i=o.length;for(let l=0;l<i;l++)for(let a=0;a<i;a++)l===0&&a===0||l===0&&a===i-1||l===i-1&&a===0||n.push([o[l],o[a]]);return n}})(_e)),_e}var ke={},it;function No(){if(it)return ke;it=1;const e=W().getSymbolSize,s=7;return ke.getPositions=function(t){const n=e(t);return[[0,0],[n-s,0],[0,n-s]]},ke}var Be={},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,l=0,a=0,u=null,d=null;for(let p=0;p<o;p++){l=a=0,u=d=null;for(let b=0;b<o;b++){let f=n.get(p,b);f===u?l++:(l>=5&&(i+=s.N1+(l-5)),u=f,l=1),f=n.get(b,p),f===d?a++:(a>=5&&(i+=s.N1+(a-5)),d=f,a=1)}l>=5&&(i+=s.N1+(l-5)),a>=5&&(i+=s.N1+(a-5))}return i},e.getPenaltyN2=function(n){const o=n.size;let i=0;for(let l=0;l<o-1;l++)for(let a=0;a<o-1;a++){const u=n.get(l,a)+n.get(l,a+1)+n.get(l+1,a)+n.get(l+1,a+1);(u===4||u===0)&&i++}return i*s.N2},e.getPenaltyN3=function(n){const o=n.size;let i=0,l=0,a=0;for(let u=0;u<o;u++){l=a=0;for(let d=0;d<o;d++)l=l<<1&2047|n.get(u,d),d>=10&&(l===1488||l===93)&&i++,a=a<<1&2047|n.get(d,u),d>=10&&(a===1488||a===93)&&i++}return i*s.N3},e.getPenaltyN4=function(n){let o=0;const i=n.data.length;for(let a=0;a<i;a++)o+=n.data[a];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 l=0;l<i;l++)for(let a=0;a<i;a++)o.isReserved(a,l)||o.xor(a,l,r(n,a,l))},e.getBestMask=function(n,o){const i=Object.keys(e.Patterns).length;let l=0,a=1/0;for(let u=0;u<i;u++){o(u),e.applyMask(u,n);const d=e.getPenaltyN1(n)+e.getPenaltyN2(n)+e.getPenaltyN3(n)+e.getPenaltyN4(n);e.applyMask(u,n),d<a&&(a=d,l=u)}return l}})(Be)),Be}var le={},lt;function Ht(){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 Ie={},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 l=0;l<n.length;l++)o[i+l]^=s.mul(t[i],n[l]);return o},e.mod=function(t,n){let o=new Uint8Array(t);for(;o.length-n.length>=0;){const i=o[0];for(let a=0;a<n.length;a++)o[a]^=s.mul(n[a],i);let l=0;for(;l<o.length&&o[l]===0;)l++;o=o.slice(l)}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}})(Ie)),Ie}var Ae,dt;function $o(){if(dt)return Ae;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 l=new Uint8Array(this.degree);return l.set(o,i),l}return o},Ae=s,Ae}var Re={},Te={},Me={},ft;function Ot(){return ft||(ft=1,Me.isValid=function(s){return!isNaN(s)&&s>=1&&s<=40}),Me}var V={},ht;function jt(){if(ht)return V;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
6
+ ]))+`;V.KANJI=new RegExp(r,"g"),V.BYTE_KANJI=new RegExp("[^A-Z0-9 $%*+\\-./:]+","g"),V.BYTE=new RegExp(t,"g"),V.NUMERIC=new RegExp(e,"g"),V.ALPHANUMERIC=new RegExp(s,"g");const n=new RegExp("^"+r+"$"),o=new RegExp("^"+e+"$"),i=new RegExp("^[A-Z0-9 $%*+\\-./:]+$");return V.testKanji=function(a){return n.test(a)},V.testNumeric=function(a){return o.test(a)},V.testAlphanumeric=function(a){return i.test(a)},V}var gt;function Z(){return gt||(gt=1,(function(e){const s=Ot(),r=jt();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}}})(Te)),Te}var mt;function qo(){return mt||(mt=1,(function(e){const s=W(),r=Ht(),t=Je(),n=Z(),o=Ot(),i=7973,l=s.getBCHDigit(i);function a(b,f,w){for(let h=1;h<=40;h++)if(f<=e.getCapacity(h,w,b))return h}function u(b,f){return n.getCharCountIndicator(b,f)+4}function d(b,f){let w=0;return b.forEach(function(h){const _=u(h.mode,f);w+=_+h.getBitsLength()}),w}function p(b,f){for(let w=1;w<=40;w++)if(d(b,w)<=e.getCapacity(w,f,n.MIXED))return w}e.from=function(f,w){return o.isValid(f)?parseInt(f,10):w},e.getCapacity=function(f,w,h){if(!o.isValid(f))throw new Error("Invalid QR Code version");typeof h>"u"&&(h=n.BYTE);const _=s.getSymbolTotalCodewords(f),A=r.getTotalCodewordsCount(f,w),P=(_-A)*8;if(h===n.MIXED)return P;const c=P-u(h,f);switch(h){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(f,w){let h;const _=t.from(w,t.M);if(Array.isArray(f)){if(f.length>1)return p(f,_);if(f.length===0)return 1;h=f[0]}else h=f;return a(h.mode,h.getLength(),_)},e.getEncodedBits=function(f){if(!o.isValid(f)||f<7)throw new Error("Invalid QR Code version");let w=f<<12;for(;s.getBCHDigit(w)-l>=0;)w^=i<<s.getBCHDigit(w)-l;return f<<12|w}})(Re)),Re}var Ne={},yt;function Fo(){if(yt)return Ne;yt=1;const e=W(),s=1335,r=21522,t=e.getBCHDigit(s);return Ne.getEncodedBits=function(o,i){const l=o.bit<<3|i;let a=l<<10;for(;e.getBCHDigit(a)-t>=0;)a^=s<<e.getBCHDigit(a)-t;return(l<<10|a)^r},Ne}var Pe={},De,pt;function Uo(){if(pt)return De;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 l=this.data.length-n;l>0&&(o=this.data.substr(n),i=parseInt(o,10),t.put(i,l*3+1))},De=s,De}var Le,wt;function Ko(){if(wt)return Le;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)},Le=r,Le}var $e,bt;function Vo(){if(bt)return $e;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)},$e=s,$e}var qe,vt;function Ho(){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]+`
7
+ 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 Oo(){return Ct||(Ct=1,(function(e){var s={single_source_shortest_paths:function(r,t,n){var o={},i={};i[t]=0;var l=s.PriorityQueue.make();l.push(t,0);for(var a,u,d,p,b,f,w,h,_;!l.empty();){a=l.pop(),u=a.value,p=a.cost,b=r[u]||{};for(d in b)b.hasOwnProperty(d)&&(f=b[d],w=p+f,h=i[d],_=typeof i[d]>"u",(_||h>w)&&(i[d]=w,l.push(d,w),o[d]=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 jo(){return St||(St=1,(function(e){const s=Z(),r=Uo(),t=Ko(),n=Vo(),o=Ho(),i=jt(),l=W(),a=Oo();function u(A){return unescape(encodeURIComponent(A)).length}function d(A,P,c){const S=[];let R;for(;(R=A.exec(c))!==null;)S.push({data:R[0],index:R.index,mode:P,length:R[0].length});return S}function p(A){const P=d(i.NUMERIC,s.NUMERIC,A),c=d(i.ALPHANUMERIC,s.ALPHANUMERIC,A);let S,R;return l.isKanjiModeEnabled()?(S=d(i.BYTE,s.BYTE,A),R=d(i.KANJI,s.KANJI,A)):(S=d(i.BYTE_KANJI,s.BYTE,A),R=[]),P.concat(c,S,R).sort(function(y,m){return y.index-m.index}).map(function(y){return{data:y.data,mode:y.mode,length:y.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 f(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 w(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 h(A,P){const c={},S={start:{}};let R=["start"];for(let C=0;C<A.length;C++){const y=A[C],m=[];for(let g=0;g<y.length;g++){const E=y[g],k=""+C+g;m.push(k),c[k]={node:E,lastCount:0},S[k]={};for(let B=0;B<R.length;B++){const I=R[B];c[I]&&c[I].node.mode===E.mode?(S[I][k]=b(c[I].lastCount+E.length,E.mode)-b(c[I].lastCount,E.mode),c[I].lastCount+=E.length):(c[I]&&(c[I].lastCount=E.length),S[I][k]=b(E.length,E.mode)+4+s.getCharCountIndicator(E.mode,P))}}R=m}for(let C=0;C<R.length;C++)S[R[C]].end=0;return{map:S,table:c}}function _(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)+`.
8
+ Suggested mode is: `+s.toString(S));switch(c===s.KANJI&&!l.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(_(S,null)):S.data&&c.push(_(S.data,S.mode)),c},[])},e.fromString=function(P,c){const S=p(P,l.isKanjiModeEnabled()),R=w(S),C=h(R,c),y=a.find_path(C.map,"start","end"),m=[];for(let g=1;g<y.length-1;g++)m.push(C.table[y[g]].node);return e.fromArray(f(m))},e.rawSplit=function(P){return e.fromArray(p(P,l.isKanjiModeEnabled()))}})(Pe)),Pe}var Et;function xo(){if(Et)return ve;Et=1;const e=W(),s=Je(),r=Ro(),t=To(),n=Mo(),o=No(),i=Po(),l=Ht(),a=$o(),u=qo(),d=Fo(),p=Z(),b=jo();function f(C,y){const m=C.size,g=o.getPositions(y);for(let E=0;E<g.length;E++){const k=g[E][0],B=g[E][1];for(let I=-1;I<=7;I++)if(!(k+I<=-1||m<=k+I))for(let N=-1;N<=7;N++)B+N<=-1||m<=B+N||(I>=0&&I<=6&&(N===0||N===6)||N>=0&&N<=6&&(I===0||I===6)||I>=2&&I<=4&&N>=2&&N<=4?C.set(k+I,B+N,!0,!0):C.set(k+I,B+N,!1,!0))}}function w(C){const y=C.size;for(let m=8;m<y-8;m++){const g=m%2===0;C.set(m,6,g,!0),C.set(6,m,g,!0)}}function h(C,y){const m=n.getPositions(y);for(let g=0;g<m.length;g++){const E=m[g][0],k=m[g][1];for(let B=-2;B<=2;B++)for(let I=-2;I<=2;I++)B===-2||B===2||I===-2||I===2||B===0&&I===0?C.set(E+B,k+I,!0,!0):C.set(E+B,k+I,!1,!0)}}function _(C,y){const m=C.size,g=u.getEncodedBits(y);let E,k,B;for(let I=0;I<18;I++)E=Math.floor(I/3),k=I%3+m-8-3,B=(g>>I&1)===1,C.set(E,k,B,!0),C.set(k,E,B,!0)}function A(C,y,m){const g=C.size,E=d.getEncodedBits(y,m);let k,B;for(k=0;k<15;k++)B=(E>>k&1)===1,k<6?C.set(k,8,B,!0):k<8?C.set(k+1,8,B,!0):C.set(g-15+k,8,B,!0),k<8?C.set(8,g-k-1,B,!0):k<9?C.set(8,15-k-1+1,B,!0):C.set(8,15-k-1,B,!0);C.set(g-8,8,1,!0)}function P(C,y){const m=C.size;let g=-1,E=m-1,k=7,B=0;for(let I=m-1;I>0;I-=2)for(I===6&&I--;;){for(let N=0;N<2;N++)if(!C.isReserved(E,I-N)){let K=!1;B<y.length&&(K=(y[B]>>>k&1)===1),C.set(E,I-N,K),k--,k===-1&&(B++,k=7)}if(E+=g,E<0||m<=E){E-=g,g=-g;break}}}function c(C,y,m){const g=new r;m.forEach(function(N){g.put(N.mode.bit,4),g.put(N.getLength(),p.getCharCountIndicator(N.mode,C)),N.write(g)});const E=e.getSymbolTotalCodewords(C),k=l.getTotalCodewordsCount(C,y),B=(E-k)*8;for(g.getLengthInBits()+4<=B&&g.put(0,4);g.getLengthInBits()%8!==0;)g.putBit(0);const I=(B-g.getLengthInBits())/8;for(let N=0;N<I;N++)g.put(N%2?17:236,8);return S(g,C,y)}function S(C,y,m){const g=e.getSymbolTotalCodewords(y),E=l.getTotalCodewordsCount(y,m),k=g-E,B=l.getBlocksCount(y,m),I=g%B,N=B-I,K=Math.floor(g/B),U=Math.floor(k/B),$=U+1,Ye=K-U,zt=new a(Ye);let ge=0;const ie=new Array(B),Qe=new Array(B);let me=0;const Jt=new Uint8Array(C.buffer);for(let X=0;X<B;X++){const pe=X<N?U:$;ie[X]=Jt.slice(ge,ge+pe),Qe[X]=zt.encode(ie[X]),ge+=pe,me=Math.max(me,pe)}const ye=new Uint8Array(g);let Ge=0,H,O;for(H=0;H<me;H++)for(O=0;O<B;O++)H<ie[O].length&&(ye[Ge++]=ie[O][H]);for(H=0;H<Ye;H++)for(O=0;O<B;O++)ye[Ge++]=Qe[O][H];return ye}function R(C,y,m,g){let E;if(Array.isArray(C))E=b.fromArray(C);else if(typeof C=="string"){let K=y;if(!K){const U=b.rawSplit(C);K=u.getBestVersionForData(U,m)}E=b.fromString(C,K||40)}else throw new Error("Invalid data");const k=u.getBestVersionForData(E,m);if(!k)throw new Error("The amount of data is too big to be stored in a QR Code");if(!y)y=k;else if(y<k)throw new Error(`
9
+ The chosen QR Code version cannot contain this amount of data.
10
+ Minimum version required to store current data is: `+k+`.
11
+ `);const B=c(y,m,E),I=e.getSymbolSize(y),N=new t(I);return f(N,y),w(N),h(N,y),A(N,m,0),y>=7&&_(N,y),P(N,B),isNaN(g)&&(g=i.getBestMask(N,A.bind(null,N,m))),i.applyMask(g,N),A(N,m,g),{modules:N,version:y,errorCorrectionLevel:m,maskPattern:g,segments:E}}return ve.create=function(y,m){if(typeof y>"u"||y==="")throw new Error("No input text");let g=s.M,E,k;return typeof m<"u"&&(g=s.from(m.errorCorrectionLevel,s.M),E=u.from(m.version),k=i.from(m.maskPattern),m.toSJISFunc&&e.setToSJISFunction(m.toSJISFunc)),R(y,E,g,k)},ve}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,l=n.modules.data,a=e.getScale(i,o),u=Math.floor((i+o.margin*2)*a),d=o.margin*a,p=[o.color.light,o.color.dark];for(let b=0;b<u;b++)for(let f=0;f<u;f++){let w=(b*u+f)*4,h=o.color.light;if(b>=d&&f>=d&&b<u-d&&f<u-d){const _=Math.floor((b-d)/a),A=Math.floor((f-d)/a);h=p[l[_*i+A]?1:0]}t[w++]=h.r,t[w++]=h.g,t[w++]=h.b,t[w]=h.a}}})(Ke)),Ke}var kt;function zo(){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,l){let a=l,u=i;typeof a>"u"&&(!i||!i.getContext)&&(a=i,i=void 0),i||(u=t()),a=s.getOptions(a);const d=s.getImageWidth(o.modules.size,a),p=u.getContext("2d"),b=p.createImageData(d,d);return s.qrToImageData(b.data,o,a),r(p,u,d),p.putImageData(b,0,0),u},e.renderToDataURL=function(o,i,l){let a=l;typeof a>"u"&&(!i||!i.getContext)&&(a=i,i=void 0),a||(a={});const u=e.render(o,i,a),d=a.type||"image/png",p=a.rendererOpts||{};return u.toDataURL(d,p.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,l=o+'="'+n.hex+'"';return i<1?l+" "+o+'-opacity="'+i.toFixed(2).slice(1)+'"':l}function r(n,o,i){let l=n+o;return typeof i<"u"&&(l+=" "+i),l}function t(n,o,i){let l="",a=0,u=!1,d=0;for(let p=0;p<n.length;p++){const b=Math.floor(p%o),f=Math.floor(p/o);!b&&!u&&(u=!0),n[p]?(d++,p>0&&b>0&&n[p-1]||(l+=u?r("M",b+i,.5+f+i):r("m",a,0),a=0,u=!1),b+1<o&&n[p+1]||(l+=r("h",d),d=0)):a++}return l}return Ve.render=function(o,i,l){const a=e.getOptions(i),u=o.modules.size,d=o.modules.data,p=u+a.margin*2,b=a.color.light.a?"<path "+s(a.color.light,"fill")+' d="M0 0h'+p+"v"+p+'H0z"/>':"",f="<path "+s(a.color.dark,"stroke")+' d="'+t(d,u,a.margin)+'"/>',w='viewBox="0 0 '+p+" "+p+'"',_='<svg xmlns="http://www.w3.org/2000/svg" '+(a.width?'width="'+a.width+'" height="'+a.width+'" ':"")+w+' shape-rendering="crispEdges">'+b+f+`</svg>
12
+ `;return typeof l=="function"&&l(null,_),_},Ve}var It;function Yo(){if(It)return te;It=1;const e=Ao(),s=xo(),r=zo(),t=Jo();function n(o,i,l,a,u){const d=[].slice.call(arguments,1),p=d.length,b=typeof d[p-1]=="function";if(!b&&!e())throw new Error("Callback required as last argument");if(b){if(p<2)throw new Error("Too few arguments provided");p===2?(u=l,l=i,i=a=void 0):p===3&&(i.getContext&&typeof u>"u"?(u=a,a=void 0):(u=a,a=l,l=i,i=void 0))}else{if(p<1)throw new Error("Too few arguments provided");return p===1?(l=i,i=a=void 0):p===2&&!i.getContext&&(a=l,l=i,i=void 0),new Promise(function(f,w){try{const h=s.create(l,a);f(o(h,i,a))}catch(h){w(h)}})}try{const f=s.create(l,a);u(null,o(f,i,a))}catch(f){u(f)}}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,l){return t.render(o,l)}),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=q(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(a){console.error("QR code generation failed:",a)}}async function l(){if(r.url)try{await navigator.clipboard.writeText(r.url),t("copied")}catch(a){console.error("Failed to copy link:",a)}}return He(()=>r.url,()=>{i()},{immediate:!0}),He(n,()=>{n.value&&r.url&&i()},{immediate:!0}),(a,u)=>(M(),T("div",Wo,[v("div",Zo,[v("a",{href:e.url,onClick:de(l,["prevent"]),class:"qr-link",title:"Click to copy link",tabindex:"0",onKeydown:un(de(l,["prevent"]),["enter"])},[v("canvas",{ref_key:"qrCanvas",ref:n,class:"qr-code"},null,512),e.showLink&&e.url?(M(),T("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=he(),o=q(null),i=q(null),l=q(null),a=q(null),u=q(null);async function d(){try{const h=await Q(r.endpoint,{method:"POST"});if(h.url){if(i.value=h.url,l.value=h.expires?new Date(h.expires):null,await xe(),o.value){o.value.showModal();const _=a.value;(_?.querySelector(".btn-primary")||_?.querySelector("button"))?.focus()}}else t("close")}catch(h){n.showMessage(h.message||"Failed to generate link","error"),t("close")}}function p(){t("copied")}const b=h=>{const _=j(h)},f=h=>{const _=j(h);_&&(h.preventDefault(),(_==="down"||_==="up")&&a.value?.querySelector("button")?.focus())},w=h=>{const _=j(h);_&&(h.preventDefault(),(_==="up"||_==="down")&&document.querySelector(".qr-link")?.focus())};return $t(()=>{u.value=document.activeElement,d()}),qt(()=>{const h=u.value;h&&document.body.contains(h)&&!h.disabled&&h.focus()}),(h,_)=>(M(),T("dialog",{ref_key:"dialog",ref:o,onClose:_[2]||(_[2]=A=>h.$emit("close")),onKeydown:b},[v("div",or,[v("div",rr,[v("h2",sr,[_[3]||(_[3]=ze(" 📱 ",-1)),e.userName?(M(),T("span",ir,"Registration for "+D(e.userName),1)):(M(),T("span",ar,"Add Another Device"))]),v("button",{class:"icon-btn",onClick:_[0]||(_[0]=A=>h.$emit("close")),"aria-label":"Close",tabindex:"-1"},"✕")]),v("div",lr,[_[4]||(_[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:i.value,"show-link":!0,onCopied:p,onKeydown:f},null,8,["url"]),l.value?(M(),T("p",ur," This link expires "+D(F(G)(l.value).toLowerCase())+". ",1)):L("",!0)]),v("div",{class:"reg-actions",ref_key:"actionsRow",ref:a,onKeydown:w},[v("button",{class:"btn-secondary",onClick:_[1]||(_[1]=A=>h.$emit("close"))},"Close")],544)])],544))}},Ar=Y(cr,[["__scopeId","data-v-26360b56"]]),dr={class:"loading-container"},fr={__name:"LoadingView",props:{message:{type:String,default:"Loading..."}},setup(e){return(s,r)=>(M(),T("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)=>(M(),T("div",hr,[v("div",gr,[v("h2",null,D(e.icon)+" "+D(e.title),1),e.message?(M(),T("p",mr,D(e.message),1)):L("",!0),v("div",yr,[v("button",{class:"btn-secondary",onClick:t[0]||(t[0]=(...n)=>F(We)&&F(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,he as u};
@@ -1 +1 @@
1
- .remote-auth-inline[data-v-1280e25b]{display:flex;flex-direction:column;gap:1rem;width:100%}.loading-section[data-v-1280e25b]{display:flex;flex-direction:column;align-items:center;gap:.75rem;padding:2rem 1rem;min-height:180px;justify-content:center}.loading-section p[data-v-1280e25b]{margin:0;color:var(--color-text-muted);font-size:.95rem}.spinner[data-v-1280e25b]{width:40px;height:40px;border:3px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;animation:spin-1280e25b .8s linear infinite}@keyframes spin-1280e25b{to{transform:rotate(360deg)}}.auth-display[data-v-1280e25b]{display:flex;flex-direction:column;gap:1.25rem;width:100%;min-height:180px}.auth-content[data-v-1280e25b]{display:flex;gap:2rem;align-items:center;justify-content:center;flex-wrap:nowrap}.loading-placeholder[data-v-1280e25b]{display:flex;flex-direction:column;align-items:center;gap:.75rem;width:100%;padding:1rem}.loading-placeholder p[data-v-1280e25b]{margin:0;color:var(--color-text-muted);font-size:.95rem}.pairing-code-section[data-v-1280e25b]{flex:0 0 auto;display:flex;flex-direction:column;gap:.5rem;width:280px;max-width:100%}.pairing-label[data-v-1280e25b]{margin:0;font-size:.875rem;color:var(--color-text-muted);font-weight:500;text-align:center}.slot-machine[data-v-1280e25b]{padding:.875rem 1rem;background:var(--color-surface-hover, rgba(0, 0, 0, .03));border:2px solid var(--color-border);border-radius:var(--radius-sm, 6px);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[data-v-1280e25b]{overflow:hidden;background:var(--color-surface, rgba(255, 255, 255, .5))}.slot-machine:not(.stopped) .slot-reel[data-v-1280e25b]:nth-child(1){animation:slotSpin-1280e25b .14s ease-in-out infinite}.slot-machine:not(.stopped) .slot-reel[data-v-1280e25b]:nth-child(2){animation:slotSpin-1280e25b .17s ease-in-out infinite}.slot-machine:not(.stopped) .slot-reel[data-v-1280e25b]:nth-child(3){animation:slotSpin-1280e25b .2s ease-in-out infinite}.slot-word[data-v-1280e25b]{font-size:1.25rem;font-weight:600;letter-spacing:.05em;text-align:center;width:100%}.slot-machine:not(.stopped) .slot-reel:nth-child(1) .slot-word[data-v-1280e25b]{animation:wordRoll-1280e25b .14s ease-in-out infinite}.slot-machine:not(.stopped) .slot-reel:nth-child(2) .slot-word[data-v-1280e25b]{animation:wordRoll-1280e25b .17s ease-in-out infinite}.slot-machine:not(.stopped) .slot-reel:nth-child(3) .slot-word[data-v-1280e25b]{animation:wordRoll-1280e25b .2s ease-in-out infinite}@keyframes slotSpin-1280e25b{0%{box-shadow:inset 0 2px 4px #0000001a}50%{box-shadow:inset 0 4px 8px #0003}to{box-shadow:inset 0 2px 4px #0000001a}}@keyframes wordRoll-1280e25b{0%{transform:translateY(-30%) scale(.9);opacity:.4;filter:blur(1.5px)}25%{transform:translateY(-10%) scale(.95);opacity:.6;filter:blur(1px)}50%{transform:translateY(0) scale(1);opacity:1;filter:blur(0)}75%{transform:translateY(10%) scale(.95);opacity:.6;filter:blur(1px)}to{transform:translateY(30%) scale(.9);opacity:.4;filter:blur(1.5px)}}.site-url[data-v-1280e25b]{margin:.5rem 0 0;font-size:.8rem;color:var(--color-text-muted);text-align:center;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;opacity:.8}.waiting-indicator[data-v-1280e25b]{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.75rem;background:var(--color-surface-hover, rgba(0, 0, 0, .02));border-radius:var(--radius-sm, 6px);font-size:.875rem;color:var(--color-text-muted)}.spinner-small[data-v-1280e25b]{width:16px;height:16px;border:2px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;animation:spin-1280e25b .8s linear infinite}.success-section[data-v-1280e25b]{padding:1rem;text-align:center;min-height:180px;display:flex;align-items:center;justify-content:center}.success-message[data-v-1280e25b]{margin:0;font-size:1rem;color:var(--color-success, #10b981);font-weight:500}.error-section[data-v-1280e25b]{padding:1rem;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;min-height:180px}.error-message[data-v-1280e25b]{margin:0;font-size:.95rem;color:var(--color-error, #ef4444)}@media(max-width:640px){.auth-content[data-v-1280e25b]{gap:1.5rem;flex-direction:column;align-items:center}.pairing-code-section[data-v-1280e25b]{width:100%;max-width:280px}}@media(max-width:480px){.pairing-code[data-v-1280e25b]{font-size:1.1rem;padding:.75rem .875rem}.pairing-code-section[data-v-1280e25b]{width:100%;max-width:100%}}.button-row.center[data-v-5c04d110]{display:flex;justify-content:center;gap:.75rem;flex-wrap:wrap}.user-line[data-v-5c04d110]{margin:.5rem 0 0;font-weight:500;color:var(--color-text)}main.view-root[data-v-5c04d110]{min-height:100vh;align-items:center;justify-content:center;padding:2rem 1rem}.surface.surface--tight[data-v-5c04d110]{max-width:520px;margin:0 auto;width:100%;display:flex;flex-direction:column;gap:1.75rem}.auth-view[data-v-5c04d110]{display:flex;flex-direction:column;align-items:center;gap:1rem;width:100%}.view-lede[data-v-5c04d110] .inline-link{color:var(--color-primary);text-decoration:none;transition:opacity .15s;font-weight:400}.view-lede[data-v-5c04d110] .inline-link:hover{opacity:.8;text-decoration:underline}
1
+ .remote-auth-inline[data-v-1280e25b]{display:flex;flex-direction:column;gap:1rem;width:100%}.loading-section[data-v-1280e25b]{display:flex;flex-direction:column;align-items:center;gap:.75rem;padding:2rem 1rem;min-height:180px;justify-content:center}.loading-section p[data-v-1280e25b]{margin:0;color:var(--color-text-muted);font-size:.95rem}.spinner[data-v-1280e25b]{width:40px;height:40px;border:3px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;animation:spin-1280e25b .8s linear infinite}@keyframes spin-1280e25b{to{transform:rotate(360deg)}}.auth-display[data-v-1280e25b]{display:flex;flex-direction:column;gap:1.25rem;width:100%;min-height:180px}.auth-content[data-v-1280e25b]{display:flex;gap:2rem;align-items:center;justify-content:center;flex-wrap:nowrap}.loading-placeholder[data-v-1280e25b]{display:flex;flex-direction:column;align-items:center;gap:.75rem;width:100%;padding:1rem}.loading-placeholder p[data-v-1280e25b]{margin:0;color:var(--color-text-muted);font-size:.95rem}.pairing-code-section[data-v-1280e25b]{flex:0 0 auto;display:flex;flex-direction:column;gap:.5rem;width:280px;max-width:100%}.pairing-label[data-v-1280e25b]{margin:0;font-size:.875rem;color:var(--color-text-muted);font-weight:500;text-align:center}.slot-machine[data-v-1280e25b]{padding:.875rem 1rem;background:var(--color-surface-hover, rgba(0, 0, 0, .03));border:2px solid var(--color-border);border-radius:var(--radius-sm, 6px);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[data-v-1280e25b]{overflow:hidden;background:var(--color-surface, rgba(255, 255, 255, .5))}.slot-machine:not(.stopped) .slot-reel[data-v-1280e25b]:nth-child(1){animation:slotSpin-1280e25b .14s ease-in-out infinite}.slot-machine:not(.stopped) .slot-reel[data-v-1280e25b]:nth-child(2){animation:slotSpin-1280e25b .17s ease-in-out infinite}.slot-machine:not(.stopped) .slot-reel[data-v-1280e25b]:nth-child(3){animation:slotSpin-1280e25b .2s ease-in-out infinite}.slot-word[data-v-1280e25b]{font-size:1.25rem;font-weight:600;letter-spacing:.05em;text-align:center;width:100%}.slot-machine:not(.stopped) .slot-reel:nth-child(1) .slot-word[data-v-1280e25b]{animation:wordRoll-1280e25b .14s ease-in-out infinite}.slot-machine:not(.stopped) .slot-reel:nth-child(2) .slot-word[data-v-1280e25b]{animation:wordRoll-1280e25b .17s ease-in-out infinite}.slot-machine:not(.stopped) .slot-reel:nth-child(3) .slot-word[data-v-1280e25b]{animation:wordRoll-1280e25b .2s ease-in-out infinite}@keyframes slotSpin-1280e25b{0%{box-shadow:inset 0 2px 4px #0000001a}50%{box-shadow:inset 0 4px 8px #0003}to{box-shadow:inset 0 2px 4px #0000001a}}@keyframes wordRoll-1280e25b{0%{transform:translateY(-30%) scale(.9);opacity:.4;filter:blur(1.5px)}25%{transform:translateY(-10%) scale(.95);opacity:.6;filter:blur(1px)}50%{transform:translateY(0) scale(1);opacity:1;filter:blur(0)}75%{transform:translateY(10%) scale(.95);opacity:.6;filter:blur(1px)}to{transform:translateY(30%) scale(.9);opacity:.4;filter:blur(1.5px)}}.site-url[data-v-1280e25b]{margin:.5rem 0 0;font-size:.8rem;color:var(--color-text-muted);text-align:center;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;opacity:.8}.waiting-indicator[data-v-1280e25b]{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.75rem;background:var(--color-surface-hover, rgba(0, 0, 0, .02));border-radius:var(--radius-sm, 6px);font-size:.875rem;color:var(--color-text-muted)}.spinner-small[data-v-1280e25b]{width:16px;height:16px;border:2px solid var(--color-border);border-top-color:var(--color-primary);border-radius:50%;animation:spin-1280e25b .8s linear infinite}.success-section[data-v-1280e25b]{padding:1rem;text-align:center;min-height:180px;display:flex;align-items:center;justify-content:center}.success-message[data-v-1280e25b]{margin:0;font-size:1rem;color:var(--color-success, #10b981);font-weight:500}.error-section[data-v-1280e25b]{padding:1rem;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.75rem;min-height:180px}.error-message[data-v-1280e25b]{margin:0;font-size:.95rem;color:var(--color-error, #ef4444)}@media (max-width: 640px){.auth-content[data-v-1280e25b]{gap:1.5rem;flex-direction:column;align-items:center}.pairing-code-section[data-v-1280e25b]{width:100%;max-width:280px}}@media (max-width: 480px){.pairing-code[data-v-1280e25b]{font-size:1.1rem;padding:.75rem .875rem}.pairing-code-section[data-v-1280e25b]{width:100%;max-width:100%}}.button-row.center[data-v-3295ed62]{display:flex;justify-content:center;gap:.75rem;flex-wrap:wrap}.user-line[data-v-3295ed62]{margin:.5rem 0 0;font-weight:500;color:var(--color-text)}main.view-root[data-v-3295ed62]{min-height:100vh;align-items:center;justify-content:center;padding:2rem 1rem}.surface.surface--tight[data-v-3295ed62]{max-width:520px;margin:0 auto;width:100%;display:flex;flex-direction:column;gap:1.75rem}.auth-view[data-v-3295ed62]{display:flex;flex-direction:column;align-items:center;gap:1rem;width:100%}.view-lede[data-v-3295ed62] .inline-link{color:var(--color-primary);text-decoration:none;transition:opacity .15s;font-weight:400}.view-lede[data-v-3295ed62] .inline-link:hover{opacity:.8;text-decoration:underline}
@@ -1 +1 @@
1
- import{_ as G,r as m,c as S,w as Y,o as J,a as K,b as i,d as l,e as t,t as _,F as N,i as j,f as P,m as Q,p as Z,O as ee,g as te,a1 as se,x as ae,a7 as O,a6 as H,G as ne,n as oe,a8 as ie,a4 as le}from"./_plugin-vue_export-helper-nhjnO_bd.js";import{c as re,s as ce,b as ue,w as z}from"./pow-2N9bxgAo.js";const de={class:"remote-auth-inline"},he={key:0,class:"success-section"},ve={class:"success-message"},fe={key:1,class:"error-section"},me={class:"error-message"},ge={key:2,class:"auth-display"},pe={class:"auth-content"},_e={class:"pairing-code-section"},we={class:"slot-machine","aria-hidden":"true"},ye={class:"slot-word"},ke={class:"site-url"},be={key:3,class:"auth-display"},$e={class:"auth-content"},Ae={key:0,class:"pairing-code-section"},Re={class:"slot-machine stopped"},Se={class:"slot-word"},Ce={class:"site-url"},Pe={class:"waiting-indicator"},Te={__name:"RemoteAuthRequest",props:{active:{type:Boolean,default:!1}},emits:["authenticated","cancelled","error","register"],setup(w,{expose:I,emit:x}){const $=w,g=x,v=m(null),y=m(!1),n=m(null),A=m("connecting"),p=m(null),u=m(["","",""]);let a=null,k=null;const W=S(()=>v.value?v.value.replace(/\./g," "):""),b=S(()=>{if(!p.value)return"";const s=(p.value.auth_site_url||`${location.protocol}//${location.host}/auth/`).replace(/^https?:\/\//,"");return s.endsWith("/")?s.slice(0,-1):s}),E=S(()=>A.value==="authenticating"?"Complete on another device…":"Waiting for authentication…"),B=S(()=>"Authenticated successfully!");function C(){return z[Math.floor(Math.random()*z.length)]}function F(){u.value=[C(),C(),C()];const c=20,s=[setInterval(()=>{const o=[...u.value];o[0]=C(),u.value=o},140),setInterval(()=>{const o=[...u.value];o[1]=C(),u.value=o},170),setInterval(()=>{const o=[...u.value];o[2]=C(),u.value=o},200)];k=s,setTimeout(()=>{s.forEach(o=>clearInterval(o)),k=null},c*170)}function f(){k&&(Array.isArray(k)?k.forEach(c=>clearInterval(c)):clearInterval(k),k=null)}async function L(){n.value=null,y.value=!1,v.value=null,A.value="connecting",F();try{p.value=await Q();const c=p.value?.auth_host,s="/auth/ws/remote-auth/request",o=c&&location.host!==c?`//${c}${s}`:s;a=await Z(o);const R=await a.receive_json();if(R.pow){const h=re(R.pow.challenge),V=await ce(h,R.pow.work);a.send_json({pow:ue(V),action:"login"})}const T=await a.receive_json();if(T.status)throw new Error(T.detail||`Failed to create remote auth request: ${T.status}`);for(v.value=T.pairing_code,f(),A.value="waiting";;){const h=await a.receive_json();if(h.status==="locked")A.value="authenticating";else if(h.status==="paired")A.value="authenticating";else if(h.status==="authenticated"){y.value=!0,g("authenticated",{session_token:h.session_token});break}else{if(h.status==="denied")throw new Error("Access denied");if(h.status==="completed"){h.reset_token&&(y.value=!0,g("register",h.reset_token));break}else if(h.status==="error"||h.detail)throw new Error(h.detail||"Remote authentication failed")}}}catch(c){console.error("Remote authentication error:",c);const s=c.message||"Authentication failed";n.value=s,g("error",s)}finally{a&&(a.close(),a=null)}}function M(){L()}function U(){a&&(a.close(),a=null),g("cancelled")}return Y(()=>$.active,c=>{c&&!v.value&&!n.value&&!y.value&&L()}),J(()=>{$.active&&L()}),K(()=>{a&&(a.close(),a=null),f()}),I({retry:M,cancel:U}),(c,s)=>(l(),i("div",de,[y.value?(l(),i("div",he,[t("p",ve,"✅ "+_(B.value),1)])):n.value?(l(),i("div",fe,[t("p",me,_(n.value),1),t("button",{class:"btn-primary",onClick:M,style:{"margin-top":"0.75rem"}},"Try Again")])):A.value==="connecting"?(l(),i("div",ge,[t("div",pe,[t("div",_e,[s[0]||(s[0]=t("p",{class:"pairing-label"},"Enter the code words:",-1)),t("div",we,[(l(!0),i(N,null,j(u.value,(o,R)=>(l(),i("div",{class:"slot-reel",key:R},[t("div",ye,_(o),1)]))),128))]),t("p",ke,_(b.value),1)])]),s[1]||(s[1]=t("div",{class:"waiting-indicator"},[t("div",{class:"spinner-small"}),t("span",null,"Generating code…")],-1))])):(l(),i("div",be,[t("div",$e,[v.value?(l(),i("div",Ae,[s[2]||(s[2]=t("p",{class:"pairing-label"},"Enter the code words:",-1)),t("div",Re,[(l(!0),i(N,null,j(W.value.split(" "),(o,R)=>(l(),i("div",{class:"slot-reel",key:R},[t("div",Se,_(o),1)]))),128))]),t("p",Ce,_(b.value),1)])):P("",!0)]),t("div",Pe,[s[3]||(s[3]=t("div",{class:"spinner-small"},null,-1)),t("span",null,_(E.value),1)])]))]))}},Ee=G(Te,[["__scopeId","data-v-1280e25b"]]),We={class:"app-shell"},Le={key:0,class:"global-status",style:{display:"block"}},Me={class:"view-root"},Ue={key:0,class:"surface surface--tight"},Ie={class:"view-header center"},xe={key:0,class:"user-line"},Be=["innerHTML"],Fe={class:"section-block"},Ve={class:"section-body center"},Oe={key:0,class:"auth-view"},qe=["disabled"],De=["disabled"],Ne=["disabled"],je=["disabled"],He={key:1,class:"auth-view"},ze={__name:"RestrictedAuth",props:{mode:{type:String,default:"login",validator:w=>["login","reauth","forbidden"].includes(w)}},emits:["authenticated","forbidden","logout","back","home","auth-error"],setup(w,{expose:I,emit:x}){const $=w,g=x,v=ee({show:!1,message:"",type:"info"}),y=m(!0),n=m(!1),A=m(null),p=m(null),u=m("initial"),a=m("local"),k=m(null);let W=null;const b=S(()=>!!p.value),E=S(()=>y.value?!1:$.mode==="reauth"?!0:u.value!=="forbidden"),B=S(()=>$.mode==="reauth"?"🔐 Additional Authentication":u.value==="forbidden"?"🚫 Forbidden":`🔐 ${A.value?.rp_name||location.origin}`),C=S(()=>$.mode==="reauth"?"Please verify your identity to continue with this action.":u.value==="forbidden"?"You lack the required permissions.":a.value==="remote"?'Confirm from your other device. Or <a href="#" class="inline-link" data-action="local">this device</a>.':E.value&&$.mode!=="reauth"?'Please sign in with your passkey. Or use <a href="#" class="inline-link" data-action="remote">another device</a>.':"Please sign in with your passkey."),F=S(()=>p.value?.ctx.user.display_name||"User");function f(e,r="info",d=3e3){v.show=!0,v.message=e,v.type=r,W&&clearTimeout(W),d>0&&(W=setTimeout(()=>{v.show=!1},d))}async function L(){try{const e=await Q();if(A.value=e,e?.rp_name){const r=$.mode==="reauth"?"Verify Identity":b.value?"Forbidden":"Sign In";document.title=`${e.rp_name} · ${r}`}}catch(e){console.warn("Unable to load settings",e)}}async function M(){try{p.value=await O("/auth/api/validate",{method:"POST"}),b.value&&$.mode!=="reauth"?(u.value="forbidden",g("forbidden",p.value)):u.value="login"}catch(e){p.value=null,u.value="login",e.status!==401&&e.status!==403&&f(H(e),"error",4e3)}}async function U(){if(!E.value||n.value)return;n.value=!0,f("Starting authentication…","info");let e;try{e=await ne.authenticate()}catch(r){n.value=!1;const d=r?.message||"Passkey authentication cancelled",D=d==="Passkey authentication cancelled";f(d,D?"info":"error",4e3),g("auth-error",{message:d,cancelled:D});return}try{await o(e)}catch(r){n.value=!1;const d=r?.message||"Failed to establish session";f(d,"error",4e3),g("auth-error",{message:d,cancelled:!1});return}n.value=!1,g("authenticated",e)}async function c(){if(!n.value){n.value=!0;try{await O("/auth/api/logout",{method:"POST"}),p.value=null,u.value="login",f("Logged out. You can sign in with a different account.","info",3e3)}catch(e){f(H(e),"error",4e3)}finally{n.value=!1}g("logout")}}function s(){const e=window.open("/auth/","passkey_auth_profile");e&&e.focus()}async function o(e){if(!e?.session_token)throw console.error("setSessionCookie called with missing session_token:",e),new Error("Authentication response missing session_token");return await O("/auth/api/set-session",{method:"POST",headers:{Authorization:`Bearer ${e.session_token}`}})}function R(){a.value="remote"}function T(){a.value="local"}async function h(e){f("Authenticated from another device!","success",2e3);try{await o(e)}catch(r){const d=r?.message||"Failed to establish session";f(d,"error",4e3),g("auth-error",{message:d,cancelled:!1});return}g("authenticated",e)}function V(e){f("Registration approved! Redirecting...","success",2e3);const r=le()||"/auth/";window.location.href=`${r}${e}`}function X(e){}function q(e){const r=e.target;if(r.tagName==="A"&&r.classList.contains("inline-link")){e.preventDefault();const d=r.dataset.action;d==="remote"?R():d==="local"&&T()}}return Y(y,e=>{e||oe(()=>ie(k.value))}),J(async()=>{await L(),await M(),y.value=!1,document.addEventListener("click",q)}),K(()=>{document.removeEventListener("click",q)}),I({showMessage:f,isAuthenticated:b,session:p}),(e,r)=>(l(),i("div",We,[v.show?(l(),i("div",Le,[t("div",{class:te(["status",v.type])},_(v.message),3)])):P("",!0),t("main",Me,[y.value?P("",!0):(l(),i("div",Ue,[t("header",Ie,[t("h1",null,_(B.value),1),b.value?(l(),i("p",xe,"👤 "+_(F.value),1)):P("",!0),t("p",{class:"view-lede",innerHTML:C.value},null,8,Be)]),t("section",Fe,[t("div",Ve,[a.value==="local"?(l(),i("div",Oe,[t("div",{class:"button-row center",ref_key:"buttonRow",ref:k},[se(e.$slots,"actions",{loading:n.value,canAuthenticate:E.value,isAuthenticated:b.value,authenticate:U,logout:c,mode:w.mode},()=>[t("button",{class:"btn-secondary",disabled:n.value,onClick:r[0]||(r[0]=d=>e.$emit("back"))},"Back",8,qe),E.value?(l(),i("button",{key:0,class:"btn-primary",disabled:n.value,onClick:U},_(n.value?w.mode==="reauth"?"Verifying…":"Signing in…":w.mode==="reauth"?"Verify":"Login"),9,De)):P("",!0),b.value&&w.mode!=="reauth"?(l(),i("button",{key:1,class:"btn-danger",disabled:n.value,onClick:c},"Logout",8,Ne)):P("",!0),b.value&&w.mode!=="reauth"?(l(),i("button",{key:2,class:"btn-primary",disabled:n.value,onClick:s},"Profile",8,je)):P("",!0)])],512)])):a.value==="remote"?(l(),i("div",He,[ae(Ee,{active:a.value==="remote",onAuthenticated:h,onRegister:V,onCancelled:T,onError:X},null,8,["active"])])):P("",!0)])])]))])]))}},Je=G(ze,[["__scopeId","data-v-5c04d110"]]);export{Je as R};
1
+ import{_ as G,r as m,c as S,w as Y,o as Q,a as J,b as i,d as l,e as t,t as _,F as O,i as j,f as P,m as K,p as Z,Q as ee,g as te,a3 as se,x as ae,a9 as q,a8 as H,G as ne,n as oe,aa as ie,a6 as le}from"./_plugin-vue_export-helper-D2l53SUz.js";import{c as re,s as ce,b as ue,w as z}from"./pow-2N9bxgAo.js";const de={class:"remote-auth-inline"},he={key:0,class:"success-section"},ve={class:"success-message"},fe={key:1,class:"error-section"},me={class:"error-message"},ge={key:2,class:"auth-display"},pe={class:"auth-content"},_e={class:"pairing-code-section"},we={class:"slot-machine","aria-hidden":"true"},ye={class:"slot-word"},ke={class:"site-url"},be={key:3,class:"auth-display"},$e={class:"auth-content"},Ae={key:0,class:"pairing-code-section"},Re={class:"slot-machine stopped"},Se={class:"slot-word"},Ce={class:"site-url"},Pe={class:"waiting-indicator"},Te={__name:"RemoteAuthRequest",props:{active:{type:Boolean,default:!1}},emits:["authenticated","cancelled","error","register"],setup(w,{expose:M,emit:x}){const $=w,g=x,v=m(null),y=m(!1),n=m(null),A=m("connecting"),p=m(null),u=m(["","",""]);let a=null,k=null;const W=S(()=>v.value?v.value.replace(/\./g," "):""),b=S(()=>{if(!p.value)return"";const s=(p.value.auth_site_url||`${location.protocol}//${location.host}/auth/`).replace(/^https?:\/\//,"");return s.endsWith("/")?s.slice(0,-1):s}),E=S(()=>A.value==="authenticating"?"Complete on another device…":"Waiting for authentication…"),B=S(()=>"Authenticated successfully!");function C(){return z[Math.floor(Math.random()*z.length)]}function V(){u.value=[C(),C(),C()];const c=20,s=[setInterval(()=>{const o=[...u.value];o[0]=C(),u.value=o},140),setInterval(()=>{const o=[...u.value];o[1]=C(),u.value=o},170),setInterval(()=>{const o=[...u.value];o[2]=C(),u.value=o},200)];k=s,setTimeout(()=>{s.forEach(o=>clearInterval(o)),k=null},c*170)}function f(){k&&(Array.isArray(k)?k.forEach(c=>clearInterval(c)):clearInterval(k),k=null)}async function L(){n.value=null,y.value=!1,v.value=null,A.value="connecting",V();try{p.value=await K();const c=p.value?.auth_host,s="/auth/ws/remote-auth/request",o=c&&location.host!==c?`//${c}${s}`:s;a=await Z(o);const R=await a.receive_json();if(R.pow){const h=re(R.pow.challenge),F=await ce(h,R.pow.work);a.send_json({pow:ue(F),action:"login"})}const T=await a.receive_json();if(T.status)throw new Error(T.detail||`Failed to create remote auth request: ${T.status}`);for(v.value=T.pairing_code,f(),A.value="waiting";;){const h=await a.receive_json();if(h.status==="locked")A.value="authenticating";else if(h.status==="paired")A.value="authenticating";else if(h.status==="authenticated"){y.value=!0,g("authenticated",{session_token:h.session_token});break}else{if(h.status==="denied")throw new Error("Access denied");if(h.status==="completed"){h.reset_token&&(y.value=!0,g("register",h.reset_token));break}else if(h.status==="error"||h.detail)throw new Error(h.detail||"Remote authentication failed")}}}catch(c){console.error("Remote authentication error:",c);const s=c.message||"Authentication failed";n.value=s,g("error",s)}finally{a&&(a.close(),a=null)}}function U(){L()}function I(){a&&(a.close(),a=null),g("cancelled")}return Y(()=>$.active,c=>{c&&!v.value&&!n.value&&!y.value&&L()}),Q(()=>{$.active&&L()}),J(()=>{a&&(a.close(),a=null),f()}),M({retry:U,cancel:I}),(c,s)=>(l(),i("div",de,[y.value?(l(),i("div",he,[t("p",ve,"✅ "+_(B.value),1)])):n.value?(l(),i("div",fe,[t("p",me,_(n.value),1),t("button",{class:"btn-primary",onClick:U,style:{"margin-top":"0.75rem"}},"Try Again")])):A.value==="connecting"?(l(),i("div",ge,[t("div",pe,[t("div",_e,[s[0]||(s[0]=t("p",{class:"pairing-label"},"Enter the code words:",-1)),t("div",we,[(l(!0),i(O,null,j(u.value,(o,R)=>(l(),i("div",{class:"slot-reel",key:R},[t("div",ye,_(o),1)]))),128))]),t("p",ke,_(b.value),1)])]),s[1]||(s[1]=t("div",{class:"waiting-indicator"},[t("div",{class:"spinner-small"}),t("span",null,"Generating code…")],-1))])):(l(),i("div",be,[t("div",$e,[v.value?(l(),i("div",Ae,[s[2]||(s[2]=t("p",{class:"pairing-label"},"Enter the code words:",-1)),t("div",Re,[(l(!0),i(O,null,j(W.value.split(" "),(o,R)=>(l(),i("div",{class:"slot-reel",key:R},[t("div",Se,_(o),1)]))),128))]),t("p",Ce,_(b.value),1)])):P("",!0)]),t("div",Pe,[s[3]||(s[3]=t("div",{class:"spinner-small"},null,-1)),t("span",null,_(E.value),1)])]))]))}},Ee=G(Te,[["__scopeId","data-v-1280e25b"]]),We={class:"app-shell"},Le={key:0,class:"global-status",style:{display:"block"}},Ue={class:"view-root"},Ie={key:0,class:"surface surface--tight"},Me={class:"view-header center"},xe={key:0,class:"user-line"},Be=["innerHTML"],Ve={class:"section-block"},Fe={class:"section-body center"},qe={key:0,class:"auth-view"},De=["disabled"],Ne=["disabled"],Oe=["disabled"],je=["disabled"],He={key:1,class:"auth-view"},ze={__name:"RestrictedAuth",props:{mode:{type:String,default:"login",validator:w=>["login","reauth","forbidden"].includes(w)}},emits:["authenticated","forbidden","logout","back","home","auth-error"],setup(w,{expose:M,emit:x}){const $=w,g=x,v=ee({show:!1,message:"",type:"info"}),y=m(!0),n=m(!1),A=m(null),p=m(null),u=m("initial"),a=m("local"),k=m(null);let W=null;const b=S(()=>!!p.value),E=S(()=>y.value?!1:$.mode==="reauth"?!0:u.value!=="forbidden"),B=S(()=>$.mode==="reauth"?"🔐 Additional Authentication":u.value==="forbidden"?"🚫 Forbidden":`🔐 ${A.value?.rp_name||location.origin}`),C=S(()=>$.mode==="reauth"?"Please verify your identity to continue with this action.":u.value==="forbidden"?"You lack the required permissions.":a.value==="remote"?'Confirm from your other device. Or <a href="#" class="inline-link" data-action="local">this device</a>.':E.value&&$.mode!=="reauth"?'Please sign in with your passkey. Or use <a href="#" class="inline-link" data-action="remote">another device</a>.':"Please sign in with your passkey."),V=S(()=>p.value?.ctx.user.display_name||"User");function f(e,r="info",d=3e3){v.show=!0,v.message=e,v.type=r,W&&clearTimeout(W),d>0&&(W=setTimeout(()=>{v.show=!1},d))}async function L(){try{const e=await K();if(A.value=e,e?.rp_name){const r=$.mode==="reauth"?"Verify Identity":b.value?"Forbidden":"Sign In";document.title=`${e.rp_name} · ${r}`}}catch(e){console.warn("Unable to load settings",e)}}async function U(){try{p.value=await q("/auth/api/validate",{method:"POST"}),b.value&&$.mode!=="reauth"?(u.value="forbidden",g("forbidden",p.value)):u.value="login"}catch(e){p.value=null,u.value="login",e.status!==401&&e.status!==403&&f(H(e),"error",4e3)}}async function I(){if(!E.value||n.value)return;n.value=!0,f("Starting authentication…","info");let e;try{e=await ne.authenticate()}catch(r){n.value=!1;const d=r?.message||"Passkey authentication cancelled",N=d==="Passkey authentication cancelled";f(d,N?"info":"error",4e3),g("auth-error",{message:d,cancelled:N});return}try{await o(e)}catch(r){n.value=!1;const d=r?.message||"Failed to establish session";f(d,"error",4e3),g("auth-error",{message:d,cancelled:!1});return}n.value=!1,g("authenticated",e)}async function c(){if(!n.value){n.value=!0;try{await q("/auth/api/logout",{method:"POST"}),p.value=null,u.value="login",f("Logged out. You can sign in with a different account.","info",3e3)}catch(e){f(H(e),"error",4e3)}finally{n.value=!1}g("logout")}}function s(){const e=window.open("/auth/","passkey_auth_profile");e&&e.focus()}async function o(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}`}})}function R(){a.value="remote"}function T(){a.value="local"}async function h(e){f("Authenticated from another device!","success",2e3);try{await o(e)}catch(r){const d=r?.message||"Failed to establish session";f(d,"error",4e3),g("auth-error",{message:d,cancelled:!1});return}g("authenticated",e)}function F(e){f("Registration approved! Redirecting...","success",2e3);const r=le()||"/auth/";window.location.href=`${r}${e}`}function X(e){}function D(e){const r=e.target;if(r.tagName==="A"&&r.classList.contains("inline-link")){e.preventDefault();const d=r.dataset.action;d==="remote"?R():d==="local"&&T()}}return Y(y,e=>{e||oe(()=>ie(k.value))}),Q(async()=>{await L(),await U(),y.value=!1,document.addEventListener("click",D)}),J(()=>{document.removeEventListener("click",D)}),M({showMessage:f,isAuthenticated:b,session:p}),(e,r)=>(l(),i("div",We,[v.show?(l(),i("div",Le,[t("div",{class:te(["status",v.type])},_(v.message),3)])):P("",!0),t("main",Ue,[y.value?P("",!0):(l(),i("div",Ie,[t("header",Me,[t("h1",null,_(B.value),1),b.value?(l(),i("p",xe,"👤 "+_(V.value),1)):P("",!0),t("p",{class:"view-lede",innerHTML:C.value},null,8,Be)]),t("section",Ve,[t("div",Fe,[a.value==="local"?(l(),i("div",qe,[t("div",{class:"button-row center",ref_key:"buttonRow",ref:k},[se(e.$slots,"actions",{loading:n.value,canAuthenticate:E.value,isAuthenticated:b.value,authenticate:I,logout:c,mode:w.mode},()=>[t("button",{class:"btn-secondary",disabled:n.value,onClick:r[0]||(r[0]=d=>e.$emit("back"))},"Back",8,De),E.value?(l(),i("button",{key:0,class:"btn-primary",disabled:n.value,onClick:I},_(n.value?w.mode==="reauth"?"Verifying…":"Signing in…":w.mode==="reauth"?"Verify":"Login"),9,Ne)):P("",!0),b.value&&w.mode!=="reauth"?(l(),i("button",{key:1,class:"btn-danger",disabled:n.value,onClick:c},"Logout",8,Oe)):P("",!0),b.value&&w.mode!=="reauth"?(l(),i("button",{key:2,class:"btn-primary",disabled:n.value,onClick:s},"Profile",8,je)):P("",!0)])],512)])):a.value==="remote"?(l(),i("div",He,[ae(Ee,{active:a.value==="remote",onAuthenticated:h,onRegister:F,onCancelled:T,onError:X},null,8,["active"])])):P("",!0)])])]))])]))}},Qe=G(ze,[["__scopeId","data-v-3295ed62"]]);export{Qe as R};