Initial commit: private Texas Hold'em ring game site (lobby + table stub)
- 6-digit access key gate with long-lived HttpOnly cookie, brute-force limits - Lobby with saved player name and live table list - Table creation (name, starting stack, blinds, blind timer) - Table play screen stub (seats, button/SB/BB, phase, blinds, timer) - Security hardening: strict CSP, origin checks, host pinning, input sanitizing Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
b2c91062f1
22 files changed
+3450
No files matched your search
@@ -0,0 +1,82 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const form = document.getElementById('form');
|
||||
const box = document.getElementById('digits');
|
||||
const inputs = [...box.querySelectorAll('input')];
|
||||
const errorEl = document.getElementById('error');
|
||||
const submitBtn = document.getElementById('submit');
|
||||
let busy = false;
|
||||
|
||||
const value = () => inputs.map((i) => i.value).join('');
|
||||
|
||||
function fill(digits, from) {
|
||||
let i = from;
|
||||
for (const d of digits) {
|
||||
if (i >= inputs.length) break;
|
||||
inputs[i++].value = d;
|
||||
}
|
||||
inputs[Math.min(i, inputs.length - 1)].focus();
|
||||
if (value().length === 6) submit();
|
||||
}
|
||||
|
||||
inputs.forEach((input, idx) => {
|
||||
input.addEventListener('input', () => {
|
||||
const digits = input.value.replace(/\D/g, '');
|
||||
input.value = '';
|
||||
if (digits) fill(digits, idx);
|
||||
errorEl.textContent = '';
|
||||
});
|
||||
input.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Backspace' && !input.value && idx > 0) {
|
||||
inputs[idx - 1].value = '';
|
||||
inputs[idx - 1].focus();
|
||||
e.preventDefault();
|
||||
} else if (e.key === 'ArrowLeft' && idx > 0) {
|
||||
inputs[idx - 1].focus();
|
||||
} else if (e.key === 'ArrowRight' && idx < inputs.length - 1) {
|
||||
inputs[idx + 1].focus();
|
||||
}
|
||||
});
|
||||
input.addEventListener('paste', (e) => {
|
||||
const digits = (e.clipboardData.getData('text') || '').replace(/\D/g, '');
|
||||
if (!digits) return;
|
||||
e.preventDefault();
|
||||
fill(digits, idx);
|
||||
});
|
||||
input.addEventListener('focus', () => input.select());
|
||||
});
|
||||
|
||||
async function submit() {
|
||||
if (busy) return;
|
||||
const key = value();
|
||||
if (key.length !== 6) {
|
||||
errorEl.textContent = '6桁すべて入力してください。';
|
||||
return;
|
||||
}
|
||||
busy = true;
|
||||
submitBtn.disabled = true;
|
||||
try {
|
||||
await App.api('POST', '/api/auth', { key });
|
||||
const next = new URLSearchParams(location.search).get('next');
|
||||
location.replace(App.safeNext(next));
|
||||
} catch (err) {
|
||||
errorEl.textContent = err.message;
|
||||
box.classList.remove('shake');
|
||||
void box.offsetWidth;
|
||||
box.classList.add('shake');
|
||||
inputs.forEach((i) => { i.value = ''; });
|
||||
inputs[0].focus();
|
||||
} finally {
|
||||
busy = false;
|
||||
submitBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
form.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
submit();
|
||||
});
|
||||
|
||||
inputs[0].focus();
|
||||
})();
|
||||
Reference in new issue
Block a user