Added @cspnonce to all inline <script> and <style> tags in layout, explorer, and register views. Enabled nonce generation in headers config. unsafe-inline kept as fallback. Nonces will activate after container restart when the Headers Boot registers the Blade directive. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
139 lines
6.8 KiB
PHP
139 lines
6.8 KiB
PHP
@extends('lethean::layout')
|
|
|
|
@section('title', 'Register a .lthn name')
|
|
@section('meta_description', 'Check availability and register your .lthn blockchain domain name. Free registration, DNS included, pay with BTC.')
|
|
|
|
@section('content')
|
|
<div class="section" style="max-width: 600px; margin: 0 auto;">
|
|
<div style="text-align: center; margin-bottom: 2rem;">
|
|
<h2>Register a .lthn Name</h2>
|
|
<p style="color: var(--muted);">Claim your identity on the Lethean blockchain. Free registration.</p>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div style="display: flex; gap: 0.5rem;">
|
|
<input type="text" id="name-input" placeholder="Enter a name..." autofocus
|
|
style="flex: 1; padding: 0.75rem 1rem; background: var(--bg); border: 1px solid var(--border); border-radius: 0.5rem; color: var(--text); font-size: 1rem;">
|
|
<span style="padding: 0.75rem 0; color: var(--muted); font-size: 1rem;">.lthn</span>
|
|
<button id="check-btn" class="api-link" style="margin-top: 0; padding: 0.75rem 1.5rem;">Check</button>
|
|
</div>
|
|
<div id="result" style="margin-top: 1rem; min-height: 60px;"></div>
|
|
</div>
|
|
|
|
<div class="card-grid" style="margin-top: 2rem;">
|
|
<div class="card">
|
|
<h3>What you get</h3>
|
|
<ul style="color: var(--muted); line-height: 2; list-style: none; padding: 0; font-size: 0.85rem;">
|
|
<li>Blockchain-native identity</li>
|
|
<li>DNS management portal</li>
|
|
<li>VPN/proxy routing</li>
|
|
<li>Free .lthn SSL cert</li>
|
|
</ul>
|
|
</div>
|
|
<div class="card">
|
|
<h3>Requirements</h3>
|
|
<ul style="color: var(--muted); line-height: 2; list-style: none; padding: 0; font-size: 0.85rem;">
|
|
<li>6+ characters (a-z, 0-9, dash, dot)</li>
|
|
<li>Not already registered</li>
|
|
<li>Not reserved during sunrise</li>
|
|
<li>BTC for payment (free for now)</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script @cspnonce>
|
|
(function() {
|
|
var input = document.getElementById('name-input');
|
|
var btn = document.getElementById('check-btn');
|
|
var result = document.getElementById('result');
|
|
|
|
function el(tag, style, text) {
|
|
var e = document.createElement(tag);
|
|
if (style) Object.assign(e.style, style);
|
|
if (text) e.textContent = text;
|
|
return e;
|
|
}
|
|
|
|
function check() {
|
|
var name = input.value.trim().toLowerCase().replace(/\.lthn$/, '').replace(/[^a-z0-9.\-]/g, '');
|
|
if (!name || name.length < 6) {
|
|
result.textContent = '';
|
|
result.appendChild(el('p', {color: '#fbbf24', fontSize: '0.9rem'}, 'Name must be at least 6 characters.'));
|
|
return;
|
|
}
|
|
input.value = name;
|
|
result.textContent = '';
|
|
result.appendChild(el('p', {color: '#9ca3af', fontSize: '0.9rem'}, 'Checking...'));
|
|
btn.disabled = true;
|
|
|
|
fetch((window.LTHN_API || '') + '/v1/names/available/' + encodeURIComponent(name), {headers: {'Accept': 'application/json'}})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
btn.disabled = false;
|
|
result.textContent = '';
|
|
|
|
if (data.available && !data.reserved) {
|
|
var wrap = el('div', {});
|
|
wrap.appendChild(el('p', {color: '#34d399', fontWeight: '600', fontSize: '1.1rem', marginBottom: '0.75rem'}, name + '.lthn is available!'));
|
|
|
|
var emailInput = el('input', {
|
|
padding: '0.5rem 1rem', background: '#0a0e17', border: '1px solid #1f2937',
|
|
borderRadius: '0.5rem', color: '#e5e7eb', fontSize: '0.9rem', width: '100%', marginBottom: '0.5rem'
|
|
});
|
|
emailInput.type = 'email';
|
|
emailInput.placeholder = 'Your email address';
|
|
emailInput.id = 'claim-email';
|
|
wrap.appendChild(emailInput);
|
|
|
|
var claimBtn = el('button', {
|
|
padding: '0.75rem 2rem', background: '#34d399', color: '#fff',
|
|
borderRadius: '0.5rem', border: 'none', fontWeight: '600', fontSize: '1rem', cursor: 'pointer', width: '100%'
|
|
}, 'Claim ' + name + '.lthn');
|
|
claimBtn.addEventListener('click', function() {
|
|
var email = document.getElementById('claim-email').value;
|
|
if (!email) { return; }
|
|
claimBtn.disabled = true;
|
|
claimBtn.textContent = 'Submitting...';
|
|
fetch((window.LTHN_API || '') + '/v1/names/claim', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
|
|
body: JSON.stringify({name: name, email: email})
|
|
}).then(function(r) { return r.json(); }).then(function(d) {
|
|
result.textContent = '';
|
|
if (d.claim_id) {
|
|
result.appendChild(el('p', {color: '#34d399', fontWeight: '600', fontSize: '1rem'}, 'Claim submitted!'));
|
|
result.appendChild(el('p', {color: '#9ca3af', fontSize: '0.85rem'}, 'Claim ID: ' + d.claim_id + '. We will email ' + email + ' when approved.'));
|
|
} else {
|
|
result.appendChild(el('p', {color: '#fbbf24', fontSize: '0.9rem'}, d.error || 'Something went wrong.'));
|
|
}
|
|
});
|
|
});
|
|
wrap.appendChild(claimBtn);
|
|
result.appendChild(wrap);
|
|
} else if (data.reserved) {
|
|
var p = el('p', {color: '#fbbf24', fontSize: '0.9rem'}, name + '.lthn is reserved during the sunrise period. ');
|
|
var a = el('a', {color: '#818cf8'}, 'Learn more');
|
|
a.href = '/sunrise';
|
|
p.appendChild(a);
|
|
result.appendChild(p);
|
|
} else {
|
|
var p2 = el('p', {color: '#fbbf24', fontSize: '0.9rem'}, name + '.lthn is already taken. ');
|
|
var a2 = el('a', {color: '#818cf8'}, 'View details');
|
|
a2.href = '/names/' + name;
|
|
p2.appendChild(a2);
|
|
result.appendChild(p2);
|
|
}
|
|
})
|
|
.catch(function() {
|
|
btn.disabled = false;
|
|
result.textContent = '';
|
|
result.appendChild(el('p', {color: '#fbbf24', fontSize: '0.9rem'}, 'Could not check. Try again.'));
|
|
});
|
|
}
|
|
|
|
btn.addEventListener('click', check);
|
|
input.addEventListener('keypress', function(e) { if (e.key === 'Enter') check(); });
|
|
})();
|
|
</script>
|
|
@endsection
|