This commit is contained in:
bcjang
2026-03-12 14:17:39 +09:00
parent bc0a546d6f
commit 413cdf8cc2
10 changed files with 385 additions and 54 deletions

View File

@@ -375,6 +375,18 @@
margin-top: 10px;
}
/* Keypair display */
.keypair-section { margin-bottom: 16px; }
.keypair-section:last-child { margin-bottom: 0; }
.keypair-section-label {
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-muted);
margin-bottom: 6px;
}
/* Icon SVG */
svg { display: inline-block; vertical-align: middle; }
</style>
@@ -389,7 +401,7 @@
</svg>
Key Generator
</h1>
<p>JWT Secret · API Key · Operation Key · UUID · Random Hex</p>
<p>JWT Secret · RS256 · ES256 · API Key · Operation Key · UUID · Random Hex</p>
</header>
<div class="card">
@@ -463,6 +475,35 @@
</div>
</div>
<!-- Keypair result -->
<div id="resultKeypair" style="display:none">
<div class="keypair-section">
<div class="keypair-section-label">Private Key</div>
<div class="key-display" id="privateKeyDisplay" style="white-space:pre;font-size:0.75rem;"></div>
<div class="copy-row">
<button class="copy-btn" id="copyPrivateBtn" onclick="copyPrivateKey()">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>
Copy Private Key
</button>
</div>
</div>
<div class="keypair-section">
<div class="keypair-section-label">Public Key</div>
<div class="key-display" id="publicKeyDisplay" style="white-space:pre;font-size:0.75rem;"></div>
<div class="copy-row">
<button class="copy-btn" id="copyPublicBtn" onclick="copyPublicKey()">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>
Copy Public Key
</button>
</div>
</div>
<div class="key-meta" id="keyMetaKeypair"></div>
</div>
<!-- Bulk result -->
<div id="resultBulk" style="display:none">
<div class="bulk-list" id="bulkList"></div>
@@ -483,6 +524,8 @@
let selectedType = 'jwt_hs256';
let bulkMode = false;
let lastBulkKeys = [];
let lastBulkData = [];
let lastKeypair = null;
function selectType(type, el) {
selectedType = type;
@@ -541,69 +584,111 @@
}
}
const COPY_ICON = `<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>`;
const CHECK_ICON = `<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
function renderSingle(data) {
document.getElementById('resultArea').style.display = 'block';
document.getElementById('resultSingle').style.display = 'block';
document.getElementById('resultBulk').style.display = 'none';
document.getElementById('keyDisplay').textContent = data.key;
if (data.keypair) {
lastKeypair = data;
document.getElementById('resultSingle').style.display = 'none';
document.getElementById('resultKeypair').style.display = 'block';
const meta = document.getElementById('keyMeta');
meta.innerHTML = `
<span class="meta-tag highlight">${data.label}</span>
<span class="meta-tag">${data.bits} bit</span>
<span class="meta-tag">${data.algorithm}</span>
<span class="meta-tag">${data.length} chars</span>
`;
document.getElementById('privateKeyDisplay').textContent = data.key;
document.getElementById('publicKeyDisplay').textContent = data.public_key;
const copyBtn = document.getElementById('copyBtn');
copyBtn.classList.remove('copied');
copyBtn.innerHTML = `
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg> Copy`;
const meta = document.getElementById('keyMetaKeypair');
meta.innerHTML = `
<span class="meta-tag highlight">${data.label}</span>
<span class="meta-tag">${data.bits} bit</span>
<span class="meta-tag">${data.algorithm}</span>
`;
document.getElementById('copyPrivateBtn').classList.remove('copied');
document.getElementById('copyPublicBtn').classList.remove('copied');
document.getElementById('copyPrivateBtn').innerHTML = `${COPY_ICON} Copy Private Key`;
document.getElementById('copyPublicBtn').innerHTML = `${COPY_ICON} Copy Public Key`;
} else {
lastKeypair = null;
document.getElementById('resultSingle').style.display = 'block';
document.getElementById('resultKeypair').style.display = 'none';
document.getElementById('keyDisplay').textContent = data.key;
const meta = document.getElementById('keyMeta');
meta.innerHTML = `
<span class="meta-tag highlight">${data.label}</span>
<span class="meta-tag">${data.bits} bit</span>
<span class="meta-tag">${data.algorithm}</span>
<span class="meta-tag">${data.length} chars</span>
`;
const copyBtn = document.getElementById('copyBtn');
copyBtn.classList.remove('copied');
copyBtn.innerHTML = `${COPY_ICON} Copy`;
}
}
function renderBulk(items) {
lastBulkData = items;
lastBulkKeys = items.map(i => i.key);
document.getElementById('resultArea').style.display = 'block';
document.getElementById('resultSingle').style.display = 'none';
document.getElementById('resultKeypair').style.display = 'none';
document.getElementById('resultBulk').style.display = 'block';
const list = document.getElementById('bulkList');
list.innerHTML = items.map((item, idx) => `
<div class="bulk-item">
<span class="bulk-index">#${idx + 1}</span>
<span class="bulk-key">${item.key}</span>
<button class="bulk-copy" onclick="copyBulkItem(this, '${escHtml(item.key)}')">Copy</button>
</div>
`).join('');
list.innerHTML = items.map((item, idx) => {
const displayKey = item.keypair
? item.key.split('\n').slice(0, 2).join('\n') + '\n...'
: item.key;
return `
<div class="bulk-item">
<span class="bulk-index">#${idx + 1}</span>
<span class="bulk-key" style="${item.keypair ? 'white-space:pre;font-size:0.72rem;' : ''}">${escHtmlDisplay(displayKey)}</span>
<button class="bulk-copy" data-index="${idx}" onclick="copyBulkItem(this)">Copy</button>
</div>`;
}).join('');
}
function escHtml(s) {
return s.replace(/'/g, "\\'");
function escHtmlDisplay(s) {
return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
function flashCopied(btn, resetLabel) {
btn.classList.add('copied');
btn.innerHTML = `${CHECK_ICON} Copied!`;
setTimeout(() => {
btn.classList.remove('copied');
btn.innerHTML = `${COPY_ICON} ${resetLabel}`;
}, 2000);
}
function copyKey() {
const key = document.getElementById('keyDisplay').textContent;
navigator.clipboard.writeText(key).then(() => {
const btn = document.getElementById('copyBtn');
btn.classList.add('copied');
btn.innerHTML = `
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="20 6 9 17 4 12"/>
</svg> Copied!`;
setTimeout(() => {
btn.classList.remove('copied');
btn.innerHTML = `
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg> Copy`;
}, 2000);
flashCopied(document.getElementById('copyBtn'), 'Copy');
});
}
function copyBulkItem(btn, key) {
function copyPrivateKey() {
if (!lastKeypair) return;
navigator.clipboard.writeText(lastKeypair.key).then(() => {
flashCopied(document.getElementById('copyPrivateBtn'), 'Copy Private Key');
});
}
function copyPublicKey() {
if (!lastKeypair) return;
navigator.clipboard.writeText(lastKeypair.public_key).then(() => {
flashCopied(document.getElementById('copyPublicBtn'), 'Copy Public Key');
});
}
function copyBulkItem(btn) {
const idx = parseInt(btn.dataset.index);
const key = lastBulkData[idx].key;
navigator.clipboard.writeText(key).then(() => {
btn.classList.add('copied');
btn.textContent = 'Copied!';