dns-worker 1.0.2-3.3
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.
- package/LICENSE +662 -0
- package/README.md +294 -0
- package/dist/serverfull.mjs +11777 -0
- package/migrations/0000_init.sql +80 -0
- package/migrations/0001_move_lists_to_d1.sql +12 -0
- package/migrations/0002_activity_tracking.sql +7 -0
- package/migrations/0003_fix_profiles_cascade.sql +21 -0
- package/migrations/0004_system_settings.sql +12 -0
- package/migrations/0005_add_bloom_storage.sql +3 -0
- package/migrations/0006_cleanup_profiles_table.sql +18 -0
- package/migrations/0007_user_activity_and_totp.sql +37 -0
- package/migrations/0008_add_profile_key.sql +8 -0
- package/migrations/0009_add_profile_blooms.sql +5 -0
- package/migrations/0010_session_device_info.sql +3 -0
- package/migrations/0011_session_created_at.sql +2 -0
- package/migrations/0012_profile_bloom_chunks.sql +9 -0
- package/migrations/0013_add_session_revoked_to_activity_log.sql +29 -0
- package/migrations/0014_add_session_geo.sql +3 -0
- package/migrations/0015_add_signup_to_activity_log.sql +30 -0
- package/migrations/0016_add_session_rotation_counter.sql +2 -0
- package/migrations/0017_add_access_points.sql +31 -0
- package/migrations/0018_add_list_updated_at.sql +2 -0
- package/migrations/0019_add_list_sync_error.sql +2 -0
- package/migrations/0020_add_session_last_active.sql +5 -0
- package/migrations/0021_add_user_timezone.sql +2 -0
- package/migrations/0022_add_user_locale.sql +2 -0
- package/migrations/0023_add_user_password_version.sql +2 -0
- package/migrations/0024_session_pin_and_pause.sql +37 -0
- package/migrations/0025_add_secret_table.sql +10 -0
- package/migrations/0026_session_lock_config.sql +2 -0
- package/migrations/0027_add_session_id_to_activity_log.sql +2 -0
- package/migrations/0028_rename_session_id_to_session_id_hash.sql +2 -0
- package/migrations/0029_profile_blooms_staging.sql +12 -0
- package/migrations/0030_add_list_blooms.sql +7 -0
- package/migrations/0031_list_blooms_chunks.sql +13 -0
- package/migrations/0032_profile_blooms_cascade.sql +40 -0
- package/migrations/0033_remove_system_secrets.sql +2 -0
- package/migrations/0034_remove_list_entries.sql +2 -0
- package/migrations/0035_add_envelope_encryption_columns.sql +5 -0
- package/migrations/0036_add_cf_proxy_cidrs_setting.sql +7 -0
- package/migrations/0037_optimize_logs_composite_indexes.sql +25 -0
- package/migrations/0038_optimize_logs_table_and_indexes.sql +49 -0
- package/migrations/0039_add_lists_profile_id_index.sql +5 -0
- package/migrations/0040_reduce_logs_indexes_write_cost.sql +9 -0
- package/migrations/0041_create_log_hourly_rollups.sql +21 -0
- package/migrations/0042_add_rule_created_at.sql +3 -0
- package/migrations/0043_create_client_hourly_rollups.sql +26 -0
- package/migrations/0044_create_destination_hourly_rollups.sql +29 -0
- package/migrations/0045_transform_logs_without_rowid.sql +38 -0
- package/migrations/0046_add_passkeys.sql +19 -0
- package/migrations/0047_add_passkey_actions_to_activity_log.sql +35 -0
- package/migrations/0048_add_recovery_key_rotated_to_activity_log.sql +35 -0
- package/migrations/0049_optimize_rollups_and_add_domain_rollups.sql +26 -0
- package/migrations/0050_add_dest_columns_to_logs.sql +6 -0
- package/migrations/0051_add_registration_enabled_setting.sql +2 -0
- package/package.json +71 -0
- package/static/assets/AccountView-BvRvODjN.js +4 -0
- package/static/assets/AnalyticsView-DQ7hDChh.js +2 -0
- package/static/assets/AuthView-Bwv6hbdi.js +2 -0
- package/static/assets/DestinationMap-BEQNbcb-.js +1 -0
- package/static/assets/FilteringView-BWD3e-DS.js +1 -0
- package/static/assets/LogsView-kQy7qTGd.js +5 -0
- package/static/assets/QRCodeCanvas-X07w5x_G.js +2 -0
- package/static/assets/RulesView-3d5hga0L.js +1 -0
- package/static/assets/SettingsView-B9D0kPUF.js +1 -0
- package/static/assets/SetupView-D7d-Gsdr.js +1 -0
- package/static/assets/SwipeableDrawer-B-MfxTWM.js +1 -0
- package/static/assets/TrendChart-B20w7SzD.js +53 -0
- package/static/assets/allPaths-BEI3QvIM.js +1 -0
- package/static/assets/allPathsLoader-DM2JAMeC.js +1 -0
- package/static/assets/browser-icErLjuM.js +1 -0
- package/static/assets/date-C4b8kvr-.js +1 -0
- package/static/assets/de-DE-CXKS_pep.js +10 -0
- package/static/assets/es-ES-B2e3ea35.js +10 -0
- package/static/assets/formatCountryName-CSBD8pP8.js +1 -0
- package/static/assets/fr-FR-1qQHEpoW.js +10 -0
- package/static/assets/getFlagEmoji-_Wxhq0lT.js +1 -0
- package/static/assets/index-7FKlsF79.js +16 -0
- package/static/assets/index-DdQuGqR5.css +2 -0
- package/static/assets/ja-JP-CCVeJXwX.js +10 -0
- package/static/assets/ko-KR-bQ1okpC2.js +10 -0
- package/static/assets/obex_cat_eye_logo-256-CgYNvUIC.webp +0 -0
- package/static/assets/paths-CfqdBnl8.js +1 -0
- package/static/assets/paths-cc-gUzxh.js +1 -0
- package/static/assets/rolldown-runtime-C4Xdq4VV.js +1 -0
- package/static/assets/ru-RU-DeRsms_o.js +10 -0
- package/static/assets/services-fIMx5oSx.js +1 -0
- package/static/assets/splitPathsBySizeLoader-BgBwSA38.js +1 -0
- package/static/assets/vendor-i18next-cO7FDf_e.js +1 -0
- package/static/assets/vendor-icons-16-BgwRBCeU.js +1 -0
- package/static/assets/vendor-icons-20-X5NPN60g.js +1 -0
- package/static/assets/vendor-icons-other-Bme3ywH9.js +2 -0
- package/static/assets/vendor-react-Kt98jRfM.js +11 -0
- package/static/assets/vendor-ui-core-BpucEp_q.js +1 -0
- package/static/assets/vendor-utils-CfYGGC23.js +9 -0
- package/static/assets/vi-VN-BcXfqmzH.js +10 -0
- package/static/assets/zh-CN-D8YK7j27.js +12 -0
- package/static/assets/zh-TW-C2_-uaZk.js +12 -0
- package/static/favicon.webp +0 -0
- package/static/index.html +27 -0
- package/static/manifest.webmanifest +1 -0
- package/static/registerSW.js +1 -0
- package/static/sw.js +1 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
-- Migration 0043: Create client_hourly_rollups table for high-performance client analytics
|
|
2
|
+
-- Reduces D1 read row scans on client queries (getClients) by >98%
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS client_hourly_rollups (
|
|
5
|
+
profile_id TEXT NOT NULL,
|
|
6
|
+
hour_timestamp INTEGER NOT NULL,
|
|
7
|
+
client_ip TEXT NOT NULL,
|
|
8
|
+
geo_country TEXT NOT NULL DEFAULT '',
|
|
9
|
+
access_point_id TEXT NOT NULL DEFAULT '',
|
|
10
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
11
|
+
PRIMARY KEY (profile_id, hour_timestamp, client_ip, geo_country, access_point_id)
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
-- Backfill completed historical hours older than current hour (capped at last 7 days to preserve D1 read quota)
|
|
15
|
+
INSERT OR REPLACE INTO client_hourly_rollups (profile_id, hour_timestamp, client_ip, geo_country, access_point_id, count)
|
|
16
|
+
SELECT
|
|
17
|
+
profile_id,
|
|
18
|
+
(timestamp / 3600) * 3600 AS hour_timestamp,
|
|
19
|
+
client_ip,
|
|
20
|
+
COALESCE(geo_country, '') AS geo_country,
|
|
21
|
+
COALESCE(access_point_id, '') AS access_point_id,
|
|
22
|
+
COUNT(*) AS count
|
|
23
|
+
FROM logs
|
|
24
|
+
WHERE timestamp >= (CAST(strftime('%s', 'now') AS INTEGER) - 7 * 86400)
|
|
25
|
+
AND timestamp < (CAST(strftime('%s', 'now') AS INTEGER) / 3600) * 3600
|
|
26
|
+
GROUP BY profile_id, (timestamp / 3600) * 3600, client_ip, COALESCE(geo_country, ''), COALESCE(access_point_id, '');
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
-- Migration 0044: Create destination_hourly_rollups table for high-performance destination geo analytics
|
|
2
|
+
-- Reduces D1 read row scans on destination queries (getDestinations) by >99% and avoids runtime json_extract()
|
|
3
|
+
|
|
4
|
+
CREATE TABLE IF NOT EXISTS destination_hourly_rollups (
|
|
5
|
+
profile_id TEXT NOT NULL,
|
|
6
|
+
hour_timestamp INTEGER NOT NULL,
|
|
7
|
+
country_code TEXT NOT NULL,
|
|
8
|
+
country TEXT NOT NULL DEFAULT '',
|
|
9
|
+
access_point_id TEXT NOT NULL DEFAULT '',
|
|
10
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
11
|
+
PRIMARY KEY (profile_id, hour_timestamp, country_code, country, access_point_id)
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
-- Backfill completed historical hours older than current hour (capped at last 7 days to preserve D1 read quota)
|
|
15
|
+
INSERT OR REPLACE INTO destination_hourly_rollups (profile_id, hour_timestamp, country_code, country, access_point_id, count)
|
|
16
|
+
SELECT
|
|
17
|
+
profile_id,
|
|
18
|
+
(timestamp / 3600) * 3600 AS hour_timestamp,
|
|
19
|
+
COALESCE(json_extract(dest_geoip, '$.country_code'), '') AS country_code,
|
|
20
|
+
COALESCE(json_extract(dest_geoip, '$.country'), '') AS country,
|
|
21
|
+
COALESCE(access_point_id, '') AS access_point_id,
|
|
22
|
+
COUNT(*) AS count
|
|
23
|
+
FROM logs
|
|
24
|
+
WHERE timestamp >= (CAST(strftime('%s', 'now') AS INTEGER) - 7 * 86400)
|
|
25
|
+
AND timestamp < (CAST(strftime('%s', 'now') AS INTEGER) / 3600) * 3600
|
|
26
|
+
AND dest_geoip IS NOT NULL
|
|
27
|
+
AND json_extract(dest_geoip, '$.country_code') IS NOT NULL
|
|
28
|
+
AND json_extract(dest_geoip, '$.country_code') != ''
|
|
29
|
+
GROUP BY profile_id, (timestamp / 3600) * 3600, COALESCE(json_extract(dest_geoip, '$.country_code'), ''), COALESCE(json_extract(dest_geoip, '$.country'), ''), COALESCE(access_point_id, '');
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
-- Migration 0045: Transform logs table to WITHOUT ROWID clustered table
|
|
2
|
+
-- Reduces D1 write amplification from 2 to 1 row per DNS insert (50% write cost reduction)
|
|
3
|
+
-- Eliminates table-seek reads on time-range queries by clustering data along (profile_id, timestamp, id)
|
|
4
|
+
|
|
5
|
+
-- 1. Create the clustered WITHOUT ROWID logs table
|
|
6
|
+
CREATE TABLE IF NOT EXISTS logs_v2 (
|
|
7
|
+
profile_id TEXT NOT NULL,
|
|
8
|
+
timestamp INTEGER NOT NULL,
|
|
9
|
+
id INTEGER NOT NULL,
|
|
10
|
+
client_ip TEXT,
|
|
11
|
+
geo_country TEXT,
|
|
12
|
+
domain TEXT NOT NULL,
|
|
13
|
+
record_type TEXT NOT NULL,
|
|
14
|
+
action TEXT CHECK(action IN ('PASS', 'BLOCK', 'REDIRECT', 'FAIL')) NOT NULL,
|
|
15
|
+
reason TEXT,
|
|
16
|
+
answer TEXT,
|
|
17
|
+
dest_geoip TEXT,
|
|
18
|
+
ecs TEXT,
|
|
19
|
+
upstream TEXT,
|
|
20
|
+
latency INTEGER,
|
|
21
|
+
access_point_id TEXT,
|
|
22
|
+
PRIMARY KEY (profile_id, timestamp, id)
|
|
23
|
+
) WITHOUT ROWID;
|
|
24
|
+
|
|
25
|
+
-- 2. Migrate existing logs
|
|
26
|
+
INSERT INTO logs_v2 (
|
|
27
|
+
id, profile_id, timestamp, client_ip, geo_country, domain, record_type, action, reason, answer, dest_geoip, ecs, upstream, latency, access_point_id
|
|
28
|
+
)
|
|
29
|
+
SELECT
|
|
30
|
+
id, profile_id, timestamp, client_ip, geo_country, domain, record_type, action, reason, answer, dest_geoip, ecs, upstream, latency, access_point_id
|
|
31
|
+
FROM logs;
|
|
32
|
+
|
|
33
|
+
-- 3. Replace logs table
|
|
34
|
+
DROP TABLE logs;
|
|
35
|
+
ALTER TABLE logs_v2 RENAME TO logs;
|
|
36
|
+
|
|
37
|
+
-- 4. Ensure no redundant secondary indexes exist
|
|
38
|
+
DROP INDEX IF EXISTS idx_logs_profile_time;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
-- Migration 0046: Add passkeys table for WebAuthn/FIDO2 MFA authentication
|
|
2
|
+
|
|
3
|
+
CREATE TABLE IF NOT EXISTS passkeys (
|
|
4
|
+
id TEXT PRIMARY KEY,
|
|
5
|
+
user_id TEXT NOT NULL,
|
|
6
|
+
name TEXT NOT NULL,
|
|
7
|
+
credential_id TEXT NOT NULL UNIQUE,
|
|
8
|
+
public_key TEXT NOT NULL,
|
|
9
|
+
algorithm INTEGER NOT NULL DEFAULT -7,
|
|
10
|
+
sign_count INTEGER NOT NULL DEFAULT 0,
|
|
11
|
+
transports TEXT,
|
|
12
|
+
aaguid TEXT,
|
|
13
|
+
created_at INTEGER NOT NULL,
|
|
14
|
+
last_used_at INTEGER,
|
|
15
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_passkeys_user ON passkeys(user_id);
|
|
19
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_passkeys_credential ON passkeys(credential_id);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- Migration 0047: Add passkey actions to user_activity_log CHECK constraint
|
|
2
|
+
|
|
3
|
+
PRAGMA foreign_keys=off;
|
|
4
|
+
|
|
5
|
+
CREATE TABLE user_activity_log_new (
|
|
6
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7
|
+
user_id TEXT NOT NULL,
|
|
8
|
+
action TEXT NOT NULL CHECK(action IN (
|
|
9
|
+
'signup', 'login_success', 'login_fail', 'logout',
|
|
10
|
+
'password_change_success', 'password_change_fail',
|
|
11
|
+
'totp_verify_success', 'totp_verify_fail',
|
|
12
|
+
'totp_setup', 'totp_removed',
|
|
13
|
+
'recovery_key_used', 'session_revoked',
|
|
14
|
+
'pin_verify_success', 'pin_verify_fail',
|
|
15
|
+
'passkey_registered', 'passkey_deleted',
|
|
16
|
+
'passkey_verify_success', 'passkey_verify_fail'
|
|
17
|
+
)),
|
|
18
|
+
ip_address TEXT,
|
|
19
|
+
user_agent TEXT,
|
|
20
|
+
timestamp INTEGER NOT NULL,
|
|
21
|
+
extra TEXT,
|
|
22
|
+
session_id_hash TEXT,
|
|
23
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
INSERT INTO user_activity_log_new (id, user_id, action, ip_address, user_agent, timestamp, extra, session_id_hash)
|
|
27
|
+
SELECT id, user_id, action, ip_address, user_agent, timestamp, extra, session_id_hash FROM user_activity_log;
|
|
28
|
+
|
|
29
|
+
DROP TABLE user_activity_log;
|
|
30
|
+
|
|
31
|
+
ALTER TABLE user_activity_log_new RENAME TO user_activity_log;
|
|
32
|
+
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_activity_log_user ON user_activity_log(user_id, timestamp DESC);
|
|
34
|
+
|
|
35
|
+
PRAGMA foreign_keys=on;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
-- Migration 0048: Add recovery_key_rotated to user_activity_log CHECK constraint
|
|
2
|
+
|
|
3
|
+
PRAGMA foreign_keys=off;
|
|
4
|
+
|
|
5
|
+
CREATE TABLE user_activity_log_new (
|
|
6
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7
|
+
user_id TEXT NOT NULL,
|
|
8
|
+
action TEXT NOT NULL CHECK(action IN (
|
|
9
|
+
'signup', 'login_success', 'login_fail', 'logout',
|
|
10
|
+
'password_change_success', 'password_change_fail',
|
|
11
|
+
'totp_verify_success', 'totp_verify_fail',
|
|
12
|
+
'totp_setup', 'totp_removed',
|
|
13
|
+
'recovery_key_used', 'recovery_key_rotated', 'session_revoked',
|
|
14
|
+
'pin_verify_success', 'pin_verify_fail',
|
|
15
|
+
'passkey_registered', 'passkey_deleted',
|
|
16
|
+
'passkey_verify_success', 'passkey_verify_fail'
|
|
17
|
+
)),
|
|
18
|
+
ip_address TEXT,
|
|
19
|
+
user_agent TEXT,
|
|
20
|
+
timestamp INTEGER NOT NULL,
|
|
21
|
+
extra TEXT,
|
|
22
|
+
session_id_hash TEXT,
|
|
23
|
+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
INSERT INTO user_activity_log_new (id, user_id, action, ip_address, user_agent, timestamp, extra, session_id_hash)
|
|
27
|
+
SELECT id, user_id, action, ip_address, user_agent, timestamp, extra, session_id_hash FROM user_activity_log;
|
|
28
|
+
|
|
29
|
+
DROP TABLE user_activity_log;
|
|
30
|
+
|
|
31
|
+
ALTER TABLE user_activity_log_new RENAME TO user_activity_log;
|
|
32
|
+
|
|
33
|
+
CREATE INDEX IF NOT EXISTS idx_activity_log_user ON user_activity_log(user_id, timestamp DESC);
|
|
34
|
+
|
|
35
|
+
PRAGMA foreign_keys=on;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
-- Migration 0049: Create domain_hourly_rollups table with zero secondary indexes
|
|
2
|
+
-- 1. Primary key prefix (profile_id, action, hour_timestamp, domain) matches exact query patterns.
|
|
3
|
+
-- 2. WITHOUT ROWID ensures the table is a clustered B-tree, eliminating write amplification (strict 1-write-per-row).
|
|
4
|
+
-- 3. Zero secondary indexes prevents index bloat and doubles write savings.
|
|
5
|
+
-- 4. Avoids heavy historical backfills in migration transactions to prevent D1 timeouts and read quota exhaustion.
|
|
6
|
+
|
|
7
|
+
-- Clean up any experimental secondary indexes if previously created
|
|
8
|
+
DROP INDEX IF EXISTS idx_domain_rollups_query;
|
|
9
|
+
DROP INDEX IF EXISTS idx_domain_rollups_hour;
|
|
10
|
+
DROP INDEX IF EXISTS idx_destination_rollups_hour;
|
|
11
|
+
DROP INDEX IF EXISTS idx_log_rollups_hour;
|
|
12
|
+
DROP INDEX IF EXISTS idx_client_rollups_hour;
|
|
13
|
+
|
|
14
|
+
-- Drop legacy table structure if exists during migration development
|
|
15
|
+
DROP TABLE IF EXISTS domain_hourly_rollups;
|
|
16
|
+
|
|
17
|
+
-- Create the lean clustered WITHOUT ROWID rollups table
|
|
18
|
+
CREATE TABLE IF NOT EXISTS domain_hourly_rollups (
|
|
19
|
+
profile_id TEXT NOT NULL,
|
|
20
|
+
action TEXT NOT NULL CHECK(action IN ('PASS', 'BLOCK', 'REDIRECT', 'FAIL')),
|
|
21
|
+
hour_timestamp INTEGER NOT NULL,
|
|
22
|
+
domain TEXT NOT NULL,
|
|
23
|
+
count INTEGER NOT NULL DEFAULT 0,
|
|
24
|
+
PRIMARY KEY (profile_id, action, hour_timestamp, domain)
|
|
25
|
+
) WITHOUT ROWID;
|
|
26
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- Migration 0050: Add destination geo columns to logs table
|
|
2
|
+
-- Enables native column extraction and eliminates runtime json_extract() overhead
|
|
3
|
+
|
|
4
|
+
ALTER TABLE logs ADD COLUMN dest_country_code TEXT;
|
|
5
|
+
ALTER TABLE logs ADD COLUMN dest_country TEXT;
|
|
6
|
+
ALTER TABLE logs ADD COLUMN dest_isp TEXT;
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dns-worker",
|
|
3
|
+
"version": "1.0.2-3.3",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Privacy-first DNS & DoH Resolver with modern Web Dashboard, built for Cloudflare Workers & Node.js",
|
|
6
|
+
"main": "./dist/serverfull.mjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"dns-worker": "./dist/serverfull.mjs",
|
|
9
|
+
"obexdns": "./dist/serverfull.mjs"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/",
|
|
13
|
+
"static/",
|
|
14
|
+
"migrations/",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22.5.0"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"dev": "npm run db:migrate:dev && concurrently \"npm run ui:dev\" \"wrangler dev\"",
|
|
23
|
+
"start": "npm run build && wrangler dev",
|
|
24
|
+
"start:serverfull": "npm run build:serverfull && node dist/serverfull.mjs",
|
|
25
|
+
"serverfull": "npm run build:serverfull && node dist/serverfull.mjs",
|
|
26
|
+
"build:serverfull": "npm run ui:build && npx esbuild src/serverfull/index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/serverfull.mjs --banner:js=\"#!/usr/bin/env node\" --external:node:sqlite",
|
|
27
|
+
"service-create:linux": "tsx scripts/create-linux-service.ts",
|
|
28
|
+
"deploy": "npm run build && npm run db:migrate:prod && wrangler deploy",
|
|
29
|
+
"deploy:skipdb": "npm run build && wrangler deploy",
|
|
30
|
+
"build": "npm run ui:build",
|
|
31
|
+
"build:pages": "npm run ui:build && npx esbuild src/index.ts --bundle --outfile=static/_worker.js --platform=neutral --format=esm --minify --external:cloudflare:* --external:node:*",
|
|
32
|
+
"postinstall": "npm run ui:install",
|
|
33
|
+
"db:setup": "wrangler d1 create dns_worker_db",
|
|
34
|
+
"db:migrate:dev": "wrangler d1 migrations apply dns_worker_db --local",
|
|
35
|
+
"db:migrate:prod": "echo \"y\" | wrangler d1 migrations apply dns_worker_db --remote",
|
|
36
|
+
"db:status": "wrangler d1 execute dns_worker_db --local --command='SELECT name FROM sqlite_master WHERE type=\"table\"'",
|
|
37
|
+
"test": "tsx test/test_legacy_compat.ts",
|
|
38
|
+
"test:compat": "tsx test/test_legacy_compat.ts",
|
|
39
|
+
"test:serverfull": "tsx test/test_serverfull.ts",
|
|
40
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
41
|
+
"ui:dev": "cd web && npm run dev",
|
|
42
|
+
"ui:build": "cd web && npm run build",
|
|
43
|
+
"ui:install": "cd web && npm install -f"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"dns",
|
|
47
|
+
"cloudflare-workers",
|
|
48
|
+
"doh"
|
|
49
|
+
],
|
|
50
|
+
"author": "Hugo Koo",
|
|
51
|
+
"license": "AGPL-3.0-or-later",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/Obein/DNS-Worker.git"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://github.com/Obein/DNS-Worker#readme",
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/Obein/DNS-Worker/issues"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@cloudflare/workers-types": "^5.20260911.1",
|
|
62
|
+
"@types/node": "^26.6.2",
|
|
63
|
+
"concurrently": "^10.0.5",
|
|
64
|
+
"tsx": "^4.23.13",
|
|
65
|
+
"typescript": "^7.0.2",
|
|
66
|
+
"wrangler": "^4.131.1"
|
|
67
|
+
},
|
|
68
|
+
"overrides": {
|
|
69
|
+
"esbuild": "^0.28.1"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/date-C4b8kvr-.js","assets/index-7FKlsF79.js","assets/vendor-icons-other-Bme3ywH9.js","assets/vendor-icons-16-BgwRBCeU.js","assets/rolldown-runtime-C4Xdq4VV.js","assets/vendor-icons-20-X5NPN60g.js","assets/vendor-react-Kt98jRfM.js","assets/vendor-ui-core-BpucEp_q.js","assets/vendor-utils-CfYGGC23.js","assets/vendor-i18next-cO7FDf_e.js","assets/index-DdQuGqR5.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{i as e}from"./rolldown-runtime-C4Xdq4VV.js";import{$ as t,A as n,B as r,C as i,D as a,E as o,G as s,N as c,R as l,S as u,X as d,Xt as f,Y as p,Z as m,b as h,ct as g,et as _,it as v,j as y,k as b,mt as x,pt as S,rt as C,wt as w,x as T,y as E,z as D}from"./vendor-react-Kt98jRfM.js";import{S as O,b as k,x as A}from"./vendor-icons-other-Bme3ywH9.js";import{r as j}from"./vendor-i18next-cO7FDf_e.js";import{B as M,C as N,D as ee,F as te,H as P,L as F,N as I,O as L,P as ne,R,S as z,V as B,_ as V,d as re,f as H,h as ie,j as U,p as W,r as G,u as ae,v as K,x as q,z as oe}from"./vendor-ui-core-BpucEp_q.js";import{_t as se}from"./vendor-utils-CfYGGC23.js";import{A as ce,At as le,C as J,Ct as ue,D as de,Dt as fe,E as pe,Ft as me,It as he,Lt as ge,Mt as _e,Nt as ve,O as ye,Ot as be,Pt as xe,Rt as Se,St as Ce,Tt as we,Ut as Te,Xt as Ee,_ as De,_t as Oe,a as ke,bt as Ae,c as je,d as Y,f as Me,gt as Ne,ht as Pe,jt as Fe,k as Ie,kt as Le,mt as Re,n as X,o as ze,p as Be,u as Z,vt as Ve,wt as He,xt as Ue,yt as We}from"./index-7FKlsF79.js";import{i as Ge,n as Ke,r as qe,t as Je}from"./QRCodeCanvas-X07w5x_G.js";var Q=e(O(),1),$=e(k(),1);const Ye=({recoveryKeys:e,copied:t,onCopy:r,onDone:i})=>{let{t:a}=f();return(0,$.jsxs)(`div`,{className:`p-4 bg-gray-50 dark:bg-gray-900/50 rounded-lg border border-gray-200 dark:border-gray-800`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2 mb-4`,children:[(0,$.jsx)(n,{size:20,className:`text-green-500`}),(0,$.jsx)(U,{style:{margin:0},children:a(`account.totp.recoveryKeysTitle`,`Save Your Recovery Keys`)})]}),(0,$.jsx)(z,{intent:B.WARNING,className:`mb-4`,children:a(`account.totp.recoveryKeysWarning`,`Store these keys safely. Each key can only be used once.`)}),(0,$.jsx)(`div`,{className:e.length===1?`space-y-2 mb-4`:`grid grid-cols-2 gap-2 mb-4`,children:e.map((e,t)=>(0,$.jsx)(`code`,{className:`block font-mono text-sm sm:text-base font-semibold bg-gray-100 dark:bg-gray-800 text-blue-600 dark:text-blue-400 px-4 py-3 rounded-xl text-center tracking-widest break-all select-all border border-gray-200 dark:border-gray-700`,children:e},t))}),(0,$.jsxs)(`div`,{className:`flex gap-2`,children:[(0,$.jsx)(I,{fill:!0,icon:(0,$.jsx)(g,{size:14}),text:t?a(`account.totp.copied`,`Copied!`):a(`account.totp.copyKeys`,`Copy All Keys`),intent:t?B.SUCCESS:B.NONE,onClick:r}),(0,$.jsx)(I,{fill:!0,intent:B.PRIMARY,text:a(`account.totp.done`,`Done, I've saved them`),onClick:i})]})]})},Xe=({onRefresh:e})=>{let{t}=f(),[n,r]=(0,Q.useState)([]),[i,a]=(0,Q.useState)(!0),[o,s]=(0,Q.useState)(!0),[c,l]=(0,Q.useState)(null),[u,d]=(0,Q.useState)(!1),[p,m]=(0,Q.useState)(!1),[h,g]=(0,Q.useState)(``),[_,v]=(0,Q.useState)(!1),[y,b]=(0,Q.useState)(!1),[x,S]=(0,Q.useState)(``),[C,w]=(0,Q.useState)(null),[T,E]=(0,Q.useState)(``),[D,O]=(0,Q.useState)(!1),[k,A]=(0,Q.useState)(!1),[j,M]=(0,Q.useState)(``),[N,ee]=(0,Q.useState)(null),[te,P]=(0,Q.useState)(!1),[F,I]=(0,Q.useState)(null),L=(0,Q.useCallback)(async()=>{a(!0);try{r(await He()||[])}catch{}finally{a(!1)}},[]);return(0,Q.useEffect)(()=>{s(Ke()),L()},[L]),{passkeys:n,loading:i,supported:o,recoveryKeys:c,setRecoveryKeys:l,copiedKeys:u,handleCopyRecoveryKeys:()=>{c&&navigator.clipboard.writeText(c.join(`
|
|
3
|
+
`)).then(()=>{d(!0),setTimeout(()=>d(!1),2e3)})},isAddOpen:p,setIsAddOpen:m,passkeyName:h,setPasskeyName:g,nameFocused:_,setNameFocused:v,registering:y,addError:x,setAddError:S,handleOpenAdd:()=>{g(``),S(``),v(!1),m(!0)},handleRegister:async n=>{n.preventDefault();let r=h.trim();if(!De(r)){S(t(`account.passkey.formatTip`,`1-30 characters, letters, numbers, hyphens and underscores allowed`));return}b(!0),S(``);try{let t=await ge({name:r,credential:await Ge(await ue())});m(!1),g(``),await L(),e?.(),t?.recovery_keys&&t.recovery_keys.length>0&&l(t.recovery_keys)}catch(e){console.error(`Passkey registration failed:`,e),S(e instanceof Error?e.message:t(`account.passkey.regFailed`,`Registration failed`))}finally{b(!1)}},editingPasskey:C,setEditingPasskey:w,editName:T,setEditName:E,renameFocused:D,setRenameFocused:O,renaming:k,renameError:j,setRenameError:M,handleOpenRename:e=>{w(e),E(e.name),M(``),O(!1)},handleRenameSubmit:async e=>{e.preventDefault();let n=T.trim();if(!(!C||!n)){if(!De(n)){M(t(`account.passkey.formatTip`,`1-30 characters, letters, numbers, hyphens and underscores allowed`));return}A(!0),M(``);try{await fe(C.id,n),w(null),await L()}catch(e){M(e instanceof Error?e.message:t(`common.errorNetwork`))}finally{A(!1)}}},deletingId:N,deleteConfirmOpen:te,setDeleteConfirmOpen:P,targetToDelete:F,handleOpenDelete:e=>{I(e),P(!0)},handleDeleteSubmit:async()=>{if(F){ee(F.id);try{await Ve(F.id),P(!1),I(null),await L(),e?.()}catch(e){let n=e instanceof Error?e.message:t(`common.errorNetwork`);alert(n)}finally{ee(null)}}},fetchPasskeys:L}},Ze=({passkeys:e,loading:t,deletingId:n,onOpenRename:a,onOpenDelete:o})=>{let{t:s}=f();return t?(0,$.jsx)(`div`,{className:`py-6 text-center`,children:(0,$.jsx)(ne,{size:24})}):e.length===0?(0,$.jsxs)(`div`,{className:`py-6 text-center text-sm text-gray-500 dark:text-gray-400 border border-dashed border-gray-200 dark:border-gray-800 rounded-lg`,children:[(0,$.jsx)(_,{size:28,className:`mx-auto mb-2 opacity-40`}),(0,$.jsx)(`p`,{children:s(`account.passkey.empty`,`No passkeys added yet.`)})]}):(0,$.jsx)(`div`,{className:`divide-y divide-gray-100 dark:divide-gray-800 border border-gray-200 dark:border-gray-800 rounded-lg overflow-hidden`,children:e.map(e=>(0,$.jsxs)(`div`,{className:`p-3 sm:p-4 flex items-center justify-between gap-3 hover:bg-gray-50 dark:hover:bg-gray-900/40 transition-colors`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-3 min-w-0`,children:[(0,$.jsx)(`div`,{className:`p-2 bg-purple-50 dark:bg-purple-950/40 text-purple-600 dark:text-purple-400 rounded-lg shrink-0`,children:(0,$.jsx)(_,{size:18})}),(0,$.jsxs)(`div`,{className:`min-w-0`,children:[(0,$.jsx)(`div`,{className:`font-semibold text-sm truncate text-gray-900 dark:text-gray-100`,children:e.name}),(0,$.jsxs)(`div`,{className:`text-xs text-gray-500 dark:text-gray-400 flex flex-wrap gap-x-3 gap-y-1 mt-0.5`,children:[(0,$.jsxs)(`span`,{children:[s(`account.passkey.created`,`Added`),`:`,` `,J(new Date(e.created_at*1e3))]}),e.last_used_at?(0,$.jsxs)(`span`,{children:[s(`account.passkey.lastUsed`,`Last used`),`:`,` `,J(new Date(e.last_used_at*1e3))]}):(0,$.jsx)(`span`,{children:s(`account.passkey.neverUsed`,`Never used`)})]})]})]}),(0,$.jsxs)(`div`,{className:`flex items-center gap-1 shrink-0`,children:[(0,$.jsx)(I,{minimal:!0,small:!0,icon:(0,$.jsx)(r,{size:14}),title:s(`common.rename`,`Rename`),onClick:()=>a(e)}),(0,$.jsx)(I,{minimal:!0,small:!0,intent:B.DANGER,icon:(0,$.jsx)(i,{size:14}),title:s(`common.delete`,`Delete`),loading:n===e.id,onClick:()=>o(e)})]})]},e.id))})},Qe=({isOpen:e,onClose:t,passkeyName:n,setPasskeyName:r,nameFocused:i,setNameFocused:a,registering:o,addError:s,setAddError:c,onSubmit:l})=>{let{t:u}=f();return(0,$.jsx)(L,{isOpen:e,onClose:()=>!o&&t(),title:u(`account.passkey.addTitle`,`Add New Passkey`),className:`max-w-md`,children:(0,$.jsxs)(`form`,{onSubmit:l,children:[(0,$.jsxs)(`div`,{className:F,children:[s&&(0,$.jsx)(z,{intent:B.DANGER,className:`mb-4`,children:s}),(0,$.jsx)(W,{label:u(`account.passkey.nameLabel`,`Passkey Name`),labelFor:`passkey-name-input`,helperText:u(`account.passkey.formatTip`,`1-30 characters, letters, numbers, hyphens and underscores allowed`),children:(0,$.jsx)(K,{content:u(`account.passkey.formatTip`,`1-30 characters, letters, numbers, hyphens and underscores allowed`),isOpen:i,position:M.TOP,intent:B.PRIMARY,className:`w-full`,children:(0,$.jsx)(`div`,{className:`w-full block`,children:(0,$.jsx)(H,{id:`passkey-name-input`,autoFocus:!0,placeholder:u(`account.passkey.namePlaceholder`,`e.g. my_passkey`),value:n,onChange:e=>{r(e.target.value),s&&c(``)},onFocus:()=>a(!0),onBlur:()=>a(!1),disabled:o})})})}),(0,$.jsx)(`p`,{className:`text-xs text-gray-500 dark:text-gray-400`,children:u(`account.passkey.promptNotice`,`After clicking continue, your browser will prompt you to authenticate via Key, face scan, PIN, or hardware key.`)})]}),(0,$.jsx)(`div`,{className:R,children:(0,$.jsxs)(`div`,{className:oe,children:[(0,$.jsx)(I,{text:u(`common.cancel`,`Cancel`),onClick:t,disabled:o}),(0,$.jsx)(I,{intent:B.PRIMARY,type:`submit`,text:u(`account.passkey.continue`,`Continue`),loading:o,disabled:!De(n.trim())||o})]})})]})})},$e=({isOpen:e,onClose:t,editName:n,setEditName:r,renameFocused:i,setRenameFocused:a,renaming:o,renameError:s,setRenameError:c,onSubmit:l})=>{let{t:u}=f();return(0,$.jsx)(L,{isOpen:e,onClose:()=>!o&&t(),title:u(`account.passkey.renameTitle`,`Rename Passkey`),className:`max-w-md`,children:(0,$.jsxs)(`form`,{onSubmit:l,children:[(0,$.jsxs)(`div`,{className:F,children:[s&&(0,$.jsx)(z,{intent:B.DANGER,className:`mb-4`,children:s}),(0,$.jsx)(W,{label:u(`account.passkey.appNameLabel`,`Application (Domain)`),children:(0,$.jsx)(H,{readOnly:!0,disabled:!0,leftIcon:`globe`,value:window.location.hostname})}),(0,$.jsx)(W,{label:u(`account.passkey.nameLabel`,`Passkey Name`),helperText:u(`account.passkey.formatTip`,`1-30 characters, letters, numbers, hyphens and underscores allowed`),children:(0,$.jsx)(K,{content:u(`account.passkey.formatTip`,`1-30 characters, letters, numbers, hyphens and underscores allowed`),isOpen:i,position:M.TOP,intent:B.PRIMARY,className:`w-full`,children:(0,$.jsx)(`div`,{className:`w-full block`,children:(0,$.jsx)(H,{autoFocus:!0,placeholder:u(`account.passkey.namePlaceholder`,`e.g. my_passkey`),value:n,onChange:e=>{r(e.target.value),s&&c(``)},onFocus:()=>a(!0),onBlur:()=>a(!1),disabled:o})})})})]}),(0,$.jsx)(`div`,{className:R,children:(0,$.jsxs)(`div`,{className:oe,children:[(0,$.jsx)(I,{text:u(`common.cancel`,`Cancel`),onClick:t,disabled:o}),(0,$.jsx)(I,{intent:B.PRIMARY,type:`submit`,text:u(`common.save`,`Save`),loading:o,disabled:!De(n.trim())||o})]})})]})})},et=({isOpen:e,onClose:t,targetToDelete:n,deleting:r,onConfirm:i})=>{let{t:a}=f();return(0,$.jsxs)(L,{isOpen:e,onClose:()=>!r&&t(),title:a(`account.passkey.deleteTitle`,`Delete Passkey`),className:`max-w-md`,children:[(0,$.jsx)(`div`,{className:F,children:(0,$.jsx)(`p`,{children:a(`account.passkey.deleteConfirm`,`Are you sure you want to delete passkey "{{name}}"? You will no longer be able to use this passkey for MFA.`,{name:n?.name})})}),(0,$.jsx)(`div`,{className:R,children:(0,$.jsxs)(`div`,{className:oe,children:[(0,$.jsx)(I,{text:a(`common.cancel`,`Cancel`),onClick:t,disabled:r}),(0,$.jsx)(I,{intent:B.DANGER,text:a(`common.delete`,`Delete`),onClick:i,loading:r})]})})]})},tt=({onRefresh:e})=>{let{t:n}=f(),{passkeys:r,loading:i,supported:a,recoveryKeys:o,setRecoveryKeys:s,copiedKeys:c,handleCopyRecoveryKeys:l,isAddOpen:u,setIsAddOpen:d,passkeyName:p,setPasskeyName:m,nameFocused:h,setNameFocused:g,registering:_,addError:v,setAddError:b,handleOpenAdd:x,handleRegister:S,editingPasskey:C,setEditingPasskey:w,editName:T,setEditName:E,renameFocused:O,setRenameFocused:k,renaming:A,renameError:j,setRenameError:M,handleOpenRename:N,handleRenameSubmit:ee,deletingId:te,deleteConfirmOpen:P,setDeleteConfirmOpen:F,targetToDelete:L,handleOpenDelete:ne,handleDeleteSubmit:R}=Xe({onRefresh:e});return o?(0,$.jsx)(Ye,{recoveryKeys:o,copied:c,onCopy:l,onDone:()=>s(null)}):(0,$.jsxs)(`div`,{className:`space-y-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(t,{size:20,className:`text-purple-500`}),(0,$.jsx)(U,{style:{margin:0},children:n(`account.passkey.title`,`Passkeys`)}),(0,$.jsx)(G,{intent:r.length>0?B.SUCCESS:B.NONE,minimal:!0,round:!0,children:r.length>0?n(`account.passkey.count`,{count:r.length,defaultValue:`${r.length} configured`}):n(`account.passkey.none`,`None configured`)})]}),a&&(0,$.jsx)(I,{intent:B.PRIMARY,icon:(0,$.jsx)(D,{size:16}),text:n(`account.passkey.addBtn`,`Add Passkey`),onClick:x})]}),(0,$.jsx)(`p`,{className:`text-sm text-gray-600 dark:text-gray-400 mb-4`,children:n(`account.passkey.desc`,`Authenticate securely with biometrics (Touch ID, Face ID, Windows Hello) or a hardware security key (YubiKey) as an MFA factor.`)}),!a&&(0,$.jsx)(z,{intent:B.WARNING,icon:(0,$.jsx)(y,{size:16}),className:`mb-4`,children:n(`account.passkey.notSupported`,`Your browser or device does not support Passkeys (WebAuthn).`)}),(0,$.jsx)(Ze,{passkeys:r,loading:i,deletingId:te,onOpenRename:N,onOpenDelete:ne}),(0,$.jsx)(Qe,{isOpen:u,onClose:()=>d(!1),passkeyName:p,setPasskeyName:m,nameFocused:h,setNameFocused:g,registering:_,addError:v,setAddError:b,onSubmit:S}),(0,$.jsx)($e,{isOpen:!!C,onClose:()=>w(null),editName:T,setEditName:E,renameFocused:O,setRenameFocused:k,renaming:A,renameError:j,setRenameError:M,onSubmit:ee}),(0,$.jsx)(et,{isOpen:P,onClose:()=>F(!1),targetToDelete:L,deleting:!!te,onConfirm:R})]})},nt=({user:e,disableDialogOpen:t,setDisableDialogOpen:n,disablePassword:r,setDisablePassword:i,disableError:a,setDisableError:s,disableLoading:c,onDisable:l})=>{let{t:u}=f(),[d,p]=Q.useState(!1);return(0,$.jsxs)(`div`,{className:`space-y-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(o,{size:20,className:`text-blue-500`}),(0,$.jsx)(U,{style:{margin:0},children:u(`account.totp.title`,`Authenticator App (TOTP)`)}),(0,$.jsx)(G,{intent:B.SUCCESS,minimal:!0,round:!0,children:u(`account.totp.enabled`,`Enabled`)})]}),(0,$.jsx)(I,{intent:B.DANGER,outlined:!0,icon:(0,$.jsx)(b,{size:14}),text:u(`account.totp.disable`,`Disable Authenticator App (TOTP)`),onClick:()=>n(!0)})]}),(0,$.jsx)(`div`,{className:`space-y-4`,children:(0,$.jsx)(`p`,{className:`text-sm text-gray-600 dark:text-gray-400`,children:u(`account.totp.activeDesc`,`Authenticator app (TOTP) is active and generating 6-digit verification codes for your account.`)})}),(0,$.jsx)(L,{isOpen:t,onClose:()=>{n(!1),i(``),s(``),p(!1)},title:u(`account.totp.disableTitle`,`Disable Authenticator App (TOTP)`),icon:`shield`,children:(0,$.jsxs)(`div`,{className:`p-6 space-y-4`,children:[(0,$.jsx)(z,{intent:B.WARNING,children:u(`account.totp.disableWarning`,`After disabling TOTP, if no Passkeys are configured, your account will only be protected by password.`)}),a&&(0,$.jsx)(z,{intent:B.DANGER,children:a}),!e.totp_skip_password&&(0,$.jsxs)(`form`,{onSubmit:l,className:`space-y-4`,children:[(0,$.jsx)(W,{label:u(`account.currentPassword`),children:(0,$.jsx)(H,{type:d?`text`:`password`,leftIcon:`lock`,value:r,onChange:e=>i(e.target.value),rightElement:(0,$.jsx)(I,{minimal:!0,icon:d?`eye-open`:`eye-off`,onClick:()=>p(!d),title:d?u(`auth.hidePassword`,`Hide password`):u(`auth.showPassword`,`Show password`)}),required:!0})}),(0,$.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,$.jsx)(I,{text:u(`account.cancel`),onClick:()=>n(!1)}),(0,$.jsx)(I,{intent:B.DANGER,text:u(`account.totp.confirmDisable`,`Disable TOTP`),type:`submit`,loading:c})]})]}),e.totp_skip_password&&(0,$.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,$.jsx)(I,{text:u(`account.cancel`),onClick:()=>n(!1)}),(0,$.jsx)(I,{intent:B.DANGER,text:u(`account.totp.confirmDisable`,`Disable TOTP`),loading:c,onClick:l})]})]})})]})},rt=({setupData:e,setupToken:t,setSetupToken:n,setupError:r,setupLoading:i,onStartSetup:s,onConfirmSetup:c,onCancel:l})=>{let{t:u}=f();return(0,$.jsxs)(`div`,{className:`space-y-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(o,{size:20,className:`text-blue-500`}),(0,$.jsx)(U,{style:{margin:0},children:u(`account.totp.title`,`Authenticator App (TOTP)`)}),(0,$.jsx)(G,{minimal:!0,round:!0,intent:B.NONE,children:u(`account.totp.disabled`,`Disabled`)})]}),!e&&(0,$.jsx)(I,{intent:B.PRIMARY,icon:(0,$.jsx)(a,{size:14}),text:u(`account.totp.setupBtn`,`Set Up Authenticator App (TOTP)`),loading:i,onClick:s})]}),e?(0,$.jsxs)(`div`,{className:`space-y-4`,children:[(0,$.jsx)(`p`,{className:`text-sm font-medium`,children:u(`account.totp.scanQR`,`Scan this QR code with your authenticator app:`)}),(0,$.jsxs)(`div`,{className:`flex flex-col items-center gap-3`,children:[(0,$.jsx)(Je,{uri:e.uri}),(0,$.jsxs)(`div`,{className:`text-center`,children:[(0,$.jsx)(`p`,{className:`text-xs text-gray-500 mb-1`,children:u(`account.totp.orEnterManually`,`Or enter the key manually:`)}),(0,$.jsx)(`code`,{className:`text-xs font-mono bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded select-all`,children:e.secret})]})]}),(0,$.jsx)(V,{}),r&&(0,$.jsx)(z,{intent:B.DANGER,children:r}),(0,$.jsxs)(`form`,{onSubmit:c,className:`space-y-3`,children:[(0,$.jsx)(W,{label:u(`account.totp.enterCode`,`Enter the 6-digit code to confirm:`),helperText:u(`account.totp.enterCodeHint`,`This verifies the key was scanned correctly.`),children:(0,$.jsx)(X,{length:6,value:t,onChange:n,disabled:i})}),(0,$.jsxs)(`div`,{className:`flex gap-2`,children:[(0,$.jsx)(I,{text:u(`account.cancel`),onClick:l}),(0,$.jsx)(I,{intent:B.SUCCESS,type:`submit`,loading:i,text:u(`account.totp.activate`,`Activate`),disabled:t.length<6})]})]})]}):(0,$.jsxs)(`div`,{className:`space-y-3`,children:[(0,$.jsx)(`p`,{className:`text-sm text-gray-600 dark:text-gray-400`,children:u(`account.totp.setupDesc`,`Add an extra layer of security. Use Google Authenticator, Authy, or any TOTP app.`)}),r&&(0,$.jsx)(z,{intent:B.DANGER,children:r})]})]})},it=({user:e,onRefresh:t})=>{let{t:n}=f(),[r,i]=(0,Q.useState)(null),[a,o]=(0,Q.useState)(``),[s,c]=(0,Q.useState)(null),[l,u]=(0,Q.useState)(!1),[d,p]=(0,Q.useState)(``),[m,h]=(0,Q.useState)(!1),[g,_]=(0,Q.useState)(!1),[v,y]=(0,Q.useState)(``),[b,x]=(0,Q.useState)(!1),[S,C]=(0,Q.useState)(``),[w,T]=(0,Q.useState)(!1);return s?(0,$.jsx)(Ye,{recoveryKeys:s,copied:m,onCopy:()=>{s&&navigator.clipboard.writeText(s.join(`
|
|
4
|
+
`)).then(()=>{h(!0),setTimeout(()=>h(!1),2e3)})},onDone:()=>c(null)}):e.totp_enabled?(0,$.jsx)(nt,{user:e,settingsLoading:w,onToggleSkipPassword:async e=>{T(!0);try{await he(e),t()}catch{}finally{T(!1)}},disableDialogOpen:g,setDisableDialogOpen:_,disablePassword:v,setDisablePassword:y,disableError:S,setDisableError:C,disableLoading:b,onDisable:async r=>{r.preventDefault(),x(!0),C(``);try{let n=v;e.password_version===2&&(n=await Y(v,e.username)),await We(n),_(!1),y(``),t()}catch(e){C(e.message||n(`common.errorNetwork`))}finally{x(!1)}}}):(0,$.jsx)(rt,{setupData:r,setupToken:a,setSetupToken:o,setupError:d,setupLoading:l,onStartSetup:async()=>{u(!0),p(``);try{i(await _e())}catch(e){p(e.message||n(`common.errorNetwork`))}finally{u(!1)}},onConfirmSetup:async e=>{if(e.preventDefault(),r){u(!0),p(``);try{let e=a.replace(/\s/g,``),n=crypto.randomUUID(),s=new TextEncoder().encode(e+n),l=await crypto.subtle.digest(`SHA-256`,s),u=Array.from(new Uint8Array(l)).map(e=>e.toString(16).padStart(2,`0`)).join(``);c((await Ne({secret:r.secret,totpTokenHash:u,salt:n})).recovery_keys),i(null),o(``),t()}catch(e){p(e.message||n(`common.errorNetwork`))}finally{u(!1)}}},onCancel:()=>{i(null),o(``),p(``)}})};var at=e=>e?.passkeys_count&&e.passkeys_count>0?`passkey`:e?.totp_enabled?`totp`:`password`;const ot=({isOpen:e,onClose:r,user:i,title:a,onVerify:o})=>{let{t:s}=f(),c=!!(i?.passkeys_count&&i.passkeys_count>0),l=!!i?.totp_enabled,u=at(i),[d,p]=(0,Q.useState)(u),[h,g]=(0,Q.useState)(``),[_,v]=(0,Q.useState)(!1),[y,b]=(0,Q.useState)(``),[x,S]=(0,Q.useState)(!1),[C,w]=(0,Q.useState)(``),[T,E]=(0,Q.useState)(e);!T&&e?(E(!0),p(u),g(``),v(!1),b(``),w(``)):T&&!e&&E(!1),(0,Q.useEffect)(()=>{d===`passkey`&&!c?p(l?`totp`:`password`):d===`totp`&&!l&&p(c?`passkey`:`password`)},[c,l,d]);let D=async e=>{if(e&&e.preventDefault(),!h){w(s(`auth.passwordRequired`,`Password is required`));return}S(!0),w(``);try{let e=h;i?.password_version===2&&i?.username&&(e=await Y(h,i.username)),await o({password:e}),r()}catch(e){w(Z(e,s))}finally{S(!1)}},O=async()=>{S(!0),w(``);try{await o({passkeyAssertion:await qe(await Ce())}),r()}catch(e){w(Z(e,s))}finally{S(!1)}},k=async e=>{let t=e||y;if(t.length!==6){w(s(`account.totp.invalidCode`,`Please enter a 6-digit code`));return}S(!0),w(``);try{let e=crypto.randomUUID(),n=new TextEncoder().encode(t+e),i=await crypto.subtle.digest(`SHA-256`,n);await o({totpTokenHash:Array.from(new Uint8Array(i)).map(e=>e.toString(16).padStart(2,`0`)).join(``),totpSalt:e}),r()}catch(e){w(Z(e,s))}finally{S(!1)}};return(0,$.jsx)(L,{isOpen:e,onClose:r,title:a||s(`account.verifyIdentity`,`Security Verification`),icon:`shield`,className:`max-w-md w-full`,children:(0,$.jsxs)(`div`,{className:F,children:[(0,$.jsx)(`p`,{className:`text-sm text-gray-600 dark:text-gray-400 mb-4`,children:s(`account.verifyIdentityDesc`,`To protect your account security, please verify your identity before proceeding.`)}),(c||l)&&(0,$.jsx)(`div`,{className:`flex justify-center mb-5 isolate`,style:{isolation:`isolate`},children:(0,$.jsx)(`div`,{className:`w-full bg-gray-100/70 dark:bg-gray-800/70 p-1 rounded-lg`,children:(0,$.jsxs)(N,{fill:!0,variant:`minimal`,style:{isolation:`isolate`},children:[c&&(0,$.jsx)(I,{small:!0,active:d===`passkey`,intent:d===`passkey`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(t,{size:14}),text:s(`account.mfa.passkey`,`Passkey`),onClick:()=>{p(`passkey`),w(``)}}),l&&(0,$.jsx)(I,{small:!0,active:d===`totp`,intent:d===`totp`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(n,{size:14}),text:s(`account.mfa.totp`,`TOTP`),onClick:()=>{p(`totp`),w(``)}}),(0,$.jsx)(I,{small:!0,active:d===`password`,intent:d===`password`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(m,{size:14}),text:s(`account.mfa.password`,`Password`),onClick:()=>{p(`password`),w(``)}})]})})}),C&&(0,$.jsx)(z,{intent:B.DANGER,className:`mb-4`,children:C}),d===`passkey`&&(0,$.jsxs)(`div`,{className:`text-center py-4 space-y-4`,children:[(0,$.jsx)(`div`,{className:`flex justify-center`,children:(0,$.jsx)(`div`,{className:`p-4 rounded-full bg-blue-50 dark:bg-blue-900/30 text-blue-500`,children:(0,$.jsx)(t,{size:48})})}),(0,$.jsx)(`p`,{className:`text-sm text-gray-600 dark:text-gray-300`,children:s(`account.passkey.verifyPrompt`,`Authenticate using your device's biometric sensor (Face ID, Touch ID, Windows Hello) or security key.`)}),(0,$.jsx)(I,{fill:!0,large:!0,intent:B.PRIMARY,loading:x,onClick:O,icon:(0,$.jsx)(t,{size:16}),text:s(`account.usePasskeyInstead`,`Authenticate with Passkey`)})]}),d===`totp`&&(0,$.jsxs)(`div`,{className:`py-2 space-y-4`,children:[(0,$.jsx)(W,{label:s(`account.totpCode`,`Authenticator Code`),children:(0,$.jsx)(X,{length:6,value:y,onChange:e=>{b(e),e.length===6&&k(e)},disabled:x})}),(0,$.jsx)(I,{fill:!0,intent:B.PRIMARY,loading:x,disabled:y.length!==6,onClick:()=>k(),text:s(`common.confirm`,`Confirm`)})]}),d===`password`&&(0,$.jsxs)(`form`,{onSubmit:D,className:`py-2 space-y-4`,children:[(0,$.jsx)(W,{label:s(`account.currentPassword`,`Current Password`),children:(0,$.jsx)(H,{leftIcon:`lock`,type:_?`text`:`password`,value:h,onChange:e=>g(e.target.value),autoFocus:!0,rightElement:(0,$.jsx)(I,{minimal:!0,icon:_?`eye-open`:`eye-off`,onClick:()=>v(!_)})})}),(0,$.jsx)(I,{fill:!0,intent:B.PRIMARY,type:`submit`,loading:x,text:s(`common.confirm`,`Confirm`)})]})]})})},st=({user:e,onRefresh:n})=>{let{t:r}=f(),[i,a]=(0,Q.useState)(!1),[o,s]=(0,Q.useState)(`view`),[c,u]=(0,Q.useState)(!1),[d,p]=(0,Q.useState)(null),[h,_]=(0,Q.useState)(!1),[b,S]=(0,Q.useState)(!0),[w,T]=(0,Q.useState)(!1),[E,D]=(0,Q.useState)(null),O=!!(e.has_recovery_keys||e.recovery_keys_encrypted),k=!!e.recovery_keys_encrypted,A=()=>{D(null),s(`view`),S(!0),a(!0)},j=()=>{D(null),u(!0)},N=()=>{u(!1),s(`rotate`),a(!0)},te=async e=>{if(o===`view`){let t=await Se(e);t.is_legacy&&(!t.recovery_keys||t.recovery_keys.length===0)?(_(!0),p(null),D({text:r(`account.recoveryKey.legacyNotice`,`Your recovery key is stored as a legacy one-way hash and cannot be decrypted for display. Please rotate your recovery key to generate a new KEK envelope-encrypted key.`),intent:B.WARNING})):(_(!1),p(t.recovery_keys),S(!0))}else o===`rotate`&&(p([(await le(e)).recovery_key]),_(!1),S(!1),D({text:r(`account.recoveryKey.rotateSuccess`,`Recovery key rotated successfully! Please store your new key in a safe place immediately.`),intent:B.SUCCESS}),n())},F=e=>{navigator.clipboard.writeText(e),T(!0),setTimeout(()=>T(!1),2e3)};return(0,$.jsxs)(`div`,{className:`space-y-4`,children:[(0,$.jsxs)(`div`,{className:`flex flex-col sm:flex-row sm:items-center justify-between gap-3`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,$.jsx)(t,{size:18,className:`text-amber-500`}),(0,$.jsx)(U,{style:{margin:0},children:r(`account.recoveryKey.title`,`Emergency Recovery Key`)}),(0,$.jsx)(G,{intent:O?B.SUCCESS:B.NONE,minimal:!0,round:!0,children:O?r(`account.recoveryKey.configured`,`Configured`):r(`account.recoveryKey.notConfigured`,`Not Configured`)}),k&&(0,$.jsx)(K,{content:r(`account.recoveryKey.kekTooltip`,`Protected with AES-256-GCM Envelope Encryption backed by Key Encryption Key (KEK).`),position:M.TOP,children:(0,$.jsx)(G,{intent:B.SUCCESS,minimal:!0,round:!0,icon:(0,$.jsx)(m,{size:12,style:{display:`inline-flex`,alignItems:`center`,marginRight:`4px`}}),children:r(`account.recoveryKey.kekProtected`,`KEK Encrypted`)})})]}),(0,$.jsx)(`div`,{className:`flex items-center gap-2`,children:O&&(0,$.jsx)(I,{small:!0,icon:(0,$.jsx)(C,{size:14}),text:r(`account.recoveryKey.viewBtn`,`View Recovery Key`),onClick:A})})]}),(0,$.jsx)(`p`,{className:`text-sm text-gray-600 dark:text-gray-400`,children:r(`account.recoveryKey.desc`,`An emergency recovery key allows you to regain access or reset your password if you lose all registered Passkeys or Authenticator Apps. Store it securely offline.`)}),E&&(0,$.jsx)(z,{intent:E.intent,className:`my-2`,children:E.text}),h&&(0,$.jsx)(z,{intent:B.WARNING,icon:(0,$.jsx)(y,{size:16}),className:`my-2`,children:(0,$.jsxs)(`div`,{className:`flex flex-col sm:flex-row sm:items-center justify-between gap-2`,children:[(0,$.jsx)(`span`,{children:r(`account.recoveryKey.legacyNotice`,`Your recovery key is stored as a legacy one-way hash and cannot be decrypted for display. Please rotate your recovery key to generate a new KEK envelope-encrypted key.`)}),(0,$.jsx)(I,{small:!0,intent:B.WARNING,icon:(0,$.jsx)(l,{size:14}),text:r(`account.recoveryKey.rotateBtn`,`Rotate Key`),onClick:j,className:`shrink-0`})]})}),d&&d.length>0&&(0,$.jsxs)(q,{elevation:P.ZERO,className:`bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 p-4 space-y-3`,children:[(0,$.jsxs)(`div`,{className:`flex flex-col sm:flex-row sm:items-center justify-between gap-2`,children:[(0,$.jsx)(`span`,{className:`text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider`,children:r(`account.recoveryKey.yourKey`,`Your 30-Digit Recovery Key`)}),(0,$.jsxs)(`div`,{className:`flex items-center gap-1.5 flex-wrap`,children:[(0,$.jsx)(I,{small:!0,minimal:!0,intent:B.WARNING,icon:(0,$.jsx)(l,{size:14}),text:r(`account.recoveryKey.rotateBtn`,`Rotate Key`),onClick:j}),(0,$.jsx)(`div`,{className:`h-4 w-px bg-gray-300 dark:bg-gray-600 mx-1 hidden sm:block`}),(0,$.jsx)(I,{minimal:!0,small:!0,icon:b?(0,$.jsx)(C,{size:14}):(0,$.jsx)(v,{size:14}),onClick:()=>S(!b),title:r(b?`auth.showPassword`:`auth.hidePassword`)}),(0,$.jsx)(I,{minimal:!0,small:!0,icon:w?(0,$.jsx)(x,{size:14,className:`text-green-500`}):(0,$.jsx)(g,{size:14}),onClick:()=>F(d[0]),title:r(`common.copy`)}),(0,$.jsx)(I,{minimal:!0,small:!0,icon:`cross`,onClick:()=>p(null),title:r(`common.close`)})]})]}),(0,$.jsx)(`div`,{className:`p-3 bg-white dark:bg-gray-900 rounded border border-gray-200 dark:border-gray-700 font-mono text-center text-lg sm:text-xl font-bold tracking-widest select-all text-gray-800 dark:text-gray-100`,children:b?`••••••-••••••-••••••-••••••-••••••`:d[0]}),(0,$.jsxs)(`p`,{className:`text-xs text-amber-600 dark:text-amber-400 flex items-center gap-1`,children:[(0,$.jsx)(y,{size:14,className:`shrink-0`}),r(`account.recoveryKey.securityTip`,`Keep this recovery key secret. Anyone with access to this key can regain access to your account.`)]})]}),(0,$.jsx)(ee,{isOpen:c,onConfirm:N,onCancel:()=>u(!1),cancelButtonText:r(`common.cancel`,`Cancel`),confirmButtonText:r(`account.recoveryKey.confirmRotateBtn`,`Proceed to Rotate`),intent:B.DANGER,icon:`warning-sign`,children:(0,$.jsx)(`p`,{children:r(`account.recoveryKey.rotateConfirm`,`Rotating your recovery key will immediately invalidate the current recovery key. You will need to verify your identity to complete this action.`)})}),(0,$.jsx)(ot,{isOpen:i,onClose:()=>a(!1),user:e,title:o===`view`?r(`account.recoveryKey.viewVerifyTitle`,`Verify Identity to View Key`):r(`account.recoveryKey.rotateVerifyTitle`,`Verify Identity to Rotate Key`),onVerify:te})]})},ct=({user:e,onRefresh:t})=>{let{t:r}=f(),[i,a]=(0,Q.useState)(!1),o=!!(e.mfa_enabled??(e.totp_enabled||e.passkeys_count&&e.passkeys_count>0)),s=async e=>{a(!0);try{await xe(e),t()}catch(e){alert(e.message||r(`common.errorNetwork`,`Network error`))}finally{a(!1)}};return(0,$.jsxs)(q,{elevation:P.ONE,className:`space-y-6`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`div`,{className:`flex items-center justify-between mb-3`,children:(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(n,{size:20,className:o?`text-green-500`:`text-gray-400`}),(0,$.jsx)(U,{style:{margin:0},children:r(`account.mfa.title`,`Multi-Factor Authentication (MFA)`)}),(0,$.jsx)(G,{intent:o?B.SUCCESS:B.NONE,minimal:!0,round:!0,children:o?r(`account.mfa.enabled`,`Configured`):r(`account.mfa.notConfigured`,`Not Configured`)})]})}),(0,$.jsx)(`p`,{className:`text-sm text-gray-600 dark:text-gray-400 mb-4`,children:r(`account.mfa.desc`,`Passkeys and Authenticator Apps (TOTP) both serve as MFA authentication methods. Configuring at least one factor protects your account and enables passwordless login and self-service password recovery.`)}),o?(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(V,{className:`my-3`}),(0,$.jsxs)(`div`,{className:`flex flex-col sm:flex-row sm:items-center justify-between gap-2 py-1`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`div`,{className:`font-medium text-sm text-gray-900 dark:text-gray-100`,children:r(`account.mfa.passwordlessTitle`,`Passwordless Login`)}),(0,$.jsx)(`div`,{className:`text-xs text-gray-500 dark:text-gray-400`,children:r(`account.mfa.passwordlessDesc`,`When enabled, logging in will skip the password requirement and verify your identity directly via Passkey or TOTP.`)})]}),(0,$.jsx)(ie,{checked:!!e.totp_skip_password,onChange:e=>s(e.currentTarget.checked),disabled:i,className:`mb-0 shrink-0`})]})]}):(0,$.jsx)(z,{intent:B.PRIMARY,icon:(0,$.jsx)(_,{size:16,style:{display:`inline-flex`,alignItems:`center`,marginRight:`8px`}}),children:r(`account.mfa.unconfiguredHint`,`No MFA method configured yet. Set up either a Passkey or Authenticator App below to safeguard your account and unlock passwordless login and account recovery.`)})]}),(0,$.jsx)(V,{}),(0,$.jsx)(tt,{onRefresh:t}),(0,$.jsx)(V,{}),(0,$.jsx)(it,{user:e,onRefresh:t}),(0,$.jsx)(V,{}),(0,$.jsx)(st,{user:e,onRefresh:t})]})},lt={signup:{label:`account.activity.signup`,icon:(0,$.jsx)(T,{size:14}),intent:B.SUCCESS},login_success:{label:`account.activity.loginSuccess`,icon:(0,$.jsx)(d,{size:14}),intent:B.SUCCESS},login_fail:{label:`account.activity.loginFail`,icon:(0,$.jsx)(u,{size:14}),intent:B.DANGER},logout:{label:`account.activity.logout`,icon:(0,$.jsx)(p,{size:14}),intent:B.NONE},password_change_success:{label:`account.activity.pwChangeSuccess`,icon:(0,$.jsx)(t,{size:14}),intent:B.SUCCESS},password_change_fail:{label:`account.activity.pwChangeFail`,icon:(0,$.jsx)(u,{size:14}),intent:B.DANGER},totp_verify_success:{label:`account.activity.totpVerifySuccess`,icon:(0,$.jsx)(n,{size:14}),intent:B.SUCCESS},totp_verify_fail:{label:`account.activity.totpVerifyFail`,icon:(0,$.jsx)(u,{size:14}),intent:B.DANGER},totp_setup:{label:`account.activity.totpSetup`,icon:(0,$.jsx)(a,{size:14}),intent:B.PRIMARY},totp_removed:{label:`account.activity.totpRemoved`,icon:(0,$.jsx)(b,{size:14}),intent:B.WARNING},recovery_key_used:{label:`account.activity.recoveryKeyUsed`,icon:(0,$.jsx)(t,{size:14}),intent:B.WARNING},recovery_key_rotated:{label:`account.activity.recoveryKeyRotated`,icon:(0,$.jsx)(t,{size:14}),intent:B.WARNING},session_revoked:{label:`account.activity.sessionRevoked`,icon:(0,$.jsx)(p,{size:14}),intent:B.WARNING},passkey_registered:{label:`account.activity.passkeyRegistered`,icon:(0,$.jsx)(t,{size:14}),intent:B.PRIMARY},passkey_deleted:{label:`account.activity.passkeyDeleted`,icon:(0,$.jsx)(b,{size:14}),intent:B.WARNING},passkey_verify_success:{label:`account.activity.passkeyVerifySuccess`,icon:(0,$.jsx)(n,{size:14}),intent:B.SUCCESS},passkey_verify_fail:{label:`account.activity.passkeyVerifyFail`,icon:(0,$.jsx)(u,{size:14}),intent:B.DANGER}},ut=e=>{if(!e)return`desktop`;let t=e.toLowerCase();return t.includes(`mobile`)||t.includes(`android`)||t.includes(`iphone`)||t.includes(`tablet`)||t.includes(`ipad`)?`mobile-phone`:`desktop`},dt=(e,t)=>{if(!e)return t;let n=e;return n.includes(`Edg/`)?`Edge`:n.includes(`Chrome/`)&&!n.includes(`Edg/`)?`Chrome`:n.includes(`Firefox/`)?`Firefox`:n.includes(`Safari/`)&&!n.includes(`Chrome/`)?`Safari`:t},ft=({userAgent:e})=>{let{t}=f();if(!e)return(0,$.jsx)(`span`,{className:`text-gray-500`,children:`—`});let n=dt(e,t(`account.sessions.unknownDevice`,`Unknown Device`));return(0,$.jsxs)(`div`,{children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(te,{icon:ut(e),className:`text-gray-400`}),(0,$.jsx)(`span`,{children:n})]}),(0,$.jsx)(`div`,{className:`text-xs text-gray-400 mt-1 max-w-xs truncate`,title:e,children:e})]})},pt=({hoveredSessionId:e,setHoveredSessionId:t})=>{let{t:n}=f(),[r,i]=(0,Q.useState)([]),[a,o]=(0,Q.useState)(!0),[s,c]=(0,Q.useState)(!0),[u,d]=(0,Q.useState)(!1),p=(0,Q.useCallback)(async e=>{o(!0);try{let t=new URLSearchParams({limit:`20`});e&&t.set(`before`,String(e));let n=await Ae(t.toString());i(e?e=>[...e,...n]:n),c(n.length===20)}catch{}finally{o(!1)}},[]);(0,Q.useEffect)(()=>{p()},[p]);let m=()=>{let e=r[r.length-1];e&&p(e.timestamp)},h=e=>lt[e]??{label:e,icon:(0,$.jsx)(w,{size:14}),intent:B.NONE};return(0,$.jsxs)(q,{elevation:P.ONE,children:[(0,$.jsxs)(`div`,{className:`flex items-center justify-between cursor-pointer`,onClick:()=>d(!u),children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(w,{size:20,className:`text-purple-500`}),(0,$.jsx)(U,{style:{margin:0},children:n(`account.activity.title`,`Account Activity`)}),r.length>0&&(0,$.jsxs)(G,{minimal:!0,round:!0,intent:B.NONE,children:[r.length,s?`+`:``]})]}),(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(I,{minimal:!0,icon:(0,$.jsx)(l,{size:14}),onClick:e=>{e.stopPropagation(),p()}}),(0,$.jsx)(S,{size:16,className:`text-gray-400 transition-transform ${u?`rotate-180`:``}`})]})]}),u&&(0,$.jsx)(`div`,{className:`mt-4`,children:a&&r.length===0?(0,$.jsx)(`div`,{className:`flex justify-center py-8`,children:(0,$.jsx)(ne,{size:24})}):r.length===0?(0,$.jsx)(`p`,{className:`text-sm text-gray-500 text-center py-6`,children:n(`account.activity.empty`,`No activity recorded yet.`)}):(0,$.jsxs)(`div`,{className:`overflow-x-auto`,children:[(0,$.jsxs)(ae,{interactive:!0,striped:!0,className:`w-full text-sm`,children:[(0,$.jsx)(`thead`,{children:(0,$.jsxs)(`tr`,{children:[(0,$.jsx)(`th`,{children:n(`account.activity.action`,`Action`)}),(0,$.jsx)(`th`,{children:n(`account.activity.time`,`Time`)}),(0,$.jsx)(`th`,{children:n(`account.activity.session`,`Session`)}),(0,$.jsx)(`th`,{children:n(`account.activity.ip`,`IP Address`)}),(0,$.jsx)(`th`,{children:n(`account.activity.device`,`Device`)})]})}),(0,$.jsx)(`tbody`,{children:r.map(r=>{let i=h(r.action),a=``,o=r.session_id_hash||``;if(r.extra)try{let e=JSON.parse(r.extra);if(e.reason){let t=`account.activity.reasons.${e.reason}`,r=n(t);a=r&&r!==t?r:e.reason.replace(/[_-]+/g,` `).replace(/\b\w/g,e=>e.toUpperCase())}}catch{}return(0,$.jsxs)(`tr`,{onMouseEnter:()=>{o&&t?.(o)},onMouseLeave:()=>{o&&t?.(null)},className:e&&e===o?`bg-gray-100/80 dark:bg-slate-800/80`:``,children:[(0,$.jsx)(`td`,{className:`align-middle`,children:(0,$.jsxs)(`div`,{className:`flex flex-col items-start gap-1`,children:[(0,$.jsx)(G,{minimal:!0,intent:i.intent,icon:i.icon,children:n(i.label,r.action)}),a&&(0,$.jsx)(`span`,{className:`text-xs text-gray-500 italic ml-1`,children:a})]})}),(0,$.jsx)(`td`,{className:`text-xs text-gray-500 whitespace-nowrap align-middle`,children:J(new Date(r.timestamp*1e3))}),(0,$.jsx)(`td`,{className:`font-mono text-xs text-gray-500 align-middle`,children:o?o.slice(0,8):`—`}),(0,$.jsx)(`td`,{className:`font-mono text-xs text-gray-500 align-middle`,children:r.ip_address||`—`}),(0,$.jsx)(`td`,{className:`align-middle`,children:(0,$.jsx)(ft,{userAgent:r.user_agent||null})})]},r.id)})})]}),s&&(0,$.jsx)(`div`,{className:`flex justify-center mt-3`,children:(0,$.jsx)(I,{minimal:!0,loading:a,text:n(`account.activity.loadMore`,`Load More`),onClick:m})})]})})]})},mt=({hoveredSessionId:e,setHoveredSessionId:t})=>{let{t:n}=f(),[r,i]=(0,Q.useState)([]),[a,o]=(0,Q.useState)(!0),[c,u]=(0,Q.useState)(null),[d,m]=(0,Q.useState)(!1),[h,g]=(0,Q.useState)(!1),_=r.filter(e=>!e.is_current).length,v=(0,Q.useCallback)(async()=>{o(!0);try{let e=await we(),t=Date.now();i((e||[]).filter(e=>e.expires_at*1e3>t))}catch{}finally{o(!1)}},[]);(0,Q.useEffect)(()=>{v()},[v]);let y=async e=>{u(e);try{(await Le(e)).is_current?window.location.reload():i(t=>t.filter(t=>t.id!==e))}catch(e){alert(e.message||n(`account.sessions.revokeFailed`,`Failed to revoke session.`))}finally{u(null)}};return(0,$.jsxs)(q,{elevation:P.ONE,children:[(0,$.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(s,{size:20,className:`text-green-500`}),(0,$.jsx)(U,{style:{margin:0},children:n(`account.sessions.title`,`Active Sessions`)})]}),(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[_>0&&(0,$.jsx)(I,{small:!0,minimal:!0,intent:B.DANGER,icon:(0,$.jsx)(p,{size:14}),text:n(`account.sessions.revokeOthers`,`Revoke Other Sessions`),loading:d,onClick:()=>g(!0)}),(0,$.jsx)(I,{minimal:!0,icon:(0,$.jsx)(l,{size:14}),onClick:()=>v()})]})]}),a?(0,$.jsx)(`div`,{className:`flex justify-center py-4`,children:(0,$.jsx)(ne,{size:24})}):r.length===0?(0,$.jsx)(`p`,{className:`text-sm text-gray-500 text-center py-4`,children:n(`account.sessions.empty`,`No active sessions found.`)}):(0,$.jsx)(`div`,{className:`overflow-x-auto`,children:(0,$.jsxs)(ae,{interactive:!0,striped:!0,className:`w-full text-sm`,children:[(0,$.jsx)(`thead`,{children:(0,$.jsxs)(`tr`,{children:[(0,$.jsx)(`th`,{children:n(`account.sessions.device`,`Device`)}),(0,$.jsx)(`th`,{children:n(`account.sessions.session`,`Session`)}),(0,$.jsx)(`th`,{children:n(`account.sessions.ip`,`IP Address`)}),(0,$.jsx)(`th`,{children:n(`account.sessions.loginTime`,`Login Time`)}),(0,$.jsx)(`th`,{children:n(`account.sessions.expires`,`Expires`)}),(0,$.jsx)(`th`,{children:n(`account.sessions.action`,`Action`)})]})}),(0,$.jsx)(`tbody`,{children:r.map(r=>(0,$.jsxs)(`tr`,{onMouseEnter:()=>t?.(r.id),onMouseLeave:()=>t?.(null),className:e===r.id?`bg-gray-100/80 dark:bg-slate-800/80`:``,children:[(0,$.jsx)(`td`,{children:(0,$.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,$.jsx)(ft,{userAgent:r.user_agent}),r.is_current&&(0,$.jsx)(G,{minimal:!0,intent:B.SUCCESS,className:`mt-0.5`,children:n(`account.sessions.current`,`Current`)})]})}),(0,$.jsx)(`td`,{className:`font-mono text-xs text-gray-500 align-middle`,children:r.id?r.id.slice(0,8):`—`}),(0,$.jsx)(`td`,{className:`font-mono text-xs text-gray-500 align-middle`,children:r.ip_address||`—`}),(0,$.jsx)(`td`,{className:`text-xs text-gray-500 align-middle`,children:r.created_at?J(new Date(r.created_at*1e3)):`—`}),(0,$.jsx)(`td`,{className:`text-xs text-gray-500 align-middle`,children:J(new Date(r.expires_at*1e3))}),(0,$.jsx)(`td`,{className:`align-middle`,children:(0,$.jsx)(I,{small:!0,minimal:!0,intent:B.DANGER,disabled:r.is_current,icon:(0,$.jsx)(p,{size:14}),text:n(`account.sessions.revoke`,`Revoke`),loading:c===r.id,onClick:()=>y(r.id)})})]},r.id))})]})}),(0,$.jsx)(ee,{isOpen:h,cancelButtonText:n(`common.cancel`,`Cancel`),confirmButtonText:n(`account.sessions.confirmRevokeOthers`,`Revoke Other Sessions`),intent:B.DANGER,icon:`log-out`,onCancel:()=>g(!1),onConfirm:async()=>{m(!0);try{await be(),i(e=>e.filter(e=>e.is_current)),g(!1)}catch(e){alert(e.message||n(`account.sessions.revokeFailed`,`Failed to revoke session.`))}finally{m(!1)}},loading:d,children:(0,$.jsx)(`p`,{children:n(`account.sessions.revokeOthersConfirmText`,`Are you sure you want to revoke all other active sessions? All other logged-in devices will be signed out immediately.`)})})]})},ht=({users:e,currentUserId:t,onRefresh:r,registrationEnabled:a=!0,onRefreshSettings:o})=>{let{t:s}=f(),[c,l]=(0,Q.useState)(!1),[u,d]=(0,Q.useState)(``),[p,m]=(0,Q.useState)(``),[h,g]=(0,Q.useState)(`user`),[_,v]=(0,Q.useState)(!1),[y,b]=(0,Q.useState)(!1),[x,S]=(0,Q.useState)(a),[C,w]=(0,Q.useState)(!1);(0,Q.useEffect)(()=>{S(a)},[a]);let E=async e=>{S(e),w(!0);try{await ce({registration_enabled:String(e)}),o?.()}catch(t){console.error(t),S(!e),alert(t.message||s(`common.errorNetwork`,`Network error`))}finally{w(!1)}},D=async()=>{if(!je.test(u)){alert(s(`account.formatTipUsername`));return}if(!ke.test(p)){alert(s(`account.formatTipPassword`));return}v(!0);try{await pe({username:u,password:await Y(p,u),role:h}),l(!1),d(``),m(``),b(!1),r()}catch(e){console.error(e),alert(e.message||s(`common.errorNetwork`))}finally{v(!1)}},O=async e=>{if(confirm(s(`account.confirmDeleteUser`)))try{await de(e),r()}catch(e){console.error(e)}};return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`flex flex-col sm:flex-row sm:items-center justify-between gap-3`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(n,{size:20,className:`text-red-500`}),(0,$.jsx)(U,{style:{margin:0},children:s(`account.userManagement`)})]}),(0,$.jsxs)(`div`,{className:`flex items-center gap-4 flex-wrap`,children:[(0,$.jsx)(ie,{label:s(`account.enableRegistration`,`开放新用户注册`),checked:x,disabled:C,onChange:e=>E(e.currentTarget.checked),className:`mb-0`}),(0,$.jsx)(I,{className:`whitespace-nowrap`,icon:(0,$.jsx)(T,{size:16}),intent:B.SUCCESS,text:s(`account.createUser`),onClick:()=>l(!0)})]})]}),(0,$.jsx)(q,{elevation:P.ONE,className:`p-0 overflow-hidden overflow-x-auto`,children:(0,$.jsxs)(ae,{interactive:!0,striped:!0,className:`w-full`,children:[(0,$.jsx)(`thead`,{children:(0,$.jsxs)(`tr`,{children:[(0,$.jsx)(`th`,{children:s(`account.username`)}),(0,$.jsx)(`th`,{children:s(`account.role`)}),(0,$.jsx)(`th`,{children:`MFA`}),(0,$.jsx)(`th`,{children:`ID`}),(0,$.jsx)(`th`,{children:s(`account.createdAt`)}),(0,$.jsx)(`th`,{children:s(`account.lastActive`)}),(0,$.jsx)(`th`,{children:s(`account.lastResolve`)}),(0,$.jsx)(`th`,{className:`text-right`,children:s(`account.actions`)})]})}),(0,$.jsx)(`tbody`,{children:e.map(e=>(0,$.jsxs)(`tr`,{children:[(0,$.jsx)(`td`,{className:`font-bold`,children:e.username}),(0,$.jsx)(`td`,{children:(0,$.jsx)(G,{minimal:!0,intent:e.role===`admin`?B.DANGER:B.NONE,children:e.role===`admin`?s(`account.roleAdmin`):s(`account.roleUser`)})}),(0,$.jsx)(`td`,{children:(0,$.jsxs)(`div`,{className:`flex flex-wrap gap-1`,children:[!!e.totp_enabled&&(0,$.jsx)(G,{minimal:!0,intent:B.SUCCESS,children:`TOTP`}),!!(e.passkeys_count&&e.passkeys_count>0)&&(0,$.jsx)(G,{minimal:!0,intent:B.PRIMARY,children:`Passkey`}),!e.totp_enabled&&!(e.passkeys_count&&e.passkeys_count>0)&&(0,$.jsx)(G,{minimal:!0,intent:B.NONE,style:{color:`#8a9ba8`},children:s(`account.mfaNone`,`无`)})]})}),(0,$.jsx)(`td`,{children:(0,$.jsx)(`code`,{className:`text-xs`,children:e.id})}),(0,$.jsx)(`td`,{className:`text-xs text-gray-500`,children:e.created_at?J(new Date(e.created_at*1e3)):`-`}),(0,$.jsx)(`td`,{className:`text-xs text-gray-500`,children:e.last_active_at?J(new Date(e.last_active_at*1e3)):`-`}),(0,$.jsx)(`td`,{className:`text-xs text-gray-500`,children:e.last_resolve_at?J(new Date(e.last_resolve_at*1e3)):`-`}),(0,$.jsx)(`td`,{className:`text-right`,children:(0,$.jsx)(`div`,{className:`inline-flex items-center gap-1`,children:(0,$.jsx)(I,{minimal:!0,intent:B.DANGER,icon:(0,$.jsx)(i,{size:14}),disabled:e.id===t,onClick:()=>O(e.id)})})})]},e.id))})]})}),(0,$.jsx)(L,{isOpen:c,onClose:()=>{l(!1),b(!1)},title:s(`account.createNewUser`),icon:`user`,children:(0,$.jsxs)(`div`,{className:`p-6 space-y-4`,children:[(0,$.jsx)(W,{label:s(`account.username`),children:(0,$.jsx)(H,{value:u,onChange:e=>d(e.target.value),placeholder:s(`auth.usernamePlaceholder`)})}),(0,$.jsx)(W,{label:s(`account.initialPassword`),children:(0,$.jsx)(H,{type:y?`text`:`password`,value:p,onChange:e=>m(e.target.value),placeholder:s(`auth.passwordPlaceholder`),rightElement:(0,$.jsx)(I,{minimal:!0,icon:y?`eye-open`:`eye-off`,onClick:()=>b(!y),title:y?s(`auth.hidePassword`,`Hide password`):s(`auth.showPassword`,`Show password`)})})}),(0,$.jsx)(W,{label:s(`account.userRole`),children:(0,$.jsx)(re,{fill:!0,value:h,onChange:e=>g(e.target.value),options:[{label:s(`account.roleUser`),value:`user`},{label:s(`account.roleAdmin`),value:`admin`}]})}),(0,$.jsxs)(`div`,{className:`flex justify-end gap-2 mt-6`,children:[(0,$.jsx)(I,{text:s(`account.cancel`),onClick:()=>l(!1)}),(0,$.jsx)(I,{intent:B.PRIMARY,text:s(`account.createNow`),loading:_,onClick:D})]})]})})]})},gt=({initialSettings:e,onRefresh:t})=>{let{t:n}=f(),[r,i]=(0,Q.useState)(e),[a,o]=(0,Q.useState)(!1),[s,l]=(0,Q.useState)(!1);return Q.useEffect(()=>{i(e)},[e]),(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(c,{size:20,className:`text-gray-500`}),(0,$.jsx)(U,{style:{margin:0},children:n(`account.systemSettings`,`System Settings`)})]}),(0,$.jsxs)(q,{elevation:P.ONE,children:[(0,$.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-4`,children:[(0,$.jsxs)(`div`,{className:`space-y-4`,children:[(0,$.jsx)(U,{className:`text-sm font-bold opacity-70 text-blue-500`,children:`Cloudflare Turnstile`}),(0,$.jsx)(W,{label:`Site Key`,children:(0,$.jsx)(H,{value:r.turnstile_site_key||``,onChange:e=>i({...r,turnstile_site_key:e.target.value}),placeholder:`0x000...`})}),(0,$.jsx)(W,{label:`Secret Key`,children:(0,$.jsx)(H,{type:s?`text`:`password`,value:r.turnstile_secret_key||``,onChange:e=>i({...r,turnstile_secret_key:e.target.value}),placeholder:`0x000...`,rightElement:(0,$.jsx)(I,{minimal:!0,icon:s?`eye-open`:`eye-off`,onClick:()=>l(!s),title:s?n(`auth.hidePassword`,`Hide password`):n(`auth.showPassword`,`Show password`)})})})]}),(0,$.jsxs)(`div`,{className:`space-y-4`,children:[(0,$.jsx)(U,{className:`text-sm font-bold opacity-70 text-green-500`,children:n(`account.featureToggle`,`Feature Toggle`)}),(0,$.jsx)(ie,{label:n(`account.enableTurnstileSignup`,`Enable verification on Signup`),checked:r.turnstile_enabled_signup===`true`,onChange:e=>i({...r,turnstile_enabled_signup:String(e.currentTarget.checked)})}),(0,$.jsx)(ie,{label:n(`account.enableTurnstileLogin`,`Enable verification on Login`),checked:r.turnstile_enabled_login===`true`,onChange:e=>i({...r,turnstile_enabled_login:String(e.currentTarget.checked)})})]})]}),(0,$.jsx)(V,{className:`my-4`}),(0,$.jsx)(`div`,{className:`flex justify-end`,children:(0,$.jsx)(I,{intent:B.PRIMARY,icon:`floppy-disk`,text:n(`common.save`,`Save`),loading:a,onClick:async()=>{o(!0);try{await ce({turnstile_site_key:r.turnstile_site_key||``,turnstile_secret_key:r.turnstile_secret_key||``,turnstile_enabled_signup:r.turnstile_enabled_signup||`false`,turnstile_enabled_login:r.turnstile_enabled_login||`false`}),alert(n(`common.saveSuccess`,`Settings saved`)),t()}catch(e){console.error(e)}finally{o(!1)}}})})]})]})},_t=({isAdmin:e})=>{let{t}=f();return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(U,{className:`text-red-500 flex items-center gap-2`,children:[(0,$.jsx)(i,{size:20}),` `,t(`account.dangerZone`)]}),(0,$.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-6`,children:[(0,$.jsxs)(q,{elevation:P.ONE,children:[(0,$.jsx)(U,{children:t(`account.clearLogs`)}),(0,$.jsx)(`p`,{className:`text-xs opacity-60 mb-4`,children:t(`account.clearLogsDesc`)}),(0,$.jsx)(I,{fill:!0,intent:B.DANGER,text:t(`account.clearLogsBtn`),icon:`trash`,onClick:async()=>{if(confirm(t(`account.confirmClearLogs`)))try{await Re(),alert(t(`account.clearLogsSuccess`))}catch(e){console.error(e)}}})]}),!e&&(0,$.jsxs)(q,{elevation:P.ONE,children:[(0,$.jsx)(U,{children:t(`account.deleteAccount`)}),(0,$.jsx)(`p`,{className:`text-xs opacity-60 mb-4`,children:t(`account.deleteAccountDesc`)}),(0,$.jsx)(I,{fill:!0,intent:B.DANGER,text:t(`account.deleteAccountBtn`),icon:`delete`,onClick:async()=>{if(confirm(t(`account.confirmDeleteAccount`)))try{await Oe(),window.location.href=`/`}catch(e){console.error(e),alert(e.message||t(`common.errorNetwork`))}}})]})]}),(0,$.jsx)(z,{intent:B.WARNING,icon:`info-sign`,title:t(`account.inactivityPolicy`),children:(0,$.jsx)(`p`,{className:`text-sm`,children:t(`account.inactivityDesc`)})})]})},vt=[{label:j(`account.timezoneAuto`,`Auto (Browser Default)`),value:``},{label:`Pacific/Midway (Midway Island) (Standard: UTC-11)`,value:`Pacific/Midway`},{label:`Pacific/Honolulu (Honolulu, Hawaii) (Standard: UTC-10)`,value:`Pacific/Honolulu`},{label:`America/Anchorage (Anchorage, Alaska) (Standard: UTC-9 / DST: UTC-8)`,value:`America/Anchorage`},{label:`America/Los_Angeles (Pacific Time) (Standard: UTC-8 / DST: UTC-7)`,value:`America/Los_Angeles`},{label:`America/Denver (Mountain Time) (Standard: UTC-7 / DST: UTC-6)`,value:`America/Denver`},{label:`America/Chicago (Central Time) (Standard: UTC-6 / DST: UTC-5)`,value:`America/Chicago`},{label:`America/New_York (Eastern Time) (Standard: UTC-5 / DST: UTC-4)`,value:`America/New_York`},{label:`America/Halifax (Atlantic Time) (Standard: UTC-4 / DST: UTC-3)`,value:`America/Halifax`},{label:`America/Argentina/Buenos_Aires (Buenos Aires) (Standard: UTC-3)`,value:`America/Argentina/Buenos_Aires`},{label:`America/Noronha (Fernando de Noronha) (Standard: UTC-2)`,value:`America/Noronha`},{label:`Atlantic/Azores (Azores) (Standard: UTC-1 / DST: UTC+0)`,value:`Atlantic/Azores`},{label:`UTC (Coordinated Universal Time) (Standard: UTC+0)`,value:`UTC`},{label:`Europe/London (London) (Standard: UTC+0 / DST: UTC+1)`,value:`Europe/London`},{label:`Europe/Paris (Paris, Berlin, Rome) (Standard: UTC+1 / DST: UTC+2)`,value:`Europe/Paris`},{label:`Europe/Kyiv (Kyiv, Helsinki, Cairo) (Standard: UTC+2 / DST: UTC+3)`,value:`Europe/Kyiv`},{label:`Europe/Moscow (Moscow) (Standard: UTC+3)`,value:`Europe/Moscow`},{label:`Asia/Dubai (Dubai, Baku) (Standard: UTC+4)`,value:`Asia/Dubai`},{label:`Asia/Karachi (Karachi, Tashkent) (Standard: UTC+5)`,value:`Asia/Karachi`},{label:`Asia/Dhaka (Dhaka, Almaty) (Standard: UTC+6)`,value:`Asia/Dhaka`},{label:`Asia/Bangkok (Bangkok, Jakarta) (Standard: UTC+7)`,value:`Asia/Bangkok`},{label:`Asia/Singapore (Beijing, Shanghai, Singapore, Taipei) (Standard: UTC+8)`,value:`Asia/Singapore`},{label:`Asia/Tokyo (Tokyo, Seoul) (Standard: UTC+9)`,value:`Asia/Tokyo`},{label:`Australia/Sydney (Sydney, Melbourne) (Standard: UTC+10 / DST: UTC+11)`,value:`Australia/Sydney`},{label:`Pacific/Noumea (Nouméa) (Standard: UTC+11)`,value:`Pacific/Noumea`},{label:`Pacific/Auckland (Auckland, Suva) (Standard: UTC+12 / DST: UTC+13)`,value:`Pacific/Auckland`}],yt=({me:e,isEditingUsername:t,setIsEditingUsername:n,editUsername:i,setEditUsername:a,usernameLoading:o,usernameFocused:s,setUsernameFocused:c,onUpdateUsername:l,onUpdateTimezone:u})=>{let{t:d}=f();return(0,$.jsxs)(q,{elevation:P.ONE,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2 mb-4`,children:[(0,$.jsx)(h,{size:20,className:`text-blue-500`}),(0,$.jsx)(U,{style:{margin:0},children:d(`account.personalInfo`)})]}),(0,$.jsxs)(`div`,{className:`space-y-4`,children:[(0,$.jsx)(W,{label:d(`account.username`),children:(0,$.jsx)(`div`,{className:`flex gap-2`,children:t?(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(K,{content:d(`account.formatTipUsername`),isOpen:s,position:M.TOP,intent:B.PRIMARY,className:`w-full`,children:(0,$.jsx)(`div`,{className:`w-full block`,children:(0,$.jsx)(H,{fill:!0,value:i,onChange:e=>a(e.target.value),onFocus:()=>c(!0),onBlur:()=>c(!1),autoFocus:!0})})}),(0,$.jsxs)(N,{children:[(0,$.jsx)(I,{icon:(0,$.jsx)(x,{size:16}),intent:B.SUCCESS,loading:o,onClick:l}),(0,$.jsx)(I,{icon:(0,$.jsx)(E,{size:16}),onClick:()=>{n(!1),a(e?.username||``)}})]})]}):(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(H,{fill:!0,value:e?.username,readOnly:!0}),(0,$.jsx)(I,{icon:(0,$.jsx)(r,{size:16}),onClick:()=>n(!0)})]})})}),(0,$.jsx)(W,{label:d(`account.userId`),children:(0,$.jsx)(H,{leftIcon:`id-number`,value:e?.id,disabled:!0})}),(0,$.jsx)(W,{label:d(`account.timezone`,`Timezone`),children:(0,$.jsx)(re,{fill:!0,value:e?.timezone||``,onChange:e=>u?.(e.target.value||null),options:vt})})]})]})},bt=({me:e,onRefresh:r})=>{let{t:i}=f(),a=!!(e?.passkeys_count&&e.passkeys_count>0),o=!!e?.totp_enabled,[s,c]=(0,Q.useState)(`password`),[l,u]=(0,Q.useState)(``),[d,p]=(0,Q.useState)(!1),[h,g]=(0,Q.useState)(``),[_,v]=(0,Q.useState)(``),[y,b]=(0,Q.useState)(!1),[x,S]=(0,Q.useState)(!1),[C,w]=(0,Q.useState)(!1),[T,E]=(0,Q.useState)(null);return(0,Q.useEffect)(()=>{s===`passkey`&&!a?c(o?`totp`:`password`):s===`totp`&&!o&&c(a?`passkey`:`password`)},[a,o,s]),(0,$.jsxs)(q,{elevation:P.ONE,className:`isolate`,style:{isolation:`isolate`},children:[(0,$.jsxs)(`div`,{className:`flex flex-col sm:flex-row sm:items-center justify-between gap-2 mb-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(t,{size:20,className:`text-orange-500`}),(0,$.jsx)(U,{style:{margin:0},children:i(`account.changePassword`,`Change Password`)})]}),(a||o)&&(0,$.jsx)(`div`,{className:`flex items-center isolate`,style:{isolation:`isolate`},children:(0,$.jsxs)(N,{variant:`minimal`,style:{isolation:`isolate`},children:[(0,$.jsx)(I,{small:!0,active:s===`password`,intent:s===`password`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(m,{size:14}),text:i(`account.mfa.password`,`Password`),onClick:()=>{c(`password`),E(null)}}),a&&(0,$.jsx)(I,{small:!0,active:s===`passkey`,intent:s===`passkey`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(t,{size:14}),text:i(`account.mfa.passkey`,`Passkey`),onClick:()=>{c(`passkey`),E(null)}}),o&&(0,$.jsx)(I,{small:!0,active:s===`totp`,intent:s===`totp`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(n,{size:14}),text:i(`account.mfa.totp`,`TOTP`),onClick:()=>{c(`totp`),E(null)}})]})})]}),T&&(0,$.jsx)(z,{intent:T.intent,className:`mb-4`,children:T.text}),(0,$.jsxs)(`form`,{onSubmit:async t=>{if(t.preventDefault(),!ke.test(_)){E({text:i(`account.formatTipPassword`,`Password must be 12-100 characters and contain letters, numbers, and symbols.`),intent:B.DANGER});return}if(!e?.username){E({text:i(`auth.sessionExpired`,`Session expired. Please log in again.`),intent:B.DANGER});return}w(!0),E(null);try{let t=await Y(_,e.username);if(s===`passkey`)await me({passkeyAssertion:await qe(await Ce()),newPassword:t});else if(s===`totp`){if(h.length!==6){E({text:i(`account.totp.invalidCode`,`Please enter a 6-digit code`),intent:B.DANGER}),w(!1);return}let e=crypto.randomUUID(),n=new TextEncoder().encode(h+e),r=await crypto.subtle.digest(`SHA-256`,n);await me({totpTokenHash:Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,`0`)).join(``),totpSalt:e,newPassword:t})}else{if(!l){E({text:i(`auth.passwordRequired`,`Current password is required`),intent:B.DANGER}),w(!1);return}let n=l;(e.password_version??1)===2&&(n=await Y(l,e.username)),await me({oldPassword:n,newPassword:t})}E({text:i(`account.passwordSuccess`,`Password updated successfully!`),intent:B.SUCCESS}),u(``),g(``),v(``),r&&r()}catch(e){E({text:Z(e,i),intent:B.DANGER})}finally{w(!1)}},className:`space-y-4`,children:[s===`password`&&(0,$.jsx)(W,{label:i(`account.currentPassword`,`Current Password`),children:(0,$.jsx)(H,{leftIcon:`lock`,type:d?`text`:`password`,value:l,onChange:e=>u(e.target.value),rightElement:(0,$.jsx)(I,{minimal:!0,icon:d?`eye-open`:`eye-off`,onClick:()=>p(!d),title:i(d?`auth.hidePassword`:`auth.showPassword`)}),required:!0})}),s===`totp`&&(0,$.jsx)(W,{label:i(`account.totpCode`,`Authenticator Code`),children:(0,$.jsx)(X,{length:6,value:h,onChange:g,disabled:C})}),s===`passkey`&&(0,$.jsx)(z,{intent:B.PRIMARY,children:(0,$.jsx)(`span`,{className:`text-xs`,children:i(`account.passkey.changePwNotice`,`You will be prompted to verify via biometric authentication or your security key when submitting.`)})}),(0,$.jsx)(W,{label:i(`account.newPassword`,`New Password`),children:(0,$.jsx)(K,{content:i(`account.formatTipPassword`,`Password must be 12-100 characters and contain letters, numbers, and symbols.`),isOpen:x,position:M.TOP,intent:B.PRIMARY,className:`w-full`,children:(0,$.jsx)(`div`,{className:`w-full block`,children:(0,$.jsx)(H,{leftIcon:`lock`,type:y?`text`:`password`,value:_,onChange:e=>v(e.target.value),onFocus:()=>S(!0),onBlur:()=>S(!1),rightElement:(0,$.jsx)(I,{minimal:!0,icon:y?`eye-open`:`eye-off`,onClick:()=>b(!y),title:i(y?`auth.hidePassword`:`auth.showPassword`)}),required:!0})})})}),(0,$.jsx)(I,{fill:!0,intent:s===`passkey`?B.PRIMARY:B.WARNING,type:`submit`,loading:C,icon:s===`passkey`?(0,$.jsx)(t,{size:16}):void 0,text:s===`passkey`?i(`account.changePasswordWithPasskey`,`Verify with Passkey & Update`):i(`account.updatePassword`,`Update Password`)})]})]})},xt=({isOpen:e,onClose:r,user:i,onSuccess:a})=>{let{t:o}=f(),s=!!(i?.passkeys_count&&i.passkeys_count>0),c=!!i?.totp_enabled,[l,u]=(0,Q.useState)(`password`),[d,p]=(0,Q.useState)(``),[h,g]=(0,Q.useState)(``),[_,v]=(0,Q.useState)(``),[y,b]=(0,Q.useState)(!1),[x,S]=(0,Q.useState)(``),[C,w]=(0,Q.useState)(!1),[T,E]=(0,Q.useState)(``),D=(0,Q.useRef)(null),O=(0,Q.useRef)(null);(0,Q.useEffect)(()=>{l===`passkey`&&!s?u(c?`totp`:`password`):l===`totp`&&!c&&u(s?`passkey`:`password`)},[s,c,l]);let k=async(e,t)=>{if(e&&e.preventDefault(),d.length!==4||!ze.test(d)){E(o(`auth.pinFormatTip`,`PIN must be exactly 4 digits`));return}if(d!==h){E(o(`auth.pinMatchTip`,`PINs do not match`));return}w(!0),E(``);try{let e=i?.id||sessionStorage.getItem(`dns_worker_user_id`);if(!e){E(o(`auth.sessionExpired`,`Session expired. Logging out...`)),setTimeout(()=>{A()},1500);return}let n=await Me(d,e),r={};if(l===`passkey`)r.passkeyAssertion=await qe(await Ce());else if(l===`totp`){let e=(t||x).replace(/\s/g,``);if(e.length!==6){E(o(`account.totp.invalidCode`,`Please enter a 6-digit code`)),w(!1);return}let n=crypto.randomUUID();r.totpTokenHash=await Be(e,n),r.totpSalt=n}else{if(!_){E(o(`auth.passwordRequired`,`Password is required for verification`)),w(!1);return}let e=_;i?.password_version===2&&i?.username&&(e=await Y(_,i.username)),r.password=e}await Fe(n,r),p(``),g(``),v(``),S(``),a()}catch(e){E(Z(e,o))}finally{w(!1)}},A=()=>{E(``),p(``),g(``),v(``),b(!1),S(``),u(`password`),r()};return(0,$.jsx)(L,{isOpen:e,onClose:A,title:i?.pin_enabled?o(`auth.changePin`,`Change PIN`):o(`auth.configurePin`,`Configure PIN`),icon:`key`,className:`pb-0`,style:{width:`420px`},children:(0,$.jsxs)(`form`,{onSubmit:k,children:[(0,$.jsxs)(`div`,{className:F,children:[T&&(0,$.jsx)(z,{intent:B.DANGER,className:`mb-4`,children:T}),(0,$.jsx)(W,{label:o(`auth.newPin`,`New 4-Digit PIN`),labelFor:`new-pin-input`,helperText:o(`auth.pinHelper`,`Digits only, e.g., 1234`),children:(0,$.jsx)(X,{length:4,value:d,onChange:p,type:`password`,disabled:C,autoFocus:!0,onComplete:()=>D.current?.focus()})}),(0,$.jsx)(W,{label:o(`auth.confirmPin`,`Confirm New PIN`),labelFor:`confirm-pin-input`,children:(0,$.jsx)(X,{ref:D,length:4,value:h,onChange:g,type:`password`,disabled:C,onComplete:()=>{l===`totp`?O.current?.focus():l===`password`&&document.getElementById(`verify-pw-input`)?.focus()}})}),(0,$.jsx)(V,{className:`my-4`}),(0,$.jsxs)(`div`,{className:`flex justify-between items-center mb-3`,children:[(0,$.jsx)(`span`,{className:`font-semibold text-sm`,children:o(`auth.verifyIdentity`,`Verify Identity`)}),(s||c)&&(0,$.jsx)(`div`,{className:`flex items-center isolate`,style:{isolation:`isolate`},children:(0,$.jsxs)(N,{variant:`minimal`,style:{isolation:`isolate`},children:[(0,$.jsx)(I,{small:!0,active:l===`password`,intent:l===`password`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(m,{size:14}),text:o(`account.mfa.password`,`Password`),onClick:()=>{u(`password`),E(``)}}),s&&(0,$.jsx)(I,{small:!0,active:l===`passkey`,intent:l===`passkey`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(t,{size:14}),text:o(`account.mfa.passkey`,`Passkey`),onClick:()=>{u(`passkey`),E(``)}}),c&&(0,$.jsx)(I,{small:!0,active:l===`totp`,intent:l===`totp`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(n,{size:14}),text:o(`account.mfa.totp`,`TOTP`),onClick:()=>{u(`totp`),E(``)}})]})})]}),l===`password`&&(0,$.jsx)(W,{label:o(`auth.currentPassword`,`Current Password`),labelFor:`verify-pw-input`,children:(0,$.jsx)(H,{id:`verify-pw-input`,type:y?`text`:`password`,placeholder:o(`auth.passwordPlaceholder`,`Enter current password`),value:_,onChange:e=>v(e.target.value),leftIcon:`lock`,rightElement:(0,$.jsx)(I,{minimal:!0,icon:y?`eye-open`:`eye-off`,onClick:()=>b(!y),title:y?o(`auth.hidePassword`,`Hide password`):o(`auth.showPassword`,`Show password`)}),required:!0})}),l===`totp`&&(0,$.jsx)(W,{label:o(`auth.totpCode`,`TOTP Code`),labelFor:`verify-totp-input`,children:(0,$.jsx)(X,{ref:O,length:6,value:x,onChange:S,disabled:C,onComplete:e=>k(void 0,e),autoFocus:!0})}),l===`passkey`&&(0,$.jsx)(z,{intent:B.PRIMARY,icon:(0,$.jsx)(t,{size:16}),children:(0,$.jsx)(`span`,{className:`text-xs`,children:o(`account.passkey.submitNotice`,o(`account.passkey.changePwNotice`,`You will be prompted to verify via biometric authentication or your security key when submitting.`))})})]}),(0,$.jsx)(`div`,{className:R,children:(0,$.jsxs)(`div`,{className:oe,children:[(0,$.jsx)(I,{onClick:A,children:o(`common.cancel`,`Cancel`)}),(0,$.jsx)(I,{type:`submit`,intent:B.PRIMARY,loading:C,children:o(`common.save`,`Save`)})]})})]})})},St=({isOpen:e,onClose:r,user:i,onSuccess:a})=>{let{t:o}=f(),s=!!(i?.passkeys_count&&i.passkeys_count>0),c=!!i?.totp_enabled,[l,u]=(0,Q.useState)(`password`),[d,p]=(0,Q.useState)(``),[h,g]=(0,Q.useState)(!1),[_,v]=(0,Q.useState)(``),[b,x]=(0,Q.useState)(!1),[S,C]=(0,Q.useState)(``);(0,Q.useEffect)(()=>{l===`passkey`&&!s?u(c?`totp`:`password`):l===`totp`&&!c&&u(s?`passkey`:`password`)},[s,c,l]);let w=async(e,t)=>{e&&e.preventDefault(),x(!0),C(``);try{let e={};if(l===`passkey`)e.passkeyAssertion=await qe(await Ce());else if(l===`totp`){let n=(t||_).replace(/\s/g,``);if(n.length!==6){C(o(`account.totp.invalidCode`,`Please enter a 6-digit code`)),x(!1);return}let r=crypto.randomUUID();e.totpTokenHash=await Be(n,r),e.totpSalt=r}else{if(!d){C(o(`auth.passwordRequired`,`Password is required for verification`)),x(!1);return}let t=d;i?.password_version===2&&i?.username&&(t=await Y(d,i.username)),e.password=t}await Pe(e),p(``),v(``),a()}catch(e){C(Z(e,o))}finally{x(!1)}},T=()=>{C(``),p(``),g(!1),v(``),u(`password`),r()};return(0,$.jsx)(L,{isOpen:e,onClose:T,title:o(`auth.disablePin`,`Disable Session Lock`),icon:`trash`,className:`pb-0`,style:{width:`420px`},children:(0,$.jsxs)(`form`,{onSubmit:w,children:[(0,$.jsxs)(`div`,{className:F,children:[S&&(0,$.jsx)(z,{intent:B.DANGER,className:`mb-4`,children:S}),(0,$.jsx)(z,{intent:B.WARNING,className:`mb-4`,icon:(0,$.jsx)(y,{size:20}),children:o(`auth.disablePinWarning`,`Disabling the PIN will disable the inactivity session locking feature completely.`)}),(0,$.jsxs)(`div`,{className:`flex justify-between items-center mb-3`,children:[(0,$.jsx)(`span`,{className:`font-semibold text-sm`,children:o(`auth.verifyIdentity`,`Verify Identity`)}),(s||c)&&(0,$.jsx)(`div`,{className:`flex items-center isolate`,style:{isolation:`isolate`},children:(0,$.jsxs)(N,{variant:`minimal`,style:{isolation:`isolate`},children:[(0,$.jsx)(I,{small:!0,active:l===`password`,intent:l===`password`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(m,{size:14}),text:o(`account.mfa.password`,`Password`),onClick:()=>{u(`password`),C(``)}}),s&&(0,$.jsx)(I,{small:!0,active:l===`passkey`,intent:l===`passkey`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(t,{size:14}),text:o(`account.mfa.passkey`,`Passkey`),onClick:()=>{u(`passkey`),C(``)}}),c&&(0,$.jsx)(I,{small:!0,active:l===`totp`,intent:l===`totp`?B.PRIMARY:B.NONE,icon:(0,$.jsx)(n,{size:14}),text:o(`account.mfa.totp`,`TOTP`),onClick:()=>{u(`totp`),C(``)}})]})})]}),l===`password`&&(0,$.jsx)(W,{label:o(`auth.currentPassword`,`Current Password`),labelFor:`disable-pw-input`,children:(0,$.jsx)(H,{id:`disable-pw-input`,type:h?`text`:`password`,placeholder:o(`auth.passwordPlaceholder`,`Enter current password`),value:d,onChange:e=>p(e.target.value),leftIcon:`lock`,rightElement:(0,$.jsx)(I,{minimal:!0,icon:h?`eye-open`:`eye-off`,onClick:()=>g(!h),title:h?o(`auth.hidePassword`,`Hide password`):o(`auth.showPassword`,`Show password`)}),required:!0})}),l===`totp`&&(0,$.jsx)(W,{label:o(`auth.totpCode`,`TOTP Code`),labelFor:`disable-totp-input`,children:(0,$.jsx)(X,{length:6,value:_,onChange:v,disabled:b,onComplete:e=>w(void 0,e),autoFocus:!0})}),l===`passkey`&&(0,$.jsx)(z,{intent:B.PRIMARY,icon:(0,$.jsx)(t,{size:16}),children:(0,$.jsx)(`span`,{className:`text-xs`,children:o(`account.passkey.submitNotice`,o(`account.passkey.changePwNotice`,`You will be prompted to verify via biometric authentication or your security key when submitting.`))})})]}),(0,$.jsx)(`div`,{className:R,children:(0,$.jsxs)(`div`,{className:oe,children:[(0,$.jsx)(I,{onClick:T,children:o(`common.cancel`,`Cancel`)}),(0,$.jsx)(I,{type:`submit`,intent:B.DANGER,loading:b,children:o(`common.disable`,`Disable`)})]})})]})})},Ct=({user:e,onRefresh:t})=>{let{t:r}=f(),[i,a]=(0,Q.useState)(!1),[o,s]=(0,Q.useState)(!1),[c,l]=(0,Q.useState)(!1),u=!!e?.pin_enabled,d=e?.session_lock_timeout||15,p=async e=>{let n=Number(e.currentTarget.value);a(!0);try{await ve({session_lock_timeout:n}),t()}catch(e){console.error(`Failed to change session lock timeout`,e)}finally{a(!1)}},m=()=>{s(!0)};return(0,$.jsxs)(q,{elevation:P.ONE,children:[(0,$.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,$.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,$.jsx)(n,{size:20,className:`text-indigo-600`}),(0,$.jsx)(U,{className:`m-0!`,children:r(`auth.sessionLockTitle`,`Idle Session Lock`)})]}),!u&&(0,$.jsx)(I,{icon:`key`,intent:B.PRIMARY,onClick:m,disabled:i,children:r(`auth.configurePin`,`Configure 4-Digit PIN`)})]}),(0,$.jsx)(`p`,{className:`text-gray-500 text-sm mb-4`,children:r(`auth.sessionLockDesc`,`Lock the interface with a 4-digit PIN when the application is idle to protect active sessions from unauthorized physical access.`)}),(0,$.jsx)(`div`,{className:`flex flex-col gap-4 mb-4`,children:(0,$.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,$.jsx)(`span`,{children:r(`auth.inactivityTimeout`,`Inactivity Timeout`)}),(0,$.jsx)(re,{value:d,onChange:p,disabled:!u||i,options:[{label:r(`auth.timeout1m`,`1 Minute`),value:1},{label:r(`auth.timeout2m`,`2 Minutes`),value:2},{label:r(`auth.timeout5m`,`5 Minutes`),value:5},{label:r(`auth.timeout15m`,`15 Minutes`),value:15},{label:r(`auth.timeout30m`,`30 Minutes`),value:30},{label:r(`auth.timeout60m`,`60 Minutes`),value:60}]})]})}),u&&(0,$.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3`,children:[(0,$.jsx)(I,{icon:`edit`,onClick:m,disabled:i,children:r(`auth.changePin`,`Change PIN`)}),(0,$.jsx)(I,{icon:`trash`,intent:B.DANGER,onClick:()=>{l(!0)},disabled:i,children:r(`auth.disablePin`,`Disable PIN & Lock`)}),(0,$.jsx)(I,{icon:`lock`,intent:B.WARNING,onClick:async()=>{a(!0);try{await Te(),window.dispatchEvent(new Event(`session_paused`))}catch(e){console.error(`Failed to lock session immediately`,e)}finally{a(!1)}},disabled:i,children:r(`auth.lockNow`,`Lock Now`)})]}),(0,$.jsx)(xt,{isOpen:o,onClose:()=>s(!1),user:e,onSuccess:()=>{s(!1),t()}}),(0,$.jsx)(St,{isOpen:c,onClose:()=>l(!1),user:e,onSuccess:()=>{l(!1),t()}})]})},wt=()=>{let[e,t]=(0,Q.useState)(null),[r,i]=(0,Q.useState)([]),[a,o]=(0,Q.useState)(!0),[s,c]=(0,Q.useState)(null),{t:l,i18n:d}=f(),p=Ee(),[m,h]=(0,Q.useState)(!1),[g,_]=(0,Q.useState)(``),[v,y]=(0,Q.useState)(!1),[b,x]=(0,Q.useState)(!1),[S,C]=(0,Q.useState)({}),w=async()=>{try{i(await Ie())}catch(e){console.error(e)}},T=async()=>{try{C(await ye())}catch(e){console.error(e)}},E=(0,Q.useCallback)(async()=>{try{let e=await Ue();if(t(e),_(e.username),window.dispatchEvent(new Event(`user_updated`)),e.timezone){let{setSystemTimeZone:t}=await A(async()=>{let{setSystemTimeZone:e}=await import(`./date-C4b8kvr-.js`);return{setSystemTimeZone:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10]));t(e.timezone)}if(e.locale){let{setSystemLocale:t}=await A(async()=>{let{setSystemLocale:e}=await import(`./date-C4b8kvr-.js`);return{setSystemLocale:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10]));t(e.locale),d.changeLanguage(e.locale)}e.role===`admin`&&(w(),T())}catch(e){console.error(e)}finally{o(!1)}},[]);return(0,Q.useEffect)(()=>{E()},[E]),a?(0,$.jsx)(`div`,{className:`p-8 text-center`,children:l(`common.loading`)}):(0,$.jsxs)(`div`,{className:se(`max-w-5xl mx-auto space-y-8`,p?`p-0`:`px-8`),children:[(0,$.jsxs)(`div`,{className:`flex justify-between items-end`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`h2`,{className:`bp6-heading`,children:l(`account.title`)}),(0,$.jsx)(`p`,{className:`bp6-text-muted`,children:l(`account.subtitle`)})]}),e&&(0,$.jsx)(G,{large:!0,round:!0,intent:e.role===`admin`?B.DANGER:B.PRIMARY,icon:(0,$.jsx)(n,{size:16}),children:e.role===`admin`?l(`account.roleAdmin`):l(`account.roleUser`)})]}),e?.role===`admin`&&e?.jwt_secret_warning&&(0,$.jsx)(z,{intent:B.WARNING,icon:(0,$.jsx)(u,{size:18}),title:l(`account.jwtSecretWarningTitle`),children:(0,$.jsx)(`div`,{className:`text-sm leading-relaxed mt-1`,children:l(`account.jwtSecretWarningDesc`)})}),(0,$.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-6`,children:[(0,$.jsx)(yt,{me:e,isEditingUsername:m,setIsEditingUsername:h,editUsername:g,setEditUsername:_,usernameLoading:v,usernameFocused:b,setUsernameFocused:x,onUpdateUsername:async()=>{if(g===e?.username){h(!1);return}if(!je.test(g)){alert(l(`account.formatTipUsername`));return}y(!0);try{await ve({username:g}),t(e=>e?{...e,username:g}:null),h(!1)}catch(e){console.error(e),alert(e.message||l(`common.errorNetwork`))}finally{y(!1)}},onUpdateTimezone:async e=>{try{await ve({timezone:e||``}),t(t=>t?{...t,timezone:e}:null);let{setSystemTimeZone:n}=await A(async()=>{let{setSystemTimeZone:e}=await import(`./date-C4b8kvr-.js`);return{setSystemTimeZone:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10]));n(e||``)}catch(e){console.error(e),alert(e.message||l(`common.errorNetwork`))}}}),(0,$.jsx)(bt,{me:e,onRefresh:E})]}),e&&(0,$.jsx)(ct,{user:e,onRefresh:E}),e&&(0,$.jsx)(Ct,{user:e,onRefresh:E}),e&&(0,$.jsx)(mt,{hoveredSessionId:s,setHoveredSessionId:c}),e&&(0,$.jsx)(pt,{hoveredSessionId:s,setHoveredSessionId:c}),e?.role===`admin`&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(V,{}),(0,$.jsx)(`div`,{className:`space-y-4`,children:(0,$.jsx)(ht,{users:r,currentUserId:e.id,onRefresh:w,registrationEnabled:S.registration_enabled!==`false`,onRefreshSettings:T})}),(0,$.jsx)(V,{}),(0,$.jsx)(`div`,{className:`space-y-4`,children:(0,$.jsx)(gt,{initialSettings:S,onRefresh:T})})]}),(0,$.jsx)(V,{}),(0,$.jsx)(`div`,{className:`space-y-4`,children:(0,$.jsx)(_t,{isAdmin:e?.role===`admin`})})]})};export{wt as AccountView};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/TrendChart-B20w7SzD.js","assets/index-7FKlsF79.js","assets/vendor-icons-other-Bme3ywH9.js","assets/vendor-icons-16-BgwRBCeU.js","assets/rolldown-runtime-C4Xdq4VV.js","assets/vendor-icons-20-X5NPN60g.js","assets/vendor-react-Kt98jRfM.js","assets/vendor-ui-core-BpucEp_q.js","assets/vendor-utils-CfYGGC23.js","assets/vendor-i18next-cO7FDf_e.js","assets/index-DdQuGqR5.css","assets/DestinationMap-BEQNbcb-.js","assets/formatCountryName-CSBD8pP8.js","assets/getFlagEmoji-_Wxhq0lT.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{i as e}from"./rolldown-runtime-C4Xdq4VV.js";import{D as t,J as n,L as r,Xt as i,gt as a,j as o,tt as s,v as c}from"./vendor-react-Kt98jRfM.js";import{S as l,b as u,x as d}from"./vendor-icons-other-Bme3ywH9.js";import{C as f,H as p,M as m,N as h,P as g,T as ee,V as _,d as v,f as y,o as b,p as x,r as S,u as C,x as w}from"./vendor-ui-core-BpucEp_q.js";import{_t as T}from"./vendor-utils-CfYGGC23.js";import{$ as E,Q as D,Xt as O,et as k}from"./index-7FKlsF79.js";import{t as A}from"./getFlagEmoji-_Wxhq0lT.js";var j=e(l(),1);function te(e,t,n){if(!e)return[];let r={},i=Math.floor(Date.now()/1e3),a,o;switch(t){case`10m`:o=60,a=i-600;break;case`1h`:o=60,a=i-3600;break;case`24h`:o=3600,a=i-24*3600;break;case`7d`:o=86400,a=i-7*86400;break;case`30d`:o=86400,a=i-30*86400;break;case`custom`:if(o=3600,n.start&&n.end)a=Math.floor(new Date(n.start).getTime()/1e3),i=Math.floor(new Date(n.end).getTime()/1e3);else{let t=e.trend.map(e=>e.timestamp);a=t.length?Math.min(...t):i-86400,i=t.length?Math.max(...t):i}break;default:o=3600,a=i-24*3600}a=Math.floor(a/o)*o,i=Math.floor(i/o)*o;for(let e=a;e<=i;e+=o)r[e]={timestamp:e,allowed:0,blocked:0,redirected:0};return e.trend.forEach(e=>{let t=Math.floor(e.timestamp/o)*o;r[t]||(r[t]={timestamp:t,allowed:0,blocked:0,redirected:0}),e.action===`PASS`?r[t].allowed+=e.count:e.action===`BLOCK`?r[t].blocked+=e.count:e.action===`REDIRECT`&&(r[t].redirected+=e.count)}),Object.keys(r).sort((e,t)=>Number(e)-Number(t)).map(e=>r[Number(e)])}var M=e(u(),1);const N=({title:e,value:t,icon:n})=>(0,M.jsxs)(w,{elevation:p.ZERO,className:`flex items-center gap-4 p-4 dark:bg-gray-900 dark:border-gray-800 border border-gray-100 shadow-sm`,children:[(0,M.jsx)(`div`,{className:`p-3 bg-gray-50 dark:bg-gray-800 rounded-lg`,children:n}),(0,M.jsxs)(`div`,{children:[(0,M.jsx)(`div`,{className:`text-xs text-gray-500 font-medium uppercase tracking-wider`,children:e}),(0,M.jsx)(`div`,{className:`text-xl font-bold dark:text-white`,children:t})]})]}),P=({title:e,data:t,intent:n})=>{let{t:r}=i(),a=[{key:`rank`,cellClassName:`w-8 opacity-30 font-mono text-xs`,render:(e,t)=>t+1},{key:`domain`,cellClassName:`font-medium text-sm truncate max-w-50`,render:e=>e.domain},{key:`count`,cellClassName:`text-right`,render:e=>(0,M.jsx)(S,{minimal:!0,intent:n,className:`font-bold`,children:e.count})}];return(0,M.jsxs)(w,{elevation:p.ZERO,className:`dark:bg-gray-900 dark:border-gray-800 border border-gray-100 shadow-sm`,children:[(0,M.jsx)(m,{className:`mb-4 font-bold`,children:e}),(0,M.jsx)(C,{striped:!0,className:`w-full`,children:(0,M.jsxs)(`tbody`,{children:[t.map((e,t)=>(0,M.jsx)(`tr`,{children:a.map(n=>(0,M.jsx)(`td`,{className:n.cellClassName,children:n.render(e,t)},n.key))},t)),t.length===0&&(0,M.jsx)(`tr`,{children:(0,M.jsx)(`td`,{colSpan:a.length,className:`text-center py-8 opacity-50`,children:r(`analytics.noData`)})})]})})]})};var F=(0,j.lazy)(()=>d(()=>import(`./TrendChart-B20w7SzD.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10])).then(e=>({default:e.TrendChart}))),I=(0,j.lazy)(()=>d(()=>import(`./DestinationMap-BEQNbcb-.js`),__vite__mapDeps([11,1,2,3,4,5,6,7,8,9,10,12,13])).then(e=>({default:e.DestinationMap}))),L=()=>(0,M.jsx)(`div`,{className:`h-64 flex items-center justify-center`,children:(0,M.jsx)(g,{size:30})});const R=({profileId:e})=>{let[l,u]=(0,j.useState)(null),[d,R]=(0,j.useState)(!0),{t:z}=i(),ne=O(),[B,V]=(0,j.useState)(`24h`),[H,U]=(0,j.useState)({start:``,end:``}),[W,G]=(0,j.useState)(null),[K,q]=(0,j.useState)([]),[J,Y]=(0,j.useState)(30);(0,j.useEffect)(()=>{D(e).then(e=>q(e)).catch(e=>console.error(`Failed to load access points`,e))},[e]),(0,j.useEffect)(()=>{k(e).then(e=>{try{let t=JSON.parse(e.settings||`{}`);Y(t.log_retention_days===void 0?30:Number(t.log_retention_days))}catch(e){console.error(`Failed to parse settings`,e)}}).catch(e=>console.error(`Failed to fetch profile settings`,e))},[e]);let X=async(t,n,r,i)=>{R(!0);try{let a=`?range=${t}`;if(t===`custom`&&n&&r){let e=Math.floor(new Date(n).getTime()/1e3),t=Math.floor(new Date(r).getTime()/1e3);a+=`&start=${e}&end=${t}`}i&&(a+=`&access_point_id=${i}`);let[o,s,c,l,d,f]=await Promise.all([E(e,`summary`,a),E(e,`trend`,a),E(e,`top_allowed`,a),E(e,`top_blocked`,a),E(e,`clients`,a),E(e,`destinations`,a)]);u({summary:o,trend:s,top_allowed:c,top_blocked:l,clients:d,destinations:f})}catch(e){console.error(`Failed to fetch analytics`,e)}finally{R(!1)}};if((0,j.useEffect)(()=>{B!==`custom`&&X(B,void 0,void 0,W)},[e,B,W]),d&&!l)return(0,M.jsx)(`div`,{className:`p-20 flex justify-center`,children:(0,M.jsx)(g,{size:50})});let re=te(l,B,H),Z=l?.summary.reduce((e,t)=>e+t.count,0)||0,Q=l?.summary.find(e=>e.action===`BLOCK`)?.count||0,ie=l?.summary.find(e=>e.action===`REDIRECT`)?.count||0,ae=Z>0?(Q/Z*100).toFixed(1):`0.0`,$=new Date().toLocaleString(`sv-SE`).replace(` `,`T`).slice(0,16),oe=[{title:z(`analytics.totalQueries`),value:Z.toLocaleString(),icon:(0,M.jsx)(c,{className:`text-blue-500`,size:20})},{title:z(`analytics.blocked`),value:Q.toLocaleString(),icon:(0,M.jsx)(o,{className:`text-red-500`,size:20})},{title:z(`analytics.redirected`),value:ie.toLocaleString(),icon:(0,M.jsx)(r,{className:`text-amber-500`,size:20})},{title:z(`analytics.blockRate`),value:`${ae}%`,icon:(0,M.jsx)(t,{className:`text-green-500`,size:20})},{title:z(`analytics.activeIPs`),value:l?.clients.length.toString()||`0`,icon:(0,M.jsx)(s,{className:`text-purple-500`,size:20})}],se=[{key:`10m`,days:.007},{key:`1h`,days:.0416},{key:`24h`,days:1},{key:`7d`,days:7},{key:`30d`,days:30}].filter(e=>e.days<=J).map(e=>e.key);return(0,M.jsxs)(`div`,{className:T(`max-w-7xl mx-auto space-y-6`,ne?`p-0`:`p-6`),children:[(0,M.jsxs)(`div`,{className:`flex justify-between items-center bg-white dark:bg-gray-900 p-2 rounded-lg shadow-sm border border-gray-100 dark:border-gray-800`,children:[(0,M.jsxs)(f,{variant:`minimal`,children:[se.map(e=>(0,M.jsx)(h,{active:B===e,onClick:()=>V(e),text:e.toUpperCase()},e)),(0,M.jsx)(ee,{content:(0,M.jsxs)(`div`,{className:`p-4 space-y-4 w-64`,children:[(0,M.jsx)(m,{children:z(`analytics.customRange`)}),(0,M.jsx)(x,{label:z(`analytics.startTime`),children:(0,M.jsx)(y,{type:`datetime-local`,max:H.end||$,value:H.start,onChange:e=>U({...H,start:e.target.value})})}),(0,M.jsx)(x,{label:z(`analytics.endTime`),children:(0,M.jsx)(y,{type:`datetime-local`,min:H.start,max:$,value:H.end,onChange:e=>U({...H,end:e.target.value})})}),(0,M.jsx)(h,{fill:!0,intent:_.PRIMARY,text:z(`analytics.apply`),onClick:()=>{V(`custom`),X(`custom`,H.start,H.end,W)}})]}),children:(0,M.jsx)(h,{active:B===`custom`,icon:(0,M.jsx)(a,{size:14,className:`mr-1`}),text:z(`analytics.custom`)})})]}),(0,M.jsxs)(`div`,{className:`flex items-center gap-4`,children:[K.length>0&&(0,M.jsx)(v,{value:W||``,onChange:e=>G(e.target.value||null),options:[{label:`${z(`logs.allAccessPoint`)}`,value:``},...K.map(e=>({label:e.name,value:e.id}))],minimal:!0}),d&&(0,M.jsx)(g,{size:16})]})]}),(0,M.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 gap-2 lg:gap-4`,children:oe.map((e,t)=>(0,M.jsx)(N,{title:e.title,value:e.value,icon:e.icon},t))}),(0,M.jsxs)(w,{elevation:p.ONE,className:`dark:bg-gray-900 dark:border-gray-800 relative`,children:[(0,M.jsxs)(m,{className:`mb-4 font-bold flex items-center gap-2`,children:[z(`analytics.queryTrend`),(0,M.jsx)(S,{minimal:!0,round:!0,children:B===`custom`?z(`analytics.custom`):B.toUpperCase()})]}),(0,M.jsx)(j.Suspense,{fallback:(0,M.jsx)(L,{}),children:(0,M.jsx)(F,{chartData:re,range:B})})]}),(0,M.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-6`,children:[(0,M.jsx)(P,{title:z(`analytics.topAllowed`),data:l?.top_allowed||[],intent:_.SUCCESS}),(0,M.jsx)(P,{title:z(`analytics.topBlocked`),data:l?.top_blocked||[],intent:_.DANGER})]}),(0,M.jsxs)(`div`,{className:`grid gap-6 grid-cols-1`,children:[(0,M.jsx)(b,{title:z(`analytics.destinationDistribution`),icon:(0,M.jsx)(n,{size:16}),children:(0,M.jsx)(j.Suspense,{fallback:(0,M.jsx)(L,{}),children:(0,M.jsx)(I,{destinations:l?.destinations||[],profileId:e||``,range:B,customRange:H,accessPointId:W||void 0})})}),(0,M.jsx)(b,{title:z(`analytics.clientActivity`),icon:(0,M.jsx)(s,{size:16}),children:(0,M.jsxs)(C,{striped:!0,className:`w-full mt-2`,children:[(0,M.jsx)(`thead`,{children:(0,M.jsxs)(`tr`,{children:[(0,M.jsx)(`th`,{className:`text-xs uppercase opacity-60`,children:z(`analytics.ipAddress`)}),(0,M.jsx)(`th`,{className:`text-xs uppercase opacity-60`,children:z(`analytics.location`)}),(0,M.jsx)(`th`,{className:`text-xs uppercase opacity-60 text-right`,children:z(`analytics.queries`)})]})}),(0,M.jsx)(`tbody`,{children:l?.clients.map((e,t)=>(0,M.jsxs)(`tr`,{children:[(0,M.jsx)(`td`,{className:`font-mono text-xs`,children:e.client_ip}),(0,M.jsx)(`td`,{children:(0,M.jsx)(S,{minimal:!0,children:A(e.geo_country)})}),(0,M.jsx)(`td`,{className:`text-right font-bold`,children:e.count})]},t))})]})})]})]})};export{R as AnalyticsView};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{i as e}from"./rolldown-runtime-C4Xdq4VV.js";import{$ as t,E as n,Xt as r,ct as i,et as a,xt as o}from"./vendor-react-Kt98jRfM.js";import{S as s,b as c}from"./vendor-icons-other-Bme3ywH9.js";import"./vendor-i18next-cO7FDf_e.js";import{A as l,B as u,H as d,N as f,S as p,V as m,f as h,m as g,p as _,r as v,v as y,x as b}from"./vendor-ui-core-BpucEp_q.js";import{_t as x}from"./vendor-utils-CfYGGC23.js";import{Bt as S,Ct as C,Et as w,Jt as T,Kt as E,Lt as D,Mt as O,S as k,Vt as A,Wt as j,b as M,d as N,g as P,gt as F,h as I,l as ee,m as L,n as R,p as te,r as ne,t as z,u as B,v as V,x as H,y as U,zt as re}from"./index-7FKlsF79.js";import{i as ie,r as ae,t as W}from"./QRCodeCanvas-X07w5x_G.js";var G=e(s(),1),K=e(c(),1);const q=({username:e,setUsername:t,isTurnstileEnabled:n,turnstileRef:i,loading:a,turnstileStatus:o,onSubmit:s})=>{let{t:c}=r();return(0,K.jsxs)(`form`,{onSubmit:s,className:`space-y-4`,children:[(0,K.jsx)(_,{label:c(`auth.username`),labelFor:`username`,children:(0,K.jsx)(h,{id:`username`,leftIcon:`user`,placeholder:c(`auth.usernamePlaceholder`),size:`large`,className:`rounded-xl w-full`,value:e,onChange:e=>t(e.target.value),autoFocus:!0,required:!0})}),n&&(0,K.jsx)(`div`,{className:`py-2 flex justify-center min-h-16.25`,children:(0,K.jsx)(`div`,{ref:i})}),(0,K.jsx)(f,{fill:!0,size:`large`,intent:m.PRIMARY,type:`submit`,loading:a||o===`verifying`,disabled:!!n&&o!==`success`,className:`mt-6 font-bold py-6 rounded-xl shadow-lg shadow-blue-500/20`,children:o===`verifying`?c(`auth.verifying`):c(`auth.next`,`Next`)})]})},oe=({password:e,setPassword:t,hasMfa:n,onSwitchToMfa:i,loading:a,onSubmit:o,keepLoggedIn:s,setKeepLoggedIn:c,optionalSessionExpirationDays:l})=>{let[u,d]=G.useState(!1),{t:p}=r();return(0,K.jsxs)(`form`,{onSubmit:o,className:`space-y-4`,children:[(0,K.jsx)(_,{label:p(`auth.password`),labelFor:`password`,children:(0,K.jsx)(h,{id:`password`,leftIcon:`lock`,placeholder:p(`auth.passwordPlaceholder`),type:u?`text`:`password`,size:`large`,className:`rounded-xl`,value:e,onChange:e=>t(e.target.value),rightElement:(()=>(0,K.jsxs)(`div`,{className:`flex items-center`,children:[e&&(0,K.jsx)(f,{minimal:!0,icon:`cross`,onClick:()=>t(``)}),(0,K.jsx)(f,{minimal:!0,icon:u?`eye-open`:`eye-off`,onClick:()=>d(!u),title:u?p(`auth.hidePassword`,`Hide password`):p(`auth.showPassword`,`Show password`)})]}))(),autoFocus:!0,required:!0})}),(0,K.jsx)(g,{checked:s,onChange:e=>c(e.currentTarget.checked),label:p(`auth.keepLoggedIn`,`Keep me logged in for {{days}} days`,{days:l}),className:`mt-4 text-left`}),(0,K.jsxs)(`div`,{className:`pt-2 space-y-3`,children:[(0,K.jsx)(f,{fill:!0,size:`large`,intent:m.PRIMARY,type:`submit`,loading:a,className:`font-bold py-6 rounded-xl shadow-lg shadow-blue-500/20`,children:n?p(`auth.next`,`Next`):p(`auth.loginBtn`,`Login`)}),n&&i&&(0,K.jsx)(f,{fill:!0,minimal:!0,size:`large`,type:`button`,disabled:a,onClick:i,className:`font-medium text-blue-600 dark:text-blue-400 py-2.5 rounded-xl transition-colors hover:bg-blue-50 dark:hover:bg-blue-950/30`,children:p(`auth.otherOptions`,`其他选项`)})]})]})},J=({value:e,onChange:t,disabled:n=!1,autoFocus:i=!0,className:a=``})=>{let{t:o}=r(),s=(0,G.useRef)([]),c=(e=>{let t=e.replace(/\D/g,``).slice(0,30),n=[];for(let e=0;e<5;e++)n.push(t.slice(e*6,(e+1)*6));return n})(e);(0,G.useEffect)(()=>{i&&s.current[0]&&s.current[0].focus()},[i]);let l=(e,n)=>{let r=n.replace(/\D/g,``).slice(0,6),i=[...c];i[e]=r,t(i.join(`-`)),r.length===6&&e<4&&s.current[e+1]?.focus()},u=(e,t)=>{if(t.key===`Backspace`&&c[e].length===0&&e>0){t.preventDefault();let n=s.current[e-1];n&&n.focus()}else t.key===`ArrowLeft`&&(t.currentTarget.selectionStart??0)===0&&e>0?(t.preventDefault(),s.current[e-1]?.focus()):t.key===`ArrowRight`&&(t.currentTarget.selectionStart??0)===c[e].length&&e<4&&(t.preventDefault(),s.current[e+1]?.focus())},d=(e,n)=>{let r=n.clipboardData.getData(`text`).replace(/\D/g,``);if(r.length>6){n.preventDefault();let i=[...c],a=0;for(let t=e;t<5&&a<r.length;t++){let e=r.slice(a,a+6);i[t]=e,a+=e.length}t(i.join(`-`));let o=Math.min(4,e+Math.ceil(r.length/6)-1);s.current[o]?.focus()}},f=c.map((e,t)=>e.length===6&&!U(e)?t:-1).filter(e=>e!==-1);return(0,K.jsxs)(`div`,{className:`space-y-2 ${a}`,children:[(0,K.jsx)(`div`,{className:`flex items-center justify-between gap-1 sm:gap-2`,children:c.map((e,t)=>{let r=e.length===6,i=r&&!U(e),a=r&&!i,c=`border-gray-300 dark:border-gray-600 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20`;return i?c=`border-red-500 ring-2 ring-red-500/30 bg-red-50/40 dark:bg-red-950/20 text-red-600 dark:text-red-400`:a&&(c=`border-green-500/80 dark:border-green-500/60 bg-green-50/20 dark:bg-green-950/10 text-gray-900 dark:text-gray-100`),(0,K.jsxs)(G.Fragment,{children:[(0,K.jsx)(`input`,{ref:e=>{s.current[t]=e},type:`text`,inputMode:`numeric`,pattern:`[0-9]*`,maxLength:6,value:e,disabled:n,placeholder:`000000`,onChange:e=>l(t,e.target.value),onKeyDown:e=>u(t,e),onPaste:e=>d(t,e),className:`w-full min-w-0 text-center font-mono text-xs sm:text-sm tracking-wider py-2 sm:py-2.5 px-1 rounded-lg border transition-all duration-150 outline-none ${c}`,title:i?o(`auth.recoveryChecksumError`,{defaultValue:`校验码错误:该组 6 位数无法被 11 整除`,group:t+1}):void 0}),t<4&&(0,K.jsx)(`span`,{className:`text-gray-400 dark:text-gray-500 font-bold select-none text-xs`,children:`-`})]},t)})}),f.length>0&&(0,K.jsx)(`p`,{className:`text-xs text-red-500 dark:text-red-400 text-center font-medium mt-1`,children:o(`auth.recoveryChecksumErrorDesc`,{defaultValue:`第 {{groups}} 组校验码错误,请核对后重试`,groups:f.map(e=>e+1).join(`、`)})})]})},Y=({hasPasskey:e,requiresTotp:n,mfaMethod:i,setMfaMethod:o,passkeyLoading:s,onPasskeyLogin:c,totpToken:l,setTotpToken:u,recoveryKey:d,setRecoveryKey:p,loading:h,onClearError:v,onSubmit:y,keepLoggedIn:b,setKeepLoggedIn:x,optionalSessionExpirationDays:S})=>{let{t:C}=r(),w=e=>{o(e),v()};return(0,K.jsxs)(`form`,{onSubmit:e=>{if(e.preventDefault(),i===`passkey`){c();return}y(e)},className:`space-y-4`,children:[i===`passkey`&&(0,K.jsxs)(`div`,{className:`space-y-5 text-center py-2`,children:[(0,K.jsx)(`div`,{className:`mx-auto w-16 h-16 rounded-2xl bg-blue-50 dark:bg-blue-950/40 flex items-center justify-center text-blue-600 dark:text-blue-400`,children:(0,K.jsx)(t,{size:36})}),(0,K.jsxs)(`div`,{className:`space-y-1`,children:[(0,K.jsx)(`h4`,{className:`text-base font-semibold text-gray-900 dark:text-gray-100 m-0`,children:C(`auth.passkeyVerification`,`Passkey Verification`)}),(0,K.jsx)(`p`,{className:`text-xs text-gray-500 dark:text-gray-400 max-w-xs mx-auto leading-relaxed`,children:C(`auth.passkeyPromptDesc`,`Use your registered device's biometric or hardware security key to verify`)})]}),(0,K.jsx)(g,{checked:b,onChange:e=>x(e.currentTarget.checked),label:C(`auth.keepLoggedIn`,`Keep me logged in for {{days}} days`,{days:S}),className:`text-left inline-block mt-2`}),(0,K.jsxs)(`div`,{className:`pt-2 space-y-3`,children:[(0,K.jsxs)(f,{fill:!0,size:`large`,intent:m.PRIMARY,type:`button`,loading:s,disabled:h,onClick:c,className:`font-semibold py-6 rounded-xl shadow-lg shadow-blue-500/20 flex items-center justify-center space-x-2`,children:[(0,K.jsx)(t,{size:20,className:`inline mr-1.5`}),(0,K.jsx)(`span`,{children:C(`auth.verifyWithPasskey`,`Verify with Passkey`)})]}),n&&(0,K.jsx)(f,{fill:!0,minimal:!0,size:`large`,type:`button`,disabled:s||h,onClick:()=>w(`totp`),className:`font-medium text-blue-600 dark:text-blue-400 py-2.5 rounded-xl transition-colors hover:bg-blue-50 dark:hover:bg-blue-950/30`,children:C(`auth.otherOptions`,`Other Options`)}),(0,K.jsx)(`div`,{className:`pt-1`,children:(0,K.jsxs)(`button`,{type:`button`,onClick:()=>w(`recovery`),className:`text-xs text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 hover:underline bg-transparent border-none cursor-pointer p-0 font-normal inline-flex items-center gap-1`,children:[(0,K.jsx)(a,{size:12}),(0,K.jsx)(`span`,{children:C(`auth.totpUseRecovery`,`Use Recovery Key`)})]})})]})]}),i===`totp`&&(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(_,{label:C(`account.totp.title`,`Time-based One-time Password (TOTP)`),helperText:C(`auth.totpPrompt`,`Please enter the 6-digit code from your authentication app`),children:(0,K.jsx)(`div`,{className:`pt-2`,children:(0,K.jsx)(R,{length:6,value:l,onChange:u,disabled:h,autoFocus:!0})})}),(0,K.jsx)(g,{checked:b,onChange:e=>x(e.currentTarget.checked),label:C(`auth.keepLoggedIn`,`Keep me logged in for {{days}} days`,{days:S}),className:`mt-4 text-left`}),(0,K.jsxs)(`div`,{className:`pt-2 space-y-3`,children:[(0,K.jsx)(f,{fill:!0,size:`large`,intent:m.PRIMARY,type:`submit`,loading:h,className:`font-bold py-6 rounded-xl shadow-lg shadow-blue-500/20`,children:C(`auth.loginBtn`,`Login`)}),e&&(0,K.jsx)(f,{fill:!0,minimal:!0,size:`large`,type:`button`,disabled:h,onClick:()=>w(`passkey`),className:`font-medium text-blue-600 dark:text-blue-400 py-2.5 rounded-xl transition-colors hover:bg-blue-50 dark:hover:bg-blue-950/30`,children:C(`auth.otherOptions`,`Other Options`)}),(0,K.jsx)(`div`,{className:`text-center pt-1`,children:(0,K.jsxs)(`button`,{type:`button`,onClick:()=>w(`recovery`),className:`text-xs text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 hover:underline bg-transparent border-none cursor-pointer p-0 font-normal inline-flex items-center gap-1`,children:[(0,K.jsx)(a,{size:12}),(0,K.jsx)(`span`,{children:C(`auth.totpUseRecovery`,`Use Recovery Key`)})]})})]})]}),i===`recovery`&&(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(_,{label:C(`account.totp.recoveryKeysTitle`,`Recovery Keys`),helperText:C(`auth.recoveryPrompt`,`Please enter your 30-character recovery key (5 groups of 6 digits)`),children:(0,K.jsx)(`div`,{className:`pt-2`,children:(0,K.jsx)(J,{value:d,onChange:p,disabled:h,autoFocus:!0})})}),(0,K.jsx)(g,{checked:b,onChange:e=>x(e.currentTarget.checked),label:C(`auth.keepLoggedIn`,`Keep me logged in for {{days}} days`,{days:S}),className:`mt-4 text-left`}),(0,K.jsxs)(`div`,{className:`pt-2 space-y-3`,children:[(0,K.jsx)(f,{fill:!0,size:`large`,intent:m.PRIMARY,type:`submit`,loading:h,className:`font-bold py-6 rounded-xl shadow-lg shadow-blue-500/20`,children:C(`auth.loginBtn`,`Login`)}),(0,K.jsx)(`div`,{className:`text-center pt-1`,children:(0,K.jsx)(`button`,{type:`button`,onClick:()=>w(e?`passkey`:`totp`),className:`text-xs text-blue-600 dark:text-blue-400 hover:underline bg-transparent border-none cursor-pointer p-0 font-normal`,children:e?C(`auth.backToPasskey`,`Back to Passkey Verification`):C(`auth.totpUseApp`,`Use Authentication App`)})})]})]})]})},X=({authConfig:e,turnstileReady:t,onSuccess:n})=>{let[i,a]=(0,G.useState)(1),[o,s]=(0,G.useState)(``),[c,l]=(0,G.useState)(``),[u,d]=(0,G.useState)(``),[f,p]=(0,G.useState)(``),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(1),[v,y]=(0,G.useState)(void 0),[b,x]=(0,G.useState)(void 0),[S,C]=(0,G.useState)(!0),[T,D]=(0,G.useState)(!1),[O,k]=(0,G.useState)(!1),[A,P]=(0,G.useState)(null),[F,R]=(0,G.useState)(!1),[z,V]=(0,G.useState)(`passkey`),[H,U]=(0,G.useState)(!1),[ie,W]=(0,G.useState)(``),[K,q]=(0,G.useState)(null),[oe,J]=(0,G.useState)(`idle`),Y=(0,G.useRef)(null),X=(0,G.useRef)(null),{t:Z}=r(),Q=e?.turnstile_enabled_login;(0,G.useEffect)(()=>{if(i===1&&Q&&e?.turnstile_site_key&&(t||window.turnstile)&&Y.current)try{X.current&&window.turnstile&&(window.turnstile.remove(X.current),X.current=null),J(`verifying`),Y.current.innerHTML=``,X.current=window.turnstile.render(Y.current,{sitekey:e.turnstile_site_key,callback:e=>{q(e),J(`success`),W(``)},"expired-callback":()=>{q(null),J(`idle`)},"error-callback":e=>{console.error(`Turnstile error:`,e),J(`error`),W(Z(`auth.turnstileError`,`Verification service failed to load. Please reload and try again.`)),q(null)}})}catch(e){console.error(`Turnstile render error:`,e),J(`error`)}return()=>{X.current&&window.turnstile&&(window.turnstile.remove(X.current),X.current=null)}},[Q,e,i,t,Z]);let se=async t=>{if(t.preventDefault(),!M(o)){W(Z(`auth.formatTipUsername`));return}if(Q&&e?.turnstile_site_key&&!K){W(Z(`auth.turnstileRequired`));return}U(!0),W(``);try{let e=await E({username:o,turnstileToken:K});C(e.requires_password),D(e.requires_totp),k(!!e.has_passkey),P(e.passkey_options||null),_(e.password_version??1),y(e.nonce),x(e.serverSalt),V(e.has_passkey?`passkey`:`totp`),e.requires_password?a(2):a(3)}catch(e){W(B(e,Z)),window.turnstile&&window.turnstile.reset(),q(null)}finally{U(!1)}},$=async e=>{U(!0),W(``);try{let t={keepLoggedIn:m,passkeyAssertion:e.passkeyAssertion,totpTokenHash:e.totpTokenHash,totpSalt:e.totpSalt,recoveryKey:e.recoveryKey};if(e.useEnteredPassword&&c)if(g===2){if(!v||!b)throw Error(Z(`auth.sessionExpired`,`Session expired, please start over`));t.password=await L(await ee(await N(c,o),b),v)}else t.password=c;let r=await j(t);r.accessToken&&ne(r.accessToken),r.needsMigration&&c&&await w(await N(c,o)),n()}catch(e){e instanceof re&&I({status:e.status},e.bodyText)?W(Z(`auth.passwordLeaked`)):W(B(e,Z))}finally{U(!1)}},ce=async e=>{if(e.preventDefault(),!c){W(Z(`auth.passwordRequiredFirst`,`Please enter your password first`));return}O||T?(W(``),a(3),V(O?`passkey`:`totp`)):await $({useEnteredPassword:!0})},le=()=>{l(``),W(``),a(3),V(O?`passkey`:`totp`)},ue=async()=>{if(A){R(!0),W(``);try{let e=await ae(A);await $({useEnteredPassword:!!c,passkeyAssertion:e})}catch(e){console.error(`Passkey authentication error:`,e),W(B(e,Z))}finally{R(!1)}}},de=async e=>{if(e.preventDefault(),z===`totp`){let e=u.replace(/\s/g,``);if(e.length!==6){W(Z(`auth.totpFormatError`,`Please enter a valid 6-digit code`));return}let t=crypto.randomUUID(),n=await te(e,t);await $({useEnteredPassword:!!c,totpTokenHash:n,totpSalt:t})}else if(z===`recovery`){let e=f.replace(/[-\s]/g,``);if(!e){W(Z(`auth.recoveryKeyRequired`,`Please enter your recovery key`));return}await $({useEnteredPassword:!!c,recoveryKey:e})}},fe=()=>{W(``),i===2?pe():i===3&&(S?a(2):pe())},pe=()=>{a(1),l(``),d(``),p(``),W(``),q(null),y(void 0),x(void 0),k(!1),P(null),R(!1),V(`passkey`)};return{loginStep:i,username:o,setUsername:s,password:c,setPassword:l,totpToken:u,setTotpToken:d,recoveryKey:f,setRecoveryKey:p,requiresPassword:S,requiresTotp:T,hasPasskey:O,mfaMethod:z,setMfaMethod:V,passkeyLoading:F,loading:H,error:ie,setError:W,turnstileStatus:oe,turnstileRef:Y,isTurnstileEnabled:Q,keepLoggedIn:m,setKeepLoggedIn:h,handleStep1Submit:se,handleStep2Submit:ce,handleStep3Submit:de,handleSwitchToMfa:le,handlePasskeyLogin:ue,handleBack:fe,resetToStep1:pe}},Z=({authConfig:e,turnstileReady:t,onSuccess:n,onToggleMode:i})=>{let{t:a}=r(),{loginStep:s,username:c,setUsername:u,password:d,setPassword:f,totpToken:h,setTotpToken:g,recoveryKey:_,setRecoveryKey:v,requiresTotp:y,hasPasskey:b,mfaMethod:x,setMfaMethod:S,passkeyLoading:C,loading:w,error:T,setError:E,turnstileStatus:D,turnstileRef:O,isTurnstileEnabled:k,keepLoggedIn:A,setKeepLoggedIn:j,handleStep1Submit:M,handleStep2Submit:N,handleStep3Submit:P,handleSwitchToMfa:F,handlePasskeyLogin:I,handleBack:ee}=X({authConfig:e,turnstileReady:t,onSuccess:n});return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`flex flex-col items-center mb-8 relative`,children:[s!==1&&(0,K.jsx)(`button`,{type:`button`,onClick:ee,className:`absolute left-0 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 bg-transparent border-none cursor-pointer p-1 rounded-lg transition-colors`,title:a(`common.back`,`返回`),children:(0,K.jsx)(o,{size:24})}),(0,K.jsx)(`img`,{src:H,alt:`DNS Worker Logo`,className:`w-20 h-20 object-contain`}),(0,K.jsx)(l,{className:`font-bold tracking-tight text-2xl mt-4`,children:(()=>{switch(s){case 1:return a(`auth.login`);case 2:return a(`auth.password`);case 3:return a(`auth.mfaVerification`,`多因素认证`)}})()}),(0,K.jsx)(`p`,{className:`text-gray-500 mt-2 text-center text-sm leading-relaxed`,children:s===1?a(`auth.protectInternet`):c})]}),e?.has_users===!1&&(0,K.jsx)(p,{intent:m.PRIMARY,icon:`info-sign`,className:`mb-6 rounded-xl`,children:(0,K.jsxs)(`div`,{className:`flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3`,children:[(0,K.jsx)(`span`,{className:`text-sm font-medium`,children:a(`auth.noUsersRegistered`,`系统尚无账号,请注册成为管理员。`)}),(0,K.jsx)(`button`,{type:`button`,onClick:i,className:`text-xs bg-blue-600 hover:bg-blue-700 text-white font-semibold py-1.5 px-3 rounded-lg border-none cursor-pointer whitespace-nowrap transition-colors`,children:a(`auth.goToRegisterAdmin`,`注册管理员`)})]})}),T&&(0,K.jsx)(p,{intent:m.DANGER,className:`mb-6 rounded-xl`,title:a(`auth.error`),children:T}),s===1&&(0,K.jsx)(q,{username:c,setUsername:u,isTurnstileEnabled:k,turnstileRef:O,loading:w,turnstileStatus:D,onSubmit:M}),s===2&&(0,K.jsx)(oe,{password:d,setPassword:f,hasMfa:b||y,onSwitchToMfa:F,loading:w,onSubmit:N,keepLoggedIn:A,setKeepLoggedIn:j,optionalSessionExpirationDays:e?.optional_session_expiration_days??7}),s===3&&(0,K.jsx)(Y,{hasPasskey:b,requiresTotp:y,mfaMethod:x,setMfaMethod:S,passkeyLoading:C,onPasskeyLogin:I,totpToken:h,setTotpToken:g,recoveryKey:_,setRecoveryKey:v,loading:w,onClearError:()=>E(``),onSubmit:P,keepLoggedIn:A,setKeepLoggedIn:j,optionalSessionExpirationDays:e?.optional_session_expiration_days??7}),s===1&&(e?.has_users===!1||e?.registration_enabled!==!1)&&(0,K.jsx)(`div`,{className:`mt-8 pt-6 border-t border-gray-100 dark:border-gray-800 flex justify-center items-center text-sm`,children:(0,K.jsx)(`button`,{onClick:i,className:`text-blue-600 dark:text-blue-400 font-semibold hover:underline bg-transparent border-none cursor-pointer`,children:a(`auth.noAccount`)})})]})},Q=({username:e,setUsername:t,usernameFocused:n,setUsernameFocused:i,checkUsernameDuplicate:a,loading:o,onSubmit:s,onClearError:c})=>{let{t:l}=r();return(0,K.jsxs)(`form`,{onSubmit:s,className:`space-y-4`,children:[(0,K.jsx)(_,{label:l(`auth.username`),labelFor:`username`,children:(0,K.jsx)(y,{content:l(`auth.formatTipUsername`),isOpen:n,position:u.TOP,intent:m.PRIMARY,className:`w-full`,children:(0,K.jsx)(`div`,{className:`w-full block`,children:(0,K.jsx)(h,{id:`username`,leftIcon:`user`,placeholder:l(`auth.usernamePlaceholder`),size:`large`,className:`rounded-xl w-full`,value:e,onChange:e=>{t(e.target.value),c()},onFocus:()=>i(!0),onBlur:()=>{i(!1),a(e)},autoFocus:!0,required:!0})})})}),(0,K.jsx)(f,{fill:!0,size:`large`,intent:m.PRIMARY,type:`submit`,loading:o,className:`mt-6 font-bold py-6 rounded-xl shadow-lg shadow-blue-500/20`,children:l(`auth.next`,`Next`)})]})},se=({password:e,setPassword:t,passwordFocused:n,setPasswordFocused:i,loading:a,onSubmit:o,isTurnstileEnabled:s,turnstileRef:c,turnstileStatus:l})=>{let[d,p]=G.useState(!1),{t:g}=r();return(0,K.jsxs)(`form`,{onSubmit:o,className:`space-y-4`,children:[(0,K.jsx)(_,{label:g(`auth.password`),labelFor:`password`,children:(0,K.jsx)(y,{content:g(`auth.formatTipPassword`),isOpen:n,position:u.TOP,intent:m.PRIMARY,className:`w-full`,children:(0,K.jsx)(`div`,{className:`w-full block`,children:(0,K.jsx)(h,{id:`password`,leftIcon:`lock`,placeholder:g(`auth.passwordPlaceholder`),type:d?`text`:`password`,size:`large`,className:`rounded-xl w-full`,value:e,onChange:e=>t(e.target.value),onFocus:()=>i(!0),onBlur:()=>i(!1),rightElement:(()=>(0,K.jsxs)(`div`,{className:`flex items-center`,children:[e&&(0,K.jsx)(f,{minimal:!0,icon:`cross`,onClick:()=>t(``)}),(0,K.jsx)(f,{minimal:!0,icon:d?`eye-open`:`eye-off`,onClick:()=>p(!d),title:d?g(`auth.hidePassword`,`Hide password`):g(`auth.showPassword`,`Show password`)})]}))(),required:!0,autoFocus:!0})})})}),s&&(0,K.jsx)(`div`,{className:`py-2 flex justify-center min-h-16.25`,children:(0,K.jsx)(`div`,{ref:c})}),(0,K.jsx)(f,{fill:!0,size:`large`,intent:m.PRIMARY,type:`submit`,loading:a||l===`verifying`,disabled:!!s&&l!==`success`,className:`mt-6 font-bold py-6 rounded-xl shadow-lg shadow-blue-500/20`,children:g(l===`verifying`?`auth.verifying`:`auth.signupBtn`)})]})},$=({mfaChoice:e,setMfaChoice:i,onRegisterPasskey:a,passkeyRegLoading:s,passkeyRegError:c,onStartTotp:l,totpSetupData:u,totpSetupToken:h,setTotpSetupToken:g,totpSetupError:y,totpSetupLoading:x,onTotpSubmit:S,onSkip:C})=>{let{t:w}=r();return e===`choose`?(0,K.jsxs)(`div`,{className:`space-y-4`,children:[c&&(0,K.jsx)(p,{intent:m.DANGER,className:`rounded-xl`,children:c}),(0,K.jsxs)(`div`,{className:`space-y-3`,children:[(0,K.jsxs)(b,{elevation:d.ONE,className:`p-4 rounded-xl border border-blue-100 dark:border-blue-900/40 hover:border-blue-300 dark:hover:border-blue-700 transition-colors cursor-pointer`,onClick:s?void 0:a,children:[(0,K.jsx)(`div`,{className:`flex items-start justify-between`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`p-2.5 bg-blue-50 dark:bg-blue-950/40 text-blue-600 dark:text-blue-400 rounded-xl`,children:(0,K.jsx)(t,{size:24})}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-bold text-gray-800 dark:text-gray-100 m-0`,children:w(`account.passkey.title`,`通行密钥 (Passkey)`)}),(0,K.jsx)(v,{intent:m.PRIMARY,minimal:!0,round:!0,children:w(`auth.mfaRecommended`,`推荐 · 无密码`)})]}),(0,K.jsx)(`div`,{className:`text-xs text-blue-600 dark:text-blue-400 font-mono mt-0.5`,children:window.location.hostname}),(0,K.jsx)(`p`,{className:`text-xs text-gray-500 dark:text-gray-400 mt-1 mb-0 leading-relaxed`,children:w(`auth.passkeySignupDesc`,`使用本设备生物识别 (Touch ID / Face ID / Windows Hello) 或硬件密钥 (YubiKey),一键快捷且防钓鱼。`)})]})]})}),(0,K.jsx)(`div`,{className:`mt-3 text-right`,children:(0,K.jsx)(f,{intent:m.PRIMARY,loading:s,text:w(`auth.bindPasskeyNow`,`绑定通行密钥`),className:`rounded-lg font-medium`})})]}),(0,K.jsxs)(b,{elevation:d.ONE,className:`p-4 rounded-xl border border-gray-100 dark:border-gray-800 hover:border-gray-300 dark:hover:border-gray-700 transition-colors cursor-pointer`,onClick:l,children:[(0,K.jsx)(`div`,{className:`flex items-start justify-between`,children:(0,K.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,K.jsx)(`div`,{className:`p-2.5 bg-purple-50 dark:bg-purple-950/40 text-purple-600 dark:text-purple-400 rounded-xl`,children:(0,K.jsx)(n,{size:24})}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`h4`,{className:`text-sm font-bold text-gray-800 dark:text-gray-100 m-0`,children:w(`auth.mfaMethodTotp`,`数字验证器 (TOTP)`)}),(0,K.jsx)(v,{intent:m.NONE,minimal:!0,round:!0,children:w(`auth.mfaUniversal`,`通用应用`)})]}),(0,K.jsx)(`p`,{className:`text-xs text-gray-500 dark:text-gray-400 mt-1 mb-0 leading-relaxed`,children:w(`account.totp.setupDesc`,`使用 Google Authenticator、1Password 等验证器应用扫码绑定 6 位动态验证码。`)})]})]})}),(0,K.jsx)(`div`,{className:`mt-3 text-right`,children:(0,K.jsx)(f,{minimal:!0,text:w(`auth.setupTotpBtn`,`扫码配置验证器`),className:`rounded-lg font-medium text-gray-700 dark:text-gray-200`})})]})]}),(0,K.jsx)(`div`,{className:`text-center pt-2`,children:(0,K.jsx)(f,{minimal:!0,text:w(`auth.skipMfaSetup`,`跳过多因素认证配置,直接进入系统`),onClick:C,className:`text-xs text-gray-400 hover:text-gray-600 dark:hover:text-gray-200`})})]}):(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`div`,{className:`flex items-center justify-between`,children:(0,K.jsxs)(`button`,{type:`button`,onClick:()=>i(`choose`),className:`text-xs text-blue-600 hover:underline flex items-center gap-1 bg-transparent border-none cursor-pointer p-0`,children:[(0,K.jsx)(o,{size:14}),(0,K.jsx)(`span`,{children:w(`auth.backToMfaOptions`,`选择其他认证方式`)})]})}),u&&(0,K.jsxs)(`div`,{className:`flex flex-col items-center gap-3`,children:[(0,K.jsx)(W,{uri:u.uri}),(0,K.jsxs)(`div`,{className:`text-center`,children:[(0,K.jsx)(`p`,{className:`text-xs text-gray-500 mb-1`,children:w(`account.totp.orEnterManually`,`Or enter the key manually:`)}),(0,K.jsx)(`code`,{className:`text-xs font-mono bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded select-all`,children:u.secret})]})]}),y&&(0,K.jsx)(p,{intent:m.DANGER,className:`rounded-xl`,children:y}),(0,K.jsxs)(`form`,{onSubmit:S,className:`space-y-4`,children:[(0,K.jsx)(_,{label:w(`account.totp.enterCode`,`Enter the 6-digit code:`),helperText:w(`account.totp.enterCodeHint`,`Enter the 6-digit code to confirm.`),children:(0,K.jsx)(R,{length:6,value:h,onChange:g,disabled:x,autoFocus:!0})}),(0,K.jsx)(f,{fill:!0,size:`large`,intent:m.PRIMARY,type:`submit`,loading:x,disabled:h.length!==6,className:`rounded-xl font-bold py-3`,children:w(`account.totp.activate`,`Activate`)})]})]})},ce=({totpRecoveryKeys:e,copiedRecovery:t,onCopy:n,onSuccess:a})=>{let{t:o}=r();return G.useEffect(()=>{let e=e=>{e.key===`Enter`&&a()};return window.addEventListener(`keydown`,e),()=>{window.removeEventListener(`keydown`,e)}},[a]),(0,K.jsxs)(`div`,{className:`space-y-4`,children:[(0,K.jsx)(`div`,{className:e.length===1?`space-y-2 mb-4`:`grid grid-cols-2 gap-2 mb-4`,children:e.map((e,t)=>(0,K.jsx)(`code`,{className:`block font-mono text-sm sm:text-base font-semibold bg-gray-100 dark:bg-gray-800 text-blue-600 dark:text-blue-400 px-4 py-3 rounded-xl text-center tracking-widest break-all select-all border border-gray-200 dark:border-gray-700`,children:e},t))}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsx)(f,{fill:!0,icon:(0,K.jsx)(i,{size:14}),text:t?o(`account.totp.copied`,`Copied!`):o(`account.totp.copyKeys`,`Copy All Keys`),intent:t?m.SUCCESS:m.NONE,onClick:n}),(0,K.jsx)(f,{fill:!0,intent:m.PRIMARY,text:o(`account.totp.done`,`Done`),onClick:a})]})]})},le=({authConfig:e,turnstileReady:t,onSuccess:n})=>{let[i,a]=(0,G.useState)(`username`),[o,s]=(0,G.useState)(``),[c,l]=(0,G.useState)(``),[u,d]=(0,G.useState)(``),[f,p]=(0,G.useState)(null),[m,h]=(0,G.useState)(null),[g,_]=(0,G.useState)(!1),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(!1),[w,E]=(0,G.useState)(!1),[k,A]=(0,G.useState)(!1),[j,P]=(0,G.useState)(!1),[ee,L]=(0,G.useState)(``),[R,z]=(0,G.useState)(`choose`),[H,U]=(0,G.useState)(!1),[ae,W]=(0,G.useState)(``),[K,q]=(0,G.useState)(null),[oe,J]=(0,G.useState)(`idle`),Y=(0,G.useRef)(null),X=(0,G.useRef)(null),{t:Z}=r(),Q=e?.turnstile_enabled_signup;(0,G.useEffect)(()=>{if(i===`password`&&Q&&e?.turnstile_site_key&&(t||window.turnstile)&&Y.current)try{X.current&&window.turnstile&&(window.turnstile.remove(X.current),X.current=null),J(`verifying`),Y.current.innerHTML=``,X.current=window.turnstile.render(Y.current,{sitekey:e.turnstile_site_key,callback:e=>{q(e),J(`success`),y(``)},"expired-callback":()=>{q(null),J(`idle`)},"error-callback":e=>{console.error(`Turnstile error:`,e),J(`error`),y(Z(`auth.turnstileError`,`Verification service failed to load. Please reload and try again.`)),q(null)}})}catch(e){console.error(`Turnstile render error:`,e),J(`error`)}return()=>{X.current&&window.turnstile&&(window.turnstile.remove(X.current),X.current=null)}},[Q,e,i,t,Z]);let se=async e=>{if(!(!e||!M(e)))try{await S(e)?y(Z(`auth.usernameExists`)):y(e=>e===Z(`auth.usernameExists`)?``:e)}catch(e){console.error(`Failed to check username duplicate`,e)}},$=async e=>{if(e.preventDefault(),!M(o)){y(Z(`auth.formatTipUsername`));return}_(!0),y(``);try{await S(o)?y(Z(`auth.usernameExists`)):a(`password`)}catch{y(Z(`auth.networkError`))}finally{_(!1)}},ce=async()=>{P(!0),L(``);try{p(await O()),a(`totp`)}catch(e){console.error(`Network error during signup TOTP setup:`,e),n()}finally{P(!1)}};return{signupStep:i,setSignupStep:a,username:o,setUsername:s,password:c,setPassword:l,mfaChoice:R,setMfaChoice:z,passkeyRegLoading:H,passkeyRegError:ae,handleRegisterPasskey:async()=>{U(!0),W(``);try{let e=await D({name:`primary_passkey`,credential:await ie(await C())});e.recovery_keys&&e.recovery_keys.length>0?(h(e.recovery_keys),a(`recovery`)):n()}catch(e){console.error(`Passkey registration failed:`,e),W(B(e,Z))}finally{U(!1)}},handleChooseTotp:async()=>{z(`totp`),await ce()},totpSetupToken:u,setTotpSetupToken:d,totpSetupData:f,setTotpSetupData:p,totpRecoveryKeys:m,setTotpRecoveryKeys:h,loading:g,error:v,setError:y,usernameFocused:b,setUsernameFocused:x,passwordFocused:w,setPasswordFocused:E,copiedRecovery:k,totpSetupLoading:j,totpSetupError:ee,turnstileStatus:oe,turnstileRef:Y,isTurnstileEnabled:Q,checkUsernameDuplicate:se,handleSignupUsernameSubmit:$,handleSignupTotpConfirm:async e=>{if(e.preventDefault(),f){P(!0),L(``);try{let e=u.replace(/\s/g,``),t=crypto.randomUUID(),n=await te(e,t);h((await F({secret:f.secret,totpTokenHash:n,salt:t})).recovery_keys),a(`recovery`)}catch(e){L(e.message||Z(`common.errorNetwork`))}finally{P(!1)}}},handleCopySignupRecoveryKeys:()=>{m&&navigator.clipboard.writeText(m.join(`
|
|
2
|
+
`)).then(()=>{A(!0),setTimeout(()=>A(!1),2e3)})},handleSignupSubmit:async t=>{if(t.preventDefault(),!M(o)){y(Z(`auth.formatTipUsername`));return}if(!V(c)){y(Z(`auth.formatTipPassword`));return}if(Q&&e?.turnstile_site_key&&!K){y(Z(`auth.turnstileRequired`));return}_(!0),y(``);try{let e=await T({username:o,password:await N(c,o),turnstileToken:K});e.accessToken&&ne(e.accessToken),z(`choose`),a(`totp`)}catch(e){e instanceof re&&I({status:e.status},e.bodyText)?y(Z(`auth.passwordLeaked`)):y(B(e,Z)),window.turnstile&&window.turnstile.reset(),q(null)}finally{_(!1)}}}},ue=({authConfig:e,turnstileReady:t,onSuccess:n,onToggleMode:i})=>{let{t:a}=r(),{signupStep:s,setSignupStep:c,username:u,setUsername:d,password:f,setPassword:h,mfaChoice:g,setMfaChoice:_,passkeyRegLoading:v,passkeyRegError:y,handleRegisterPasskey:b,handleChooseTotp:x,totpSetupToken:S,setTotpSetupToken:C,totpSetupData:w,totpRecoveryKeys:T,loading:E,error:D,setError:O,usernameFocused:k,setUsernameFocused:A,passwordFocused:j,setPasswordFocused:M,copiedRecovery:N,totpSetupLoading:P,totpSetupError:F,turnstileStatus:I,turnstileRef:ee,isTurnstileEnabled:L,checkUsernameDuplicate:R,handleSignupUsernameSubmit:te,handleSignupTotpConfirm:ne,handleCopySignupRecoveryKeys:z,handleSignupSubmit:B}=le({authConfig:e,turnstileReady:t,onSuccess:n});return e&&e.has_users!==!1&&e.registration_enabled===!1?(0,K.jsxs)(`div`,{className:`space-y-6 text-center`,children:[(0,K.jsxs)(`div`,{className:`flex flex-col items-center`,children:[(0,K.jsx)(`img`,{src:H,alt:`DNS Worker Logo`,className:`w-20 h-20 object-contain`}),(0,K.jsx)(l,{className:`font-bold tracking-tight text-2xl mt-4`,children:a(`auth.signup`)})]}),(0,K.jsx)(p,{intent:m.WARNING,icon:`lock`,title:a(`auth.registrationDisabledTitle`,`注册已停用`),children:a(`auth.registrationDisabledDesc`,`当前系统已暂停开放新用户注册,请联系系统管理员分配账号。`)}),(0,K.jsx)(`div`,{className:`pt-4 border-t border-gray-100 dark:border-gray-800 flex justify-center items-center text-sm`,children:(0,K.jsxs)(`button`,{onClick:i,className:`text-blue-600 dark:text-blue-400 font-semibold hover:underline bg-transparent border-none cursor-pointer flex items-center gap-1`,children:[(0,K.jsx)(o,{size:16}),a(`auth.backToLogin`,`返回登录`)]})})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`flex flex-col items-center mb-8 relative`,children:[s===`password`&&(0,K.jsx)(`button`,{onClick:()=>{c(`username`),O(``)},className:`absolute left-0 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 bg-transparent border-none cursor-pointer`,title:`Back to username`,children:(0,K.jsx)(o,{size:24})}),(0,K.jsx)(`img`,{src:H,alt:`DNS Worker Logo`,className:`w-20 h-20 object-contain`}),(0,K.jsx)(l,{className:`font-bold tracking-tight text-2xl mt-4`,children:s===`username`||s===`password`?e?.has_users===!1?a(`auth.registerAdminTitle`,`注册管理员账号`):a(`auth.signup`):s===`totp`?a(`auth.mfaSetupTitle`,`配置多因素认证 (MFA)`):a(`account.totp.recoveryKeysTitle`,`Save Recovery Keys`)}),(0,K.jsx)(`p`,{className:`text-gray-500 mt-2 text-center text-sm leading-relaxed`,children:s===`username`||s===`password`?s===`password`?u:e?.has_users===!1?a(`auth.registerAdminDesc`,`系统尚无账号,首位注册用户将自动成为系统管理员。`):a(`auth.protectInternet`):s===`totp`?a(`auth.mfaSetupDesc`,`任选一种认证方式即可完成配置,保障账号安全。`):a(`account.totp.recoveryKeysWarning`,`Store keys safely.`)})]}),D&&(0,K.jsx)(p,{intent:m.DANGER,className:`mb-6 rounded-xl`,title:a(`auth.error`),children:D}),s===`username`&&(0,K.jsx)(Q,{username:u,setUsername:d,usernameFocused:k,setUsernameFocused:A,checkUsernameDuplicate:R,loading:E,onSubmit:te,onClearError:()=>O(e=>e===a(`auth.usernameExists`)?``:e)}),s===`password`&&(0,K.jsx)(se,{password:f,setPassword:h,passwordFocused:j,setPasswordFocused:M,loading:E,onSubmit:B,isTurnstileEnabled:L,turnstileRef:ee,turnstileStatus:I}),s===`totp`&&(0,K.jsx)($,{mfaChoice:g,setMfaChoice:_,onRegisterPasskey:b,passkeyRegLoading:v,passkeyRegError:y,onStartTotp:x,totpSetupData:w,totpSetupToken:S,setTotpSetupToken:C,totpSetupError:F,totpSetupLoading:P,onTotpSubmit:ne,onSkip:n}),s===`recovery`&&T&&(0,K.jsx)(ce,{totpRecoveryKeys:T,copiedRecovery:N,onCopy:z,onSuccess:n}),s===`username`&&(0,K.jsx)(`div`,{className:`mt-8 pt-6 border-t border-gray-100 dark:border-gray-800 text-center`,children:(0,K.jsx)(`button`,{onClick:i,className:`text-blue-600 dark:text-blue-400 font-semibold hover:underline bg-transparent border-none cursor-pointer text-sm`,children:a(`auth.haveAccount`)})})]})},de=({onSuccess:e})=>{let[t,n]=(0,G.useState)(!0),[i,a]=(0,G.useState)(!0),[o,s]=(0,G.useState)(!1),{t:c}=r(),l=()=>{s(!0),setTimeout(()=>{n(e=>!e),s(!1)},300)},[u,p]=(0,G.useState)(null),[m,h]=(0,G.useState)(!1);(0,G.useEffect)(()=>{(async()=>{try{let e=await A();p(e),e&&e.has_users===!1&&n(!1)}catch(e){console.error(`Failed to load auth config`,e)}})()},[]);let g=t?u?.turnstile_enabled_login:u?.turnstile_enabled_signup;return(0,G.useEffect)(()=>{g&&u?.turnstile_site_key&&P(()=>{h(!0)})},[g,u]),(0,K.jsxs)(`div`,{className:`flex flex-row min-h-screen bg-white dark:bg-gray-950 overflow-hidden relative`,children:[(0,K.jsx)(`div`,{className:`hidden lg:block w-1/2 h-screen overflow-hidden border-r border-gray-100 dark:border-gray-900`,children:(0,K.jsx)(z,{})}),(0,K.jsx)(`div`,{className:`lg:hidden absolute inset-0 z-0 transition-opacity duration-500 cursor-pointer ${i?`opacity-25`:`opacity-70`}`,onClick:()=>a(!0),children:(0,K.jsx)(z,{})}),!i&&(0,K.jsx)(`div`,{className:`lg:hidden fixed bottom-12 left-1/2 -translate-x-1/2 z-50 animate-bounce`,children:(0,K.jsx)(f,{large:!0,intent:`primary`,icon:`log-in`,text:c(`auth.loginBtn`),onClick:()=>a(!0),className:`shadow-2xl px-8 py-4 rounded-full`})}),(0,K.jsxs)(`div`,{className:`flex-1 flex items-center justify-center p-4 relative z-10 bg-gray-50/50 dark:bg-gray-900/30 lg:bg-gray-50 lg:dark:bg-gray-900/50 transition-all duration-500 ease-in-out ${i?`translate-x-0 opacity-100`:`max-lg:translate-x-full max-lg:opacity-0 max-lg:pointer-events-none`}`,onClick:e=>{window.innerWidth<1024&&e.target===e.currentTarget&&a(!1)},children:[(0,K.jsx)(`div`,{className:`absolute top-4 right-4 z-50`,children:(0,K.jsx)(k,{})}),(0,K.jsx)(`div`,{className:x(`w-full max-w-md transition-all duration-200 ease-in-out transform-gpu`,o?`blur-lg opacity-20 scale-95`:`blur-0 opacity-100 scale-100`),children:(0,K.jsx)(b,{elevation:d.FOUR,className:`w-full p-8 rounded-2xl shadow-none! z-10 dark:bg-gray-900 border border-gray-100 dark:border-gray-800`,onClick:e=>e.stopPropagation(),children:t?(0,K.jsx)(Z,{authConfig:u,turnstileReady:m,onSuccess:e,onToggleMode:l}):(0,K.jsx)(ue,{authConfig:u,turnstileReady:m,onSuccess:e,onToggleMode:l})})})]})]})};export{de as AuthView};
|