Stripped from the internal repo: per-box deploy trees, Go services (nodelist/astmeta/proxy/svxdr), deploy/sync scripts and all secrets. Config templates for nginx, PHP-FPM, Redis and tmpfiles live in install/ with CHANGEME placeholders. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
54 lines
2.7 KiB
JavaScript
54 lines
2.7 KiB
JavaScript
// auth_ui.js — shared sign-in / register / sign-out transport (dmr-web, svx-web).
|
|
// Canonical copy: callmgr2/www-mumien/lib/auth_ui.js; other repos carry a COPY.
|
|
// Needs lib/api.js. Pages keep their own field validation and messages; this
|
|
// owns the request/response contract so both webs behave the same.
|
|
//
|
|
// authLogin({ endpoint, body, csrf, onFail(j, r) }) → true on {ok:true}
|
|
// authRegister({ endpoint, csrf, msg(text, isErr) }) reads the reg* form fields
|
|
// authLogout({ endpoint, method, after })
|
|
(function () {
|
|
'use strict';
|
|
const REG_IDS = ['regCallsign', 'regFirstname', 'regLastname', 'regEmail', 'regPass1', 'regPass2', 'regCity', 'regState', 'regCountry'];
|
|
|
|
async function authLogin(o) {
|
|
const r = await apiFetch(o.endpoint, { body: o.body, csrf: o.csrf || window._csrfToken || '' });
|
|
if (!r.ok || !r.json || !r.json.ok) {
|
|
if (typeof o.onFail === 'function') o.onFail(r.json, r);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async function authRegister(o) {
|
|
const g = id => document.getElementById(id);
|
|
const v = id => (g(id) ? g(id).value : '').trim();
|
|
const msg = typeof o.msg === 'function' ? o.msg : function () {};
|
|
msg(null);
|
|
const callsign = v('regCallsign').toUpperCase(), firstname = v('regFirstname'), lastname = v('regLastname'),
|
|
email = v('regEmail'), pass1 = g('regPass1') ? g('regPass1').value : '', pass2 = g('regPass2') ? g('regPass2').value : '',
|
|
city = v('regCity'), state = v('regState'), country = v('regCountry');
|
|
if (!callsign || !firstname || !email || !pass1) { msg('Fill in all required fields.', true); return false; }
|
|
if (pass1 !== pass2) { msg('Passwords do not match.', true); return false; }
|
|
if (pass1.length < 6) { msg('Password must be at least 6 characters.', true); return false; }
|
|
const j = await apiJson(o.endpoint, { callsign, firstname, lastname, email, password: pass1, password2: pass2, city, state, country },
|
|
{ csrf: o.csrf || window._csrfToken || '' });
|
|
if (j && j.ok) {
|
|
const emailNote = j.email_sent ? ' A verification email has been sent.' : '';
|
|
msg('Account created!' + emailNote + ' An administrator will activate your account after email verification.', false);
|
|
REG_IDS.forEach(id => { if (g(id)) g(id).value = ''; });
|
|
return true;
|
|
}
|
|
msg((j && j.error) || 'Registration failed.', true);
|
|
return false;
|
|
}
|
|
|
|
async function authLogout(o) {
|
|
try { await apiFetch(o.endpoint, { method: o.method || 'GET' }); } catch (_) {}
|
|
if (typeof o.after === 'function') o.after();
|
|
}
|
|
|
|
window.authLogin = authLogin;
|
|
window.authRegister = authRegister;
|
|
window.authLogout = authLogout;
|
|
})();
|