From ec41d50d92f1fd389439463e1a8dd1d19d19b407 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 28 Sep 2026 15:37:22 +0900 Subject: [PATCH] =?UTF-8?q?fix(A00=C2=B7B07=20CAD):=20http=20+=20IP=20?= =?UTF-8?q?=EC=A3=BC=EC=86=8C(Tailscale)=EC=97=90=EC=84=9C=20CAD=20?= =?UTF-8?q?=EA=B0=80=20=EC=A3=BD=EB=8D=98=20=EA=B2=83=20=E2=80=94=20crypto?= =?UTF-8?q?.randomUUID=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 보안 문맥이 아닌 http + IP 에서는 crypto.randomUUID 가 없어 CAD 개체 만들기에서 멈춤. 앱 본체(A00_Common/main.ts)와 CAD(openwebcad/src/main.tsx) 진입 맨 앞에서 getRandomValues 로 v4 UUID 를 채움 · 이미 있으면 그대로. crypto.subtle(B03 지문) · serviceWorker(B03) 는 이미 없을 때 건너뜀 · navigator.clipboard 는 안 씀. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01K7JS47SacjPxZ718QsZKyr --- A00_Common/main.ts | 1 + A00_Common/random_uuid_polyfill.ts | 16 ++++++++++++ B07_DesignDetail/openwebcad/src/main.tsx | 1 + .../openwebcad/src/random-uuid-polyfill.ts | 16 ++++++++++++ .../tester/cad/random-uuid-polyfill.test.ts | 26 +++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 A00_Common/random_uuid_polyfill.ts create mode 100644 B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts create mode 100644 resources/tester/cad/random-uuid-polyfill.test.ts diff --git a/A00_Common/main.ts b/A00_Common/main.ts index 192dc84f..3ffa2037 100644 --- a/A00_Common/main.ts +++ b/A00_Common/main.ts @@ -8,6 +8,7 @@ * - hashchange 1회 구독: 셸 chrome 갱신 + 현재 라우트 렌더 * ========================================================================== */ +import "./random_uuid_polyfill"; import "@ui/ui_template_theme.css"; import { injectBaseStyles } from "@ui/ui_template_elements"; import { ROUTES, type RoutePath } from "@config/config_frontend"; diff --git a/A00_Common/random_uuid_polyfill.ts b/A00_Common/random_uuid_polyfill.ts new file mode 100644 index 00000000..edc40154 --- /dev/null +++ b/A00_Common/random_uuid_polyfill.ts @@ -0,0 +1,16 @@ +/** + * http + IP 주소(예: Tailscale)는 보안 문맥이 아니라 `crypto.randomUUID` 가 없음. + * getRandomValues(보안 문맥 아니어도 됨)로 v4 UUID 를 채움 · 이미 있으면 그대로. + * `main.ts` 가 맨 먼저 부름. CAD 짝 = `B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts`. + */ +if (typeof crypto !== "undefined" && typeof crypto.randomUUID !== "function") { + crypto.randomUUID = () => { + const bytes = crypto.getRandomValues(new Uint8Array(16)); + bytes[6] = (bytes[6] & 0x0f) | 0x40; + bytes[8] = (bytes[8] & 0x3f) | 0x80; + const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""); + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}` as `${string}-${string}-${string}-${string}-${string}`; + }; +} + +export {}; diff --git a/B07_DesignDetail/openwebcad/src/main.tsx b/B07_DesignDetail/openwebcad/src/main.tsx index bc8f2dab..795a65e8 100644 --- a/B07_DesignDetail/openwebcad/src/main.tsx +++ b/B07_DesignDetail/openwebcad/src/main.tsx @@ -1,3 +1,4 @@ +import './random-uuid-polyfill'; import { Point } from '@flatten-js/core'; import React from 'react'; import ReactDOM from 'react-dom/client'; diff --git a/B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts b/B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts new file mode 100644 index 00000000..ea537f5c --- /dev/null +++ b/B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts @@ -0,0 +1,16 @@ +/** + * http + IP 주소(예: Tailscale)는 보안 문맥이 아니라 `crypto.randomUUID` 가 없음 — 개체 만들기에서 죽음. + * getRandomValues(보안 문맥 아니어도 됨)로 v4 UUID 를 채움 · 이미 있으면 그대로. + * `main.tsx` 가 맨 먼저 부름. 앱 본체 짝 = `A00_Common/random_uuid_polyfill.ts`. + */ +if (typeof crypto !== 'undefined' && typeof crypto.randomUUID !== 'function') { + crypto.randomUUID = () => { + const bytes = crypto.getRandomValues(new Uint8Array(16)); + bytes[6] = (bytes[6] & 0x0f) | 0x40; + bytes[8] = (bytes[8] & 0x3f) | 0x80; + const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join(''); + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}` as `${string}-${string}-${string}-${string}-${string}`; + }; +} + +export {}; diff --git a/resources/tester/cad/random-uuid-polyfill.test.ts b/resources/tester/cad/random-uuid-polyfill.test.ts new file mode 100644 index 00000000..9c35a3da --- /dev/null +++ b/resources/tester/cad/random-uuid-polyfill.test.ts @@ -0,0 +1,26 @@ +/** + * http + IP(보안 문맥 아님)에서 비는 crypto.randomUUID 대체 검증 — CAD · 앱 본체 두 벌. + * 실행: node --experimental-strip-types resources/tester/cad/random-uuid-polyfill.test.ts + */ +import assert from 'node:assert/strict'; + +const V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/; +const native = crypto.randomUUID; + +for (const path of [ + '../../../B07_DesignDetail/openwebcad/src/random-uuid-polyfill.ts', + '../../../A00_Common/random_uuid_polyfill.ts', +]) { + // biome-ignore lint: 시험 — 보안 문맥 아닌 브라우저처럼 비움 + (crypto as any).randomUUID = undefined; + await import(`${path}?${Math.random()}`); + const ids = Array.from({ length: 200 }, () => crypto.randomUUID()); + assert.ok(ids.every((id) => V4.test(id)), `${path}: v4 모양`); + assert.equal(new Set(ids).size, ids.length, `${path}: 안 겹침`); +} + +// 이미 있으면 그대로 +crypto.randomUUID = native; +await import(`../../../A00_Common/random_uuid_polyfill.ts?${Math.random()}`); +assert.equal(crypto.randomUUID, native, '원래 것 유지'); +console.log('random-uuid 대체 시험 통과');