openvibers/openvibe.network Commits
Registration (WS-B task 10): /register and /signup open the create-account view; the form is username, optional email and password — the claim code for a reserved name appears only when the chosen name is reserved (it was an always-visible 'Verification Key' field); the username hint is plain words
Changes
@@@ -305,15 +305,16 @@ body{min-height:100dvh;background:var(--bg);color:var(--text);font-family:'Inter<div class="field"><label>Username</label><input type="text" name="username" placeholder="Choose a username" required minlength="3" maxlength="24" pattern="^[a-zA-Z0-9_]+$" title="Use letters, numbers, and underscores only" autocomplete="username">-- <small class="panel-note">Allowed: letters, numbers, and underscores only; 3–24 characters; cannot start with "anon".</small>++ <small class="panel-note">Letters, numbers and underscores, 3 to 24 characters. You can pick a display name later.</small></div><div class="field"><label>Email <span style="color:var(--text-dim)">(optional)</span></label><input type="email" name="email" placeholder="[email protected]" autocomplete="email"></div>-- <div class="field">-- <label>Verification Key <span style="color:var(--text-dim)">(optional)</span></label>-- <input type="text" name="verification_key" placeholder="OPENVIBE-XXXX-XXXX-XXXX" style="font-family:monospace">++ <div class="field" id="claim-field" hidden>++ <label for="claim-code">Claim code</label>++ <input type="text" id="claim-code" name="verification_key" placeholder="OPENVIBE-XXXX-XXXX-XXXX" style="font-family:monospace" autocomplete="off">++ <small class="panel-note">This name is reserved for someone. If it is yours, enter the code you were given to claim it; otherwise choose another name.</small></div><div class="field"><label>Password</label>@@@ -893,6 +894,12 @@ async function handleRegister(e) {}),});const data = await res.json();++ // A reserved name: show the claim-code field only now (most people never need it).++ if (!res.ok && data.reserved) {++ const claim = document.getElementById('claim-field');++ if (claim) { claim.hidden = false; document.getElementById('claim-code').focus(); }++ throw new Error('This username is reserved. Enter its claim code, or choose another name.');++ }if (!res.ok) throw new Error(data.error || 'Registration failed');localStorage.setItem('ov_token', data.token);@@@ -734,6 +734,12 @@ if (!fs.existsSync(avatarDir)) fs.mkdirSync(avatarDir, { recursive: true });app.use('/data/avatars', express.static(avatarDir, { maxAge: '7d' }));// Serve clean auth + recovery routes++// People type /register and /signup: the sign-in page's create-account view (WS-B task 10), query kept.++app.get(['/register', '/signup', '/sign-up'], (req, res) => {++ const q = new URLSearchParams(req.query);++ q.set('tab', 'register');++ res.redirect(302, `/login?${q}`);++});app.get(['/login', '/forgot-password', '/reset-password'], (req, res) => {res.sendFile(path.join(__dirname, '..', 'public', 'login.html'));});
@@ -305,15 +305,16 @@ body{min-height:100dvh;background:var(--bg);color:var(--text);font-family:'Inter
@@ -305,15 +305,16 @@ body{min-height:100dvh;background:var(--bg);color:var(--text);font-family:'Inter
<div class="field">
<div class="field">
<label>Username</label>
<label>Username</label>
<input type="text" name="username" placeholder="Choose a username" required minlength="3" maxlength="24" pattern="^[a-zA-Z0-9_]+$" title="Use letters, numbers, and underscores only" autocomplete="username">
<input type="text" name="username" placeholder="Choose a username" required minlength="3" maxlength="24" pattern="^[a-zA-Z0-9_]+$" title="Use letters, numbers, and underscores only" autocomplete="username">
- <small class="panel-note">Allowed: letters, numbers, and underscores only; 3–24 characters; cannot start with "anon".</small>
+ <small class="panel-note">Letters, numbers and underscores, 3 to 24 characters. You can pick a display name later.</small>
</div>
</div>
<div class="field">
<div class="field">
<label>Email <span style="color:var(--text-dim)">(optional)</span></label>
<label>Email <span style="color:var(--text-dim)">(optional)</span></label>
<input type="email" name="email" placeholder="[email protected]" autocomplete="email">
<input type="email" name="email" placeholder="[email protected]" autocomplete="email">
</div>
</div>
- <div class="field">
- <label>Verification Key <span style="color:var(--text-dim)">(optional)</span></label>
- <input type="text" name="verification_key" placeholder="OPENVIBE-XXXX-XXXX-XXXX" style="font-family:monospace">
+ <div class="field" id="claim-field" hidden>
+ <label for="claim-code">Claim code</label>
+ <input type="text" id="claim-code" name="verification_key" placeholder="OPENVIBE-XXXX-XXXX-XXXX" style="font-family:monospace" autocomplete="off">
+ <small class="panel-note">This name is reserved for someone. If it is yours, enter the code you were given to claim it; otherwise choose another name.</small>
</div>
</div>
<div class="field">
<div class="field">
<label>Password</label>
<label>Password</label>
@@ -893,6 +894,12 @@ async function handleRegister(e) {
@@ -893,6 +894,12 @@ async function handleRegister(e) {
}),
}),
});
});
const data = await res.json();
const data = await res.json();
+ // A reserved name: show the claim-code field only now (most people never need it).
+ if (!res.ok && data.reserved) {
+ const claim = document.getElementById('claim-field');
+ if (claim) { claim.hidden = false; document.getElementById('claim-code').focus(); }
+ throw new Error('This username is reserved. Enter its claim code, or choose another name.');
+ }
if (!res.ok) throw new Error(data.error || 'Registration failed');
if (!res.ok) throw new Error(data.error || 'Registration failed');
localStorage.setItem('ov_token', data.token);
localStorage.setItem('ov_token', data.token);
@@ -734,6 +734,12 @@ if (!fs.existsSync(avatarDir)) fs.mkdirSync(avatarDir, { recursive: true });
@@ -734,6 +734,12 @@ if (!fs.existsSync(avatarDir)) fs.mkdirSync(avatarDir, { recursive: true });
app.use('/data/avatars', express.static(avatarDir, { maxAge: '7d' }));
app.use('/data/avatars', express.static(avatarDir, { maxAge: '7d' }));
// Serve clean auth + recovery routes
// Serve clean auth + recovery routes
+// People type /register and /signup: the sign-in page's create-account view (WS-B task 10), query kept.
+app.get(['/register', '/signup', '/sign-up'], (req, res) => {
+ const q = new URLSearchParams(req.query);
+ q.set('tab', 'register');
+ res.redirect(302, `/login?${q}`);
+});
app.get(['/login', '/forgot-password', '/reset-password'], (req, res) => {
app.get(['/login', '/forgot-password', '/reset-password'], (req, res) => {
res.sendFile(path.join(__dirname, '..', 'public', 'login.html'));
res.sendFile(path.join(__dirname, '..', 'public', 'login.html'));
});
});