Repository navigation
Expand file tree
/
Copy pathdev-code-drop.html
More file actions
153 lines (144 loc) · 12.8 KB
/
Copy pathdev-code-drop.html
File metadata and controls
153 lines (144 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<!doctype html>
<html lang="th">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Code Drop — lsuperagen.docs</title>
<meta name="description" content="Client-side code drop and secret redaction workspace for lsuperagen.docs"/>
<style>
:root{--bg:#090a12;--panel:#10111c;--panel2:#151521;--line:#302c3b;--line2:#474050;--fg:#f5f7f9;--fg2:#a2a7b0;--fg3:#7c828c;--acc:#f4bc91;--danger:#ff7a7a;--ok:#79dda8;--warn:#f7d889;--font:Inter,"Noto Sans Thai",system-ui,sans-serif;--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}*{box-sizing:border-box}body{margin:0;min-height:100vh;background:#090a12;color:var(--fg);font-family:var(--font);line-height:1.6}.bp{position:fixed;inset:0;pointer-events:none;background-image:linear-gradient(rgba(154,123,160,.07) 1px,transparent 1px),linear-gradient(90deg,rgba(154,123,160,.07) 1px,transparent 1px);background-size:56px 56px;mask-image:radial-gradient(ellipse 90% 62% at 50% 0,#000 30%,transparent 100%)}.wrap{position:relative;z-index:1;max-width:1120px;margin:0 auto;padding:24px clamp(18px,4vw,42px) 64px}.top{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:8px 0 26px}.brand{display:flex;align-items:center;gap:12px;font-weight:900;letter-spacing:-.04em}.mark{width:44px;height:44px;border:1px solid #5b5162;border-radius:14px;background:#0d0e18;display:grid;place-items:center}.tag{font-family:var(--mono);font-size:.68rem;letter-spacing:.18em;color:var(--fg3)}a{color:inherit}.back{border:1px solid var(--line2);border-radius:999px;padding:9px 13px;text-decoration:none;color:var(--fg2);font-size:.9rem}h1{font-size:clamp(2.4rem,9vw,4.9rem);line-height:.98;letter-spacing:-.06em;margin:14px 0 12px}.lede{color:var(--fg2);max-width:760px;font-size:1.06rem}.warn{margin:20px 0 26px;border:1px solid rgba(247,216,137,.22);border-left:3px solid var(--warn);border-radius:16px;background:rgba(247,216,137,.06);padding:14px 16px;color:#e8dec1}.grid{display:grid;grid-template-columns:1.08fr .92fr;gap:16px;align-items:start}.card{border:1px solid var(--line);border-radius:22px;background:linear-gradient(180deg,rgba(18,19,22,.84),rgba(7,7,8,.94));padding:18px;box-shadow:0 24px 70px rgba(0,0,0,.24)}.card h2{margin:0 0 10px;font-size:1.15rem;letter-spacing:-.025em}label{display:block;font-family:var(--mono);font-size:.72rem;color:var(--fg3);letter-spacing:.14em;margin:0 0 8px}textarea,input{width:100%;border:1px solid var(--line2);border-radius:16px;background:#0d0e18;color:var(--fg);font:14px/1.55 var(--mono);padding:14px;outline:none}textarea{min-height:430px;resize:vertical}textarea:focus,input:focus{border-color:rgba(142,198,255,.62);box-shadow:0 0 0 3px rgba(142,198,255,.08)}.row{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:0 0 12px}.actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}.btn{border:1px solid var(--line2);border-radius:999px;background:#0d0e18;color:var(--fg);min-height:44px;padding:0 15px;font-weight:800;cursor:pointer}.btn.primary{background:#fff;color:#090a12;border-color:#fff}.btn.danger{border-color:rgba(255,122,122,.42);color:#ffd5d5}.status{margin-top:12px;border:1px solid var(--line);border-radius:14px;background:#0d0e18;padding:10px 12px;color:var(--fg2);font-size:.92rem}.status.ok{border-color:rgba(121,221,168,.25);color:#c9f2db}.status.warn{border-color:rgba(247,216,137,.28);color:#f0dfad}.stats{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:14px 0}.stat{border:1px solid var(--line);border-radius:14px;background:#0d0e18;padding:12px}.stat b{display:block;font-size:1.25rem}.stat span{font-family:var(--mono);font-size:.68rem;color:var(--fg3);letter-spacing:.12em}.findings{display:grid;gap:8px;margin-top:12px}.finding{border:1px solid var(--line);border-radius:14px;background:#0d0e18;padding:10px 12px;color:var(--fg2);font-size:.92rem}.finding strong{color:var(--fg)}.finding.danger{border-color:rgba(255,122,122,.26)}.finding.ok{border-color:rgba(121,221,168,.25)}pre{white-space:pre-wrap;word-break:break-word;background:#0d0e18;border:1px solid var(--line);border-radius:16px;padding:14px;max-height:360px;overflow:auto;color:#dfe3e8;font:12px/1.55 var(--mono)}.small{font-size:.82rem;color:var(--fg3);margin-top:10px}@media(max-width:860px){.grid{grid-template-columns:1fr}.top{align-items:flex-start;flex-direction:column}.row{grid-template-columns:1fr}textarea{min-height:360px}}
</style>
<link rel="stylesheet" href="/assets/layout.css?v=1">
<link rel="stylesheet" href="/assets/theme.css?v=3"><link rel="stylesheet" href="/assets/editorial.css?v=1">
</head>
<body data-ls-code-drop="v2" class="sdk-layout sdk-standard">
<header class="top sdk-site-header"><div class="sdk-frame sdk-header-row"><div class="brand"><img class="brand-mark" src="/logo.svg" alt="" width="22" height="22"><div><div>Code Drop</div><div class="tag">CLIENT-SIDE · SECRET REDACTION</div></div></div><a class="back" href="/dev">กลับ /dev</a></div></header>
<div class="bp" aria-hidden="true"></div>
<main class="wrap sdk-frame">
<section>
<div class="tag">OWNER WORKSPACE TOOL</div>
<h1>ใส่โค้ดยาวตรงนี้</h1>
<p class="lede">วางโค้ดและระบุเป้าหมาย สแกนข้อมูลสำคัญ แล้วคัดลอกหรือดาวน์โหลดชุดข้อมูลสำหรับตรวจโค้ด</p>
<div class="warn"><b>กติกา:</b> ตรวจผลการสแกนและแทนข้อมูลสำคัญด้วย <code>[REDACTED_*]</code> ก่อน copy/download</div>
</section>
<section class="grid">
<div class="card">
<h2>Input</h2>
<div class="row"><div><label>ชื่อไฟล์ / module</label><input id="name" value="openai-generation-bridge.ts"/></div><div><label>เป้าหมายที่อยากให้ตรวจ</label><input id="goal" value="review OpenAI API generation bridge and suggest integration path"/></div></div>
<label>วางโค้ดที่นี่</label>
<textarea id="code" spellcheck="false" placeholder="paste long code here..."></textarea>
<div class="actions"><button class="btn primary" id="scan" type="button">Scan + Redact</button><button class="btn" id="copy" type="button">Copy review packet</button><button class="btn" id="download" type="button">Download .md</button><button class="btn danger" id="clear" type="button">Clear</button></div>
<div class="status warn" id="status">พร้อมรับโค้ด · วางแล้วระบบจะสแกนอัตโนมัติ หรือกด Scan + Redact</div>
<p class="small">ดาวน์โหลดชุดตรวจโค้ดหรือคัดลอกไปใช้กับผู้ช่วยพัฒนา</p>
</div>
<div class="card">
<h2>Safe Review Packet</h2>
<div class="stats"><div class="stat"><b id="lines">0</b><span>LINES</span></div><div class="stat"><b id="chars">0</b><span>CHARS</span></div><div class="stat"><b id="hits">0</b><span>SECRET HITS</span></div><div class="stat"><b id="hash">—</b><span>SHA-256 PREFIX</span></div></div>
<div class="findings" id="findings"><div class="finding ok">ยังไม่ได้สแกน</div></div>
<pre id="packet">กด Scan + Redact เพื่อสร้างแพ็กเกจ</pre>
</div>
</section>
</main>
<script>
(() => {
const $ = (id) => document.getElementById(id);
const patterns = [
['OPENAI_PROJECT_KEY', /sk-proj-[A-Za-z0-9_-]{20,}/g],
['OPENAI_API_KEY', /sk-(?!proj-)[A-Za-z0-9_-]{20,}/g],
['CLOUDFLARE_TOKEN', /cfat_[A-Za-z0-9_-]{20,}/g],
['ANTHROPIC_API_KEY', /sk-ant-[A-Za-z0-9_-]{20,}/g],
['GOOGLE_CLIENT_SECRET', /GOCSPX-[A-Za-z0-9_-]+/g],
['GITHUB_TOKEN', /gh[pousr]_[A-Za-z0-9_]{20,}/g],
['JWT', /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g],
['GENERIC_SECRET_ASSIGN', /(?:(?:api|access|secret|private|client)[_-]?(?:key|token|secret|password))\s*[:=]\s*["'][^"']{12,}["']/gi]
];
async function sha256(text) {
if (!globalThis.crypto || !crypto.subtle) return 'crypto-subtle-unavailable';
const data = new TextEncoder().encode(text);
const hash = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, '0')).join('');
}
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
}
function setStatus(message, mode = 'warn') {
const box = $('status');
box.textContent = message;
box.className = 'status ' + mode;
}
function redact(raw) {
let out = raw;
const hits = [];
for (const [name, rx] of patterns) {
out = out.replace(rx, (match) => {
hits.push({ type: name, preview: match.slice(0, 10) + '…', length: match.length });
return '[REDACTED_' + name + ']';
});
}
return { out, hits };
}
async function build({ silent = false } = {}) {
const raw = $('code').value || '';
const filename = ($('name').value || 'code-drop.txt').trim();
const goal = ($('goal').value || 'review this code').trim();
const result = redact(raw);
const hash = raw ? await sha256(raw) : '';
const lineCount = raw ? raw.split(/\r\n|\r|\n/).length : 0;
$('lines').textContent = String(lineCount);
$('chars').textContent = String(raw.length);
$('hits').textContent = String(result.hits.length);
$('hash').textContent = hash ? hash.slice(0, 12) : '—';
$('findings').innerHTML = result.hits.length
? result.hits.map((h) => '<div class="finding danger"><strong>' + escapeHtml(h.type) + '</strong> masked · ' + h.length + ' chars · ' + escapeHtml(h.preview) + '</div>').join('')
: '<div class="finding ok">ไม่พบ pattern secret เบื้องต้น</div>';
const packet = `# LSUPERAGEN Code Review Packet\n\n## Goal\n${goal}\n\n## Source\n- file: ${filename}\n- raw_sha256_prefix: ${hash ? hash.slice(0, 16) : 'empty'}\n- lines: ${lineCount}\n- chars: ${raw.length}\n- secret_hits_masked: ${result.hits.length}\n\n## Review request\nตรวจโค้ดนี้แบบ practical: architecture, security, OpenAI API integration, Cloudflare compatibility, missing env secrets, and exact next patch. Do not assume hidden files.\n\n## Redacted code\n\`\`\`ts\n${result.out}\n\`\`\`\n`;
$('packet').textContent = packet;
localStorage.setItem('ls_code_drop_packet', packet);
if (!silent) setStatus(raw ? 'สแกนแล้ว · สร้าง Safe Review Packet แล้ว' : 'ยังไม่มีโค้ดในกล่อง input', raw ? 'ok' : 'warn');
return packet;
}
let timer = null;
function scheduleBuild() {
clearTimeout(timer);
setStatus('รับโค้ดแล้ว · กำลังเตรียมสแกน...', 'warn');
timer = setTimeout(() => build({ silent: true }).then(() => setStatus('สแกนอัตโนมัติแล้ว · กด Copy หรือ Download ได้เลย', 'ok')), 450);
}
$('scan').addEventListener('click', () => build());
$('code').addEventListener('input', scheduleBuild);
$('name').addEventListener('input', scheduleBuild);
$('goal').addEventListener('input', scheduleBuild);
$('copy').addEventListener('click', async () => {
const packet = await build({ silent: true });
await navigator.clipboard.writeText(packet);
$('copy').textContent = 'Copied';
setStatus('Copy แล้ว · เอามาวางในแชตหรือโหลดเป็น .md ได้', 'ok');
setTimeout(() => { $('copy').textContent = 'Copy review packet'; }, 1200);
});
$('download').addEventListener('click', async () => {
const packet = await build({ silent: true });
const blob = new Blob([packet], { type: 'text/markdown;charset=utf-8' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'lsuperagen-code-review-packet.md';
document.body.appendChild(a);
a.click();
a.remove();
setStatus('ดาวน์โหลด .md แล้ว · อัปโหลดไฟล์นั้นกลับมาที่แชตนี้', 'ok');
setTimeout(() => URL.revokeObjectURL(a.href), 1500);
});
$('clear').addEventListener('click', () => {
if (!confirm('Clear local code input?')) return;
$('code').value = '';
$('packet').textContent = 'กด Scan + Redact เพื่อสร้างแพ็กเกจ';
$('findings').innerHTML = '<div class="finding ok">ล้างข้อมูลแล้ว</div>';
localStorage.removeItem('ls_code_drop_packet');
$('lines').textContent = '0';
$('chars').textContent = '0';
$('hits').textContent = '0';
$('hash').textContent = '—';
setStatus('ล้างข้อมูลแล้ว', 'ok');
});
})();
</script>
</body>
</html>