From 4a2c53204f63b982c6daf3e6508362b439168ac5 Mon Sep 17 00:00:00 2001 From: zikai Date: Wed, 22 Jul 2026 02:43:29 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20crypto.randomUUID=20=E5=9C=A8=E9=9D=9E?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E4=B8=8A=E4=B8=8B=E6=96=87(=E9=9D=9EHTTPS)?= =?UTF-8?q?=E4=B8=8B=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 src/lib/uuid.js 提供 genUUID(), 优先使用 crypto.randomUUID, 不可用时回退到 getRandomValues 手动拼装 v4 UUID, 最终回退到 Math.random。 原因: crypto.randomUUID() 仅在安全上下文(HTTPS 或 localhost)可用。 当前站点通过 http://f.zikai.wang:8888 访问, 属于非安全上下文, 导致 event-factory.js 的新增日程和 split.js 的拆分事件功能崩溃。 涉及文件: - src/lib/uuid.js (新增): 带 fallback 的 UUID 生成 - src/lib/event-factory.js: crypto.randomUUID -> genUUID - src/lib/split.js: crypto.randomUUID -> genUUID --- src/lib/event-factory.js | 3 ++- src/lib/split.js | 3 ++- src/lib/uuid.js | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/lib/uuid.js diff --git a/src/lib/event-factory.js b/src/lib/event-factory.js index 925cfb3..9df22fb 100644 --- a/src/lib/event-factory.js +++ b/src/lib/event-factory.js @@ -6,6 +6,7 @@ * and cloning so that useCalendar.js stays focused on state management. */ import { todayISO, nowCompactTimestamp } from './date.js' +import { genUUID } from './uuid.js' /** * Create a new single-occurrence event with sensible defaults. @@ -14,7 +15,7 @@ import { todayISO, nowCompactTimestamp } from './date.js' */ export function createEvent(overrides = {}) { return { - uid: crypto.randomUUID(), + uid: genUUID(), summary: '新日程', location: '', description: '', diff --git a/src/lib/split.js b/src/lib/split.js index 7d6a6ae..886d5f9 100644 --- a/src/lib/split.js +++ b/src/lib/split.js @@ -12,6 +12,7 @@ */ import { intervalDays } from './recur.js' import { cloneEvent } from './event-factory.js' +import { genUUID } from './uuid.js' import { toDate, toISODate, addDays, daysBetween } from './date.js' /** Snap a date forward to the next grid point on or after it. */ @@ -42,7 +43,7 @@ export function splitRecurringEvent(ev, splitDate) { partA.exdates = ev.exdates.filter((d) => d < splitDate) const partB = cloneEvent(ev) - partB.uid = crypto.randomUUID() + partB.uid = genUUID() partB.dtstartDate = snapStr partB.exdates = ev.exdates.filter((d) => d >= splitDate) diff --git a/src/lib/uuid.js b/src/lib/uuid.js new file mode 100644 index 0000000..66f93b3 --- /dev/null +++ b/src/lib/uuid.js @@ -0,0 +1,37 @@ +/** + * UUID 生成工具。 + * + * 优先使用 crypto.randomUUID(), 但该方法仅在安全上下文 (HTTPS 或 localhost) + * 中可用。当前站点通过 http://f.zikai.wang:8888 访问, 属于非安全上下文, + * crypto.randomUUID 会是 undefined, 因此需要回退方案。 + * + * 回退一: 用 crypto.getRandomValues (不受安全上下文限制) 手动拼装 + * RFC 4122 version 4 UUID。 + * 回退二: 若 crypto 对象完全不存在 (如旧版 Node 直接运行 .mjs), 用 + * Math.random 拼装, 牺牲少量随机性但保证可用。 + */ + +/** + * 生成一个 RFC 4122 version 4 UUID 字符串。 + * @returns {string} 形如 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' + */ +export function genUUID() { + const c = typeof globalThis !== 'undefined' ? globalThis.crypto : undefined + if (c && typeof c.randomUUID === 'function') { + return c.randomUUID() + } + if (c && typeof c.getRandomValues === 'function') { + const bytes = new Uint8Array(16) + c.getRandomValues(bytes) + bytes[6] = (bytes[6] & 0x0f) | 0x40 // version 4 + bytes[8] = (bytes[8] & 0x3f) | 0x80 // variant + const h = [...bytes].map((b) => b.toString(16).padStart(2, '0')) + return `${h.slice(0, 4).join('')}-${h.slice(4, 6).join('')}-${h.slice(6, 8).join('')}-${h.slice(8, 10).join('')}-${h.slice(10, 16).join('')}` + } + // 最终回退: Math.random + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (ch) => { + const r = (Math.random() * 16) | 0 + const v = ch === 'x' ? r : (r & 0x3) | 0x8 + return v.toString(16) + }) +}