feat(auth): extend admin session to 30 minutes
This commit is contained in:
parent
b410dc4257
commit
af89a17f7f
|
|
@ -42,7 +42,7 @@ docker run --env-file .env -p 8080:8080 messageweave:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Then open `http://localhost:8080` in a browser and enter your `CONFIG_ENCRYPTION_KEY`
|
Then open `http://localhost:8080` in a browser and enter your `CONFIG_ENCRYPTION_KEY`
|
||||||
value. The SPA exchanges it with `POST /api/admin/session` for a 900-second admin session,
|
value. The SPA exchanges it with `POST /api/admin/session` for a 1,800-second admin session,
|
||||||
then writes the business secrets to Redis with `PUT /api/business-config`. No environment
|
then writes the business secrets to Redis with `PUT /api/business-config`. No environment
|
||||||
variable is read or written again for business configuration.
|
variable is read or written again for business configuration.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ docker run --env-file .env -p 8080:8080 messageweave:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
然后在浏览器打开 `http://localhost:8080`,输入你的 `CONFIG_ENCRYPTION_KEY` 值。SPA 用它
|
然后在浏览器打开 `http://localhost:8080`,输入你的 `CONFIG_ENCRYPTION_KEY` 值。SPA 用它
|
||||||
经 `POST /api/admin/session` 换取 900 秒的 admin session,再用 `PUT /api/business-config`
|
经 `POST /api/admin/session` 换取 1,800 秒(30 分钟)的管理会话,再用 `PUT /api/business-config`
|
||||||
把业务密钥写入 Redis。此后业务配置不再读取或写入任何环境变量。
|
把业务密钥写入 Redis。此后业务配置不再读取或写入任何环境变量。
|
||||||
|
|
||||||
不用 Docker 的本地构建:`cargo build --locked` 产出 `message-weave` 二进制。
|
不用 Docker 的本地构建:`cargo build --locked` 产出 `message-weave` 二进制。
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,7 @@ Testing: **No integrated test directory**, and no stand-alone util tool module.
|
||||||
### 7.3.1 Configuration Management API
|
### 7.3.1 Configuration Management API
|
||||||
- `GET /` provides a SPA embedded in the Rust binary; `/assets/config.js` and `/assets/styles.css` provide page resources. The service does not read or write local files while running (`C-NO-LOCAL-WRITE`).
|
- `GET /` provides a SPA embedded in the Rust binary; `/assets/config.js` and `/assets/styles.css` provide page resources. The service does not read or write local files while running (`C-NO-LOCAL-WRITE`).
|
||||||
- `GET /api/status` publicly returns `{ "ready": boolean, "mode": "configured" | "configuration-setup", "missing": string[], "version": string }`, which only lists the missing environment variable names. When `REDIS_URL` or `CONFIG_ENCRYPTION_KEY` is missing, SPA only displays the configuration boot status and missing variables; the management session authorization area is displayed only after the service status is confirmed to be ready=true. `version` is the `BUILD_VERSION` (`<git-sha or nogit>+<UTC build time>`) baked by `build.rs` during compilation. The SPA footer uses this to confirm whether the deployment is actually implemented.
|
- `GET /api/status` publicly returns `{ "ready": boolean, "mode": "configured" | "configuration-setup", "missing": string[], "version": string }`, which only lists the missing environment variable names. When `REDIS_URL` or `CONFIG_ENCRYPTION_KEY` is missing, SPA only displays the configuration boot status and missing variables; the management session authorization area is displayed only after the service status is confirmed to be ready=true. `version` is the `BUILD_VERSION` (`<git-sha or nogit>+<UTC build time>`) baked by `build.rs` during compilation. The SPA footer uses this to confirm whether the deployment is actually implemented.
|
||||||
- `POST /api/admin/session` accepts `Authorization: Bearer <CONFIG_ENCRYPTION_KEY>` and returns `{ "session": "<opaque>", "expires_in": 900 }`; the admin session only saves the digest in Redis and expires after 900 seconds. `POST /api/admin/session/revoke` revokes the current session and returns `204` successfully.
|
- `POST /api/admin/session` accepts `Authorization: Bearer <CONFIG_ENCRYPTION_KEY>` and returns `{ "session": "<opaque>", "expires_in": 1800 }`; the admin session only saves the digest in Redis and expires after 1,800 seconds. `POST /api/admin/session/revoke` revokes the current session and returns `204` successfully.
|
||||||
- The admin page only saves the session in JavaScript memory. Request settings `credentials: omit`, `cache: no-store`, without using cookies, localStorage or sessionStorage. The admin API accepts a valid admin session; the compatibility path also accepts `WORKER_TOKEN`. Worker transparently transmits the authentication header (`SAF-LB-PASSTHRU`) as it is.
|
- The admin page only saves the session in JavaScript memory. Request settings `credentials: omit`, `cache: no-store`, without using cookies, localStorage or sessionStorage. The admin API accepts a valid admin session; the compatibility path also accepts `WORKER_TOKEN`. Worker transparently transmits the authentication header (`SAF-LB-PASSTHRU`) as it is.
|
||||||
- `GET /api/config` and `PUT /api/config` only read and write non-sensitive running parameters:
|
- `GET /api/config` and `PUT /api/config` only read and write non-sensitive running parameters:
|
||||||
```json
|
```json
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,7 @@ message-weave/
|
||||||
### 7.3.1 配置管理 API
|
### 7.3.1 配置管理 API
|
||||||
- `GET /` 提供嵌入 Rust 二进制的 SPA;`/assets/config.js` 与 `/assets/styles.css` 提供页面资源。服务不在运行时读取或写入本地文件(`C-NO-LOCAL-WRITE`)。
|
- `GET /` 提供嵌入 Rust 二进制的 SPA;`/assets/config.js` 与 `/assets/styles.css` 提供页面资源。服务不在运行时读取或写入本地文件(`C-NO-LOCAL-WRITE`)。
|
||||||
- `GET /api/status` 公开返回 `{ "ready": boolean, "mode": "configured" | "configuration-setup", "missing": string[], "version": string }`,只列缺少的环境变量名称。缺少 `REDIS_URL` 或 `CONFIG_ENCRYPTION_KEY` 时,SPA 只显示配置引导状态与缺失变量;服务状态确认 ready=true 后才显示管理会话授权区。`version` 是 `build.rs` 在编译期烘焙的 `BUILD_VERSION`(`<git-sha 或 nogit>+<UTC 构建时间>`),SPA 页脚据此确认部署是否真正落地。
|
- `GET /api/status` 公开返回 `{ "ready": boolean, "mode": "configured" | "configuration-setup", "missing": string[], "version": string }`,只列缺少的环境变量名称。缺少 `REDIS_URL` 或 `CONFIG_ENCRYPTION_KEY` 时,SPA 只显示配置引导状态与缺失变量;服务状态确认 ready=true 后才显示管理会话授权区。`version` 是 `build.rs` 在编译期烘焙的 `BUILD_VERSION`(`<git-sha 或 nogit>+<UTC 构建时间>`),SPA 页脚据此确认部署是否真正落地。
|
||||||
- `POST /api/admin/session` 接受 `Authorization: Bearer <CONFIG_ENCRYPTION_KEY>`,返回 `{ "session": "<opaque>", "expires_in": 900 }`;admin session 仅存 Redis 中的摘要并在 900 秒后过期。`POST /api/admin/session/revoke` 撤销当前 session,成功返回 `204`。
|
- `POST /api/admin/session` 接受 `Authorization: Bearer <CONFIG_ENCRYPTION_KEY>`,返回 `{ "session": "<opaque>", "expires_in": 1800 }`;Redis 中保存的是会话令牌的摘要,30 分钟后过期。`POST /api/admin/session/revoke` 可立即撤销会话,成功返回 `204`。
|
||||||
- 管理页面仅在 JavaScript 内存中保存 session。请求设置 `credentials: omit`、`cache: no-store`,不使用 Cookie、localStorage 或 sessionStorage。管理 API 接受有效 admin session;兼容路径也接受 `WORKER_TOKEN`。Worker 原样透传鉴权头(`SAF-LB-PASSTHRU`)。
|
- 管理页面仅在 JavaScript 内存中保存 session。请求设置 `credentials: omit`、`cache: no-store`,不使用 Cookie、localStorage 或 sessionStorage。管理 API 接受有效 admin session;兼容路径也接受 `WORKER_TOKEN`。Worker 原样透传鉴权头(`SAF-LB-PASSTHRU`)。
|
||||||
- `GET /api/config` 与 `PUT /api/config` 只读取和写入非敏感运行参数:
|
- `GET /api/config` 与 `PUT /api/config` 只读取和写入非敏感运行参数:
|
||||||
```json
|
```json
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ Contract baseline (see `docs/reference.md` §1 for the complete semantics of key
|
||||||
| `ttl::PUSH_SUBSCRIPTION_SECONDS` | 300 | `push:subscription:{id}` / `push:subscription-code:{code}` |
|
| `ttl::PUSH_SUBSCRIPTION_SECONDS` | 300 | `push:subscription:{id}` / `push:subscription-code:{code}` |
|
||||||
| `ttl::PUSH_REGISTRATION_SECONDS` | 604_800 | `push:registration:{sha256(callback_url)}` |
|
| `ttl::PUSH_REGISTRATION_SECONDS` | 604_800 | `push:registration:{sha256(callback_url)}` |
|
||||||
| `ttl::PUSH_ORPHAN_SECONDS` | 604_800 | `push:orphan:{subscription_id}` |
|
| `ttl::PUSH_ORPHAN_SECONDS` | 604_800 | `push:orphan:{subscription_id}` |
|
||||||
| `ttl::ADMIN_SESSION_SECONDS` | 900 | `admin-session:{token}` (also the `expires_in` returned by `/admin/session`) |
|
| `ttl::ADMIN_SESSION_SECONDS` | 1,800 | `admin-session:{token}` (also the `expires_in` returned by `/admin/session`) |
|
||||||
| `ttl::RETRY_COUNTER_SECONDS` | 86_400 | `retry:{stream}:{message.id}` |
|
| `ttl::RETRY_COUNTER_SECONDS` | 86_400 | `retry:{stream}:{message.id}` |
|
||||||
| `ttl::CONSENT_TEMPORARY_SECONDS` | 3_600 | `consent:ai:{chat_id}` ("temporary/once" shared with explicit `/ai on`) |
|
| `ttl::CONSENT_TEMPORARY_SECONDS` | 3_600 | `consent:ai:{chat_id}` ("temporary/once" shared with explicit `/ai on`) |
|
||||||
| `ttl::CONSENT_TODAY_SECONDS` | 86_400 | `consent:ai:{chat_id}` ("Today") |
|
| `ttl::CONSENT_TODAY_SECONDS` | 86_400 | `consent:ai:{chat_id}` ("Today") |
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ TTL 那条真机绿灯已经用你给的 Upstash URL 跑过了(见 §1),
|
||||||
| `ttl::PUSH_SUBSCRIPTION_SECONDS` | 300 | `push:subscription:{id}` / `push:subscription-code:{code}` |
|
| `ttl::PUSH_SUBSCRIPTION_SECONDS` | 300 | `push:subscription:{id}` / `push:subscription-code:{code}` |
|
||||||
| `ttl::PUSH_REGISTRATION_SECONDS` | 604_800 | `push:registration:{sha256(callback_url)}` |
|
| `ttl::PUSH_REGISTRATION_SECONDS` | 604_800 | `push:registration:{sha256(callback_url)}` |
|
||||||
| `ttl::PUSH_ORPHAN_SECONDS` | 604_800 | `push:orphan:{subscription_id}` |
|
| `ttl::PUSH_ORPHAN_SECONDS` | 604_800 | `push:orphan:{subscription_id}` |
|
||||||
| `ttl::ADMIN_SESSION_SECONDS` | 900 | `admin-session:{token}`(同时是 `/admin/session` 返回的 `expires_in`) |
|
| `ttl::ADMIN_SESSION_SECONDS` | 1,800 | `admin-session:{token}`(同时是 `/admin/session` 返回的 `expires_in`) |
|
||||||
| `ttl::RETRY_COUNTER_SECONDS` | 86_400 | `retry:{stream}:{message.id}` |
|
| `ttl::RETRY_COUNTER_SECONDS` | 86_400 | `retry:{stream}:{message.id}` |
|
||||||
| `ttl::CONSENT_TEMPORARY_SECONDS` | 3_600 | `consent:ai:{chat_id}`(「临时 / 一次」与显式 `/ai on` 共用) |
|
| `ttl::CONSENT_TEMPORARY_SECONDS` | 3_600 | `consent:ai:{chat_id}`(「临时 / 一次」与显式 `/ai on` 共用) |
|
||||||
| `ttl::CONSENT_TODAY_SECONDS` | 86_400 | `consent:ai:{chat_id}`(「今天」) |
|
| `ttl::CONSENT_TODAY_SECONDS` | 86_400 | `consent:ai:{chat_id}`(「今天」) |
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ Conventions used throughout:
|
||||||
| `config:business:revision` | No EX | atomic `INCR` on every config write; `SET 1 NX` on first-time init | `business_config_revision` |
|
| `config:business:revision` | No EX | atomic `INCR` on every config write; `SET 1 NX` on first-time init | `business_config_revision` |
|
||||||
| `config:outbound` | No EX | `set_outbound_config` | `get_outbound_config` |
|
| `config:outbound` | No EX | `set_outbound_config` | `get_outbound_config` |
|
||||||
| `config:enabled` | No EX | `set_enabled` | `is_enabled` |
|
| `config:enabled` | No EX | `set_enabled` | `is_enabled` |
|
||||||
| `config:admin_session` | EX 900 | `put_admin_session` | `admin_session_valid`; cleared by `revoke_admin_session` |
|
| `config:admin_session` | EX 1800 (30 minutes) | `put_admin_session` | `admin_session_valid`; cleared by `revoke_admin_session` |
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
|
|
@ -46,8 +46,8 @@ Notes:
|
||||||
request-bearing entry point calls `refresh_business_config`, which only
|
request-bearing entry point calls `refresh_business_config`, which only
|
||||||
rebuilds the worker when the remote revision exceeds the cached local value — that
|
rebuilds the worker when the remote revision exceeds the cached local value — that
|
||||||
guard is what keeps a stale or malformed snapshot from turning into a rebuild loop.
|
guard is what keeps a stale or malformed snapshot from turning into a rebuild loop.
|
||||||
- `config:admin_session` carries no TTL metadata beyond the literal `EX 900` passed at write
|
- `config:admin_session` carries no TTL metadata beyond the literal `EX 1800` passed at write
|
||||||
time; the handler reports the same window in its response body as `expires_in: 900`
|
time; the handler reports the same window in its response body as `expires_in: 1800`
|
||||||
on the handler side.
|
on the handler side.
|
||||||
- `config:enabled` is consulted as a gate; missing or `false` keeps business processing off.
|
- `config:enabled` is consulted as a gate; missing or `false` keeps business processing off.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
| `配置:业务:修订版` |没有 EX |每次配置写入时原子“INCR”;首次初始化时“SET 1 NX”| `business_config_revision` |
|
| `配置:业务:修订版` |没有 EX |每次配置写入时原子“INCR”;首次初始化时“SET 1 NX”| `business_config_revision` |
|
||||||
| `配置:出站` |没有 EX | `set_outbound_config` | `get_outbound_config` |
|
| `配置:出站` |没有 EX | `set_outbound_config` | `get_outbound_config` |
|
||||||
| `配置:启用` |没有 EX | `设置启用` | `已启用` |
|
| `配置:启用` |没有 EX | `设置启用` | `已启用` |
|
||||||
| `配置:admin_session` |前 900 | `put_admin_session` | `admin_session_valid`;由 `revoke_admin_session` 清除 |
|
| `配置:admin_session` | EX 1800(30 分钟) | `put_admin_session` | `admin_session_valid`;由 `revoke_admin_session` 清除 |
|
||||||
|
|
||||||
笔记:
|
笔记:
|
||||||
|
|
||||||
|
|
@ -46,9 +46,8 @@
|
||||||
承载请求的入口点调用“refresh_business_config”,这仅
|
承载请求的入口点调用“refresh_business_config”,这仅
|
||||||
当远程修订超出缓存的本地值时重建工作程序 - 即
|
当远程修订超出缓存的本地值时重建工作程序 - 即
|
||||||
Guard 可以防止陈旧或格式错误的快照变成重建循环。
|
Guard 可以防止陈旧或格式错误的快照变成重建循环。
|
||||||
- `config:admin_session` 不携带超出写入时传递的文字 `EX 900` 的 TTL 元数据
|
- `config:admin_session` 的 TTL 由写入时传入的 `EX 1800` 决定;处理程序也在响应正文中
|
||||||
时间;处理程序在其响应正文中报告相同的窗口“expires_in: 900”
|
通过 `expires_in: 1800` 返回相同的有效期。
|
||||||
在处理程序一侧。
|
|
||||||
- `config:enabled` 被视为一个门;缺失或“错误”会导致业务处理中断。
|
- `config:enabled` 被视为一个门;缺失或“错误”会导致业务处理中断。
|
||||||
|
|
||||||
### 1.2 AI 授权
|
### 1.2 AI 授权
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ pub(crate) mod ttl {
|
||||||
pub const PUSH_ORPHAN_SECONDS: u64 = WEEK;
|
pub const PUSH_ORPHAN_SECONDS: u64 = WEEK;
|
||||||
/// `/admin` digest session. Must match the `expires_in` reported to the
|
/// `/admin` digest session. Must match the `expires_in` reported to the
|
||||||
/// admin client.
|
/// admin client.
|
||||||
pub const ADMIN_SESSION_SECONDS: u64 = 900;
|
pub const ADMIN_SESSION_SECONDS: u64 = 1_800;
|
||||||
/// Retry counter retention. `retry_or_dlq` interpolates this into its Lua
|
/// Retry counter retention. `retry_or_dlq` interpolates this into its Lua
|
||||||
/// script, so there is exactly one literal for it.
|
/// script, so there is exactly one literal for it.
|
||||||
pub const RETRY_COUNTER_SECONDS: u64 = DAY;
|
pub const RETRY_COUNTER_SECONDS: u64 = DAY;
|
||||||
|
|
@ -1523,7 +1523,7 @@ mod tests {
|
||||||
assert_eq!(ttl::PUSH_SUBSCRIPTION_SECONDS, 300);
|
assert_eq!(ttl::PUSH_SUBSCRIPTION_SECONDS, 300);
|
||||||
assert_eq!(ttl::PUSH_REGISTRATION_SECONDS, 604_800);
|
assert_eq!(ttl::PUSH_REGISTRATION_SECONDS, 604_800);
|
||||||
assert_eq!(ttl::PUSH_ORPHAN_SECONDS, 604_800);
|
assert_eq!(ttl::PUSH_ORPHAN_SECONDS, 604_800);
|
||||||
assert_eq!(ttl::ADMIN_SESSION_SECONDS, 900);
|
assert_eq!(ttl::ADMIN_SESSION_SECONDS, 1_800);
|
||||||
|
|
||||||
assert_eq!(ttl::DEDUP_TG_SECONDS, 86_400);
|
assert_eq!(ttl::DEDUP_TG_SECONDS, 86_400);
|
||||||
assert_eq!(ttl::DEDUP_JMAP_SECONDS, 86_400);
|
assert_eq!(ttl::DEDUP_JMAP_SECONDS, 86_400);
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
"auth.eyebrow": "Authorization required",
|
"auth.eyebrow": "Authorization required",
|
||||||
"auth.title": "Create admin session",
|
"auth.title": "Create admin session",
|
||||||
"auth.bodyPre": "Enter ",
|
"auth.bodyPre": "Enter ",
|
||||||
"auth.bodyPost": ". The session lasts 15 minutes and lives only in this page's memory.",
|
"auth.bodyPost": ". The session lasts 30 minutes and lives only in this page's memory.",
|
||||||
"auth.label": "Business encryption key",
|
"auth.label": "Business encryption key",
|
||||||
"auth.placeholder": "Paste the value",
|
"auth.placeholder": "Paste the value",
|
||||||
"auth.submit": "Create session",
|
"auth.submit": "Create session",
|
||||||
|
|
@ -144,7 +144,7 @@
|
||||||
"runtime.savedToast": "Runtime parameters saved to Redis and applied immediately to subsequent requests.",
|
"runtime.savedToast": "Runtime parameters saved to Redis and applied immediately to subsequent requests.",
|
||||||
"runtime.defaultsToast": "Runtime parameters restored to default-value preview. They are written to Redis only after clicking \"Save runtime parameters\".",
|
"runtime.defaultsToast": "Runtime parameters restored to default-value preview. They are written to Redis only after clicking \"Save runtime parameters\".",
|
||||||
"privacy.title": "Secrets are never echoed or persisted to the browser.",
|
"privacy.title": "Secrets are never echoed or persisted to the browser.",
|
||||||
"privacy.body": "Business configuration is submitted only to the same-origin API and encrypted into Redis by the backend; this page never reads mailbox contents and uses no local files or database.",
|
"privacy.body": "Your settings are encrypted before they are saved on the server. Email contents are not shown here.",
|
||||||
"footer.note": "Configuration managed by your server",
|
"footer.note": "Configuration managed by your server",
|
||||||
"common.required": "Required",
|
"common.required": "Required",
|
||||||
"common.optional": "Optional",
|
"common.optional": "Optional",
|
||||||
|
|
@ -247,7 +247,7 @@
|
||||||
"auth.eyebrow": "需要授权",
|
"auth.eyebrow": "需要授权",
|
||||||
"auth.title": "管理员授权",
|
"auth.title": "管理员授权",
|
||||||
"auth.bodyPre": "输入 ",
|
"auth.bodyPre": "输入 ",
|
||||||
"auth.bodyPost": ",会话有效 15 分钟,仅保存在当前页面。",
|
"auth.bodyPost": ",会话有效 30 分钟,仅保存在当前页面。",
|
||||||
"auth.label": "业务密钥",
|
"auth.label": "业务密钥",
|
||||||
"auth.placeholder": "粘贴部署密钥",
|
"auth.placeholder": "粘贴部署密钥",
|
||||||
"auth.submit": "授权",
|
"auth.submit": "授权",
|
||||||
|
|
@ -357,8 +357,8 @@
|
||||||
"runtime.readToast": "运行参数已读取。业务配置仍需手动完整填写。",
|
"runtime.readToast": "运行参数已读取。业务配置仍需手动完整填写。",
|
||||||
"runtime.savedToast": "运行参数已保存到 Redis,并立即应用于后续请求。",
|
"runtime.savedToast": "运行参数已保存到 Redis,并立即应用于后续请求。",
|
||||||
"runtime.defaultsToast": "运行参数已恢复为默认值预览。点击“保存运行参数”后才会更新 Redis。",
|
"runtime.defaultsToast": "运行参数已恢复为默认值预览。点击“保存运行参数”后才会更新 Redis。",
|
||||||
"privacy.title": "密钥不会显示或保存到浏览器。",
|
"privacy.title": "密钥不会显示或保存在浏览器里。",
|
||||||
"privacy.body": "配置仅经同源 API 提交,并由后端加密保存。",
|
"privacy.body": "你的设置会加密后保存在服务器上。这里不会显示邮件内容。",
|
||||||
"footer.note": "配置由你的服务端管理",
|
"footer.note": "配置由你的服务端管理",
|
||||||
"common.required": "必填",
|
"common.required": "必填",
|
||||||
"common.optional": "可选",
|
"common.optional": "可选",
|
||||||
|
|
@ -836,7 +836,7 @@
|
||||||
|
|
||||||
function scheduleSessionExpiry(seconds) {
|
function scheduleSessionExpiry(seconds) {
|
||||||
if (expiryTimer) window.clearTimeout(expiryTimer);
|
if (expiryTimer) window.clearTimeout(expiryTimer);
|
||||||
const duration = Math.max(1, Math.min(Number(seconds) || 900, 900));
|
const duration = Math.max(1, Math.min(Number(seconds) || 1_800, 1_800));
|
||||||
sessionExpiry.textContent = t("session.expiry", { n: Math.ceil(duration / 60) });
|
sessionExpiry.textContent = t("session.expiry", { n: Math.ceil(duration / 60) });
|
||||||
expiryTimer = window.setTimeout(() => {
|
expiryTimer = window.setTimeout(() => {
|
||||||
expireSession(t("session.expired"));
|
expireSession(t("session.expired"));
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div><p class="eyebrow" data-i18n="auth.eyebrow">Authorization required</p><h2 id="auth-title" data-i18n="auth.title">Create admin session</h2></div>
|
<div><p class="eyebrow" data-i18n="auth.eyebrow">Authorization required</p><h2 id="auth-title" data-i18n="auth.title">Create admin session</h2></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="panel-copy"><span data-i18n="auth.bodyPre">Enter </span><code>CONFIG_ENCRYPTION_KEY</code><span data-i18n="auth.bodyPost">. The session lasts 15 minutes and lives only in this page's memory.</span></p>
|
<p class="panel-copy"><span data-i18n="auth.bodyPre">Enter </span><code>CONFIG_ENCRYPTION_KEY</code><span data-i18n="auth.bodyPost">. The session lasts 30 minutes and lives only in this page's memory.</span></p>
|
||||||
<form id="auth-form" class="auth-form" autocomplete="off">
|
<form id="auth-form" class="auth-form" autocomplete="off">
|
||||||
<label for="bootstrap-input" data-i18n="auth.label">Business encryption key</label>
|
<label for="bootstrap-input" data-i18n="auth.label">Business encryption key</label>
|
||||||
<div class="token-row">
|
<div class="token-row">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue