SSO: gate uses shared app.promptpcb.ai accounts
This commit is contained in:
parent
d20596989c
commit
4c390d45c7
1 changed files with 20 additions and 19 deletions
|
|
@ -1,18 +1,17 @@
|
||||||
// auth.js — gates the whole site behind a PromptPCB account (Corben tenant auth for this site).
|
// auth.js — gates the whole site behind your PromptPCB account (SHARED with app.promptpcb.ai via its
|
||||||
// Nothing loads until you're signed in; the catalog + file URLs come only from the authed function.
|
// SSO bridge). Nothing loads until you're signed in; the catalog + file URLs come only from the authed
|
||||||
|
// Corben function, which itself verifies your PromptPCB session.
|
||||||
(function () {
|
(function () {
|
||||||
var API = 'https://api.corben.world';
|
var CORBEN = 'https://api.corben.world'; // Corben functions (catalog/autofill/submit)
|
||||||
var SITE = '6ab5ec79-8b91-453d-aacc-5be76f9271d1'; // this site IS the tenant
|
var AUTH = 'https://app.promptpcb.ai'; // shared PromptPCB accounts live here
|
||||||
var FN_CATALOG = '0f3cd09e-81ce-43f4-88e7-cde3d91f122e';
|
var FN_CATALOG = '0f3cd09e-81ce-43f4-88e7-cde3d91f122e';
|
||||||
var TK_CATALOG = '687d2466cea418815433b60946d6742a';
|
var TK_CATALOG = '687d2466cea418815433b60946d6742a';
|
||||||
var LS = 'ppcb_token';
|
var LS = 'ppcb_token';
|
||||||
window.PPCB = { token: null, user: null };
|
window.PPCB = { token: null, user: null };
|
||||||
|
|
||||||
window.ppcbReady = function (fn) {
|
window.ppcbReady = function (fn) { if (window.PPCB.token) fn(); else addEventListener('ppcb:auth', function () { fn(); }, { once: true }); };
|
||||||
if (window.PPCB.token) fn(); else addEventListener('ppcb:auth', function () { fn(); }, { once: true });
|
|
||||||
};
|
|
||||||
window.getCatalog = async function () {
|
window.getCatalog = async function () {
|
||||||
var r = await fetch(API + '/functions/' + FN_CATALOG + '/invoke?token=' + TK_CATALOG, {
|
var r = await fetch(CORBEN + '/functions/' + FN_CATALOG + '/invoke?token=' + TK_CATALOG, {
|
||||||
method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + window.PPCB.token }, body: '{}' });
|
method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + window.PPCB.token }, body: '{}' });
|
||||||
if (r.status === 401) { logout(); throw new Error('session expired'); }
|
if (r.status === 401) { logout(); throw new Error('session expired'); }
|
||||||
var d = await r.json(); return d.parts || [];
|
var d = await r.json(); return d.parts || [];
|
||||||
|
|
@ -23,7 +22,7 @@
|
||||||
window.PPCB.user = user; document.documentElement.classList.add('ppcb-authed');
|
window.PPCB.user = user; document.documentElement.classList.add('ppcb-authed');
|
||||||
var g = document.getElementById('ppcb-gate'); if (g) g.style.display = 'none';
|
var g = document.getElementById('ppcb-gate'); if (g) g.style.display = 'none';
|
||||||
var c = document.querySelector('.credits');
|
var c = document.querySelector('.credits');
|
||||||
if (c) c.innerHTML = '<span title="' + user.email + '" style="cursor:default">◆ ' + (user.display_name || user.email.split('@')[0]) + '</span> · <a href="#" id="ppcb-logout" style="color:var(--dim)">sign out</a>';
|
if (c) c.innerHTML = '<span title="' + user.email + '" style="cursor:default">◆ ' + (user.name || user.email.split('@')[0]) + '</span> · <a href="#" id="ppcb-logout" style="color:var(--dim)">sign out</a>';
|
||||||
var lo = document.getElementById('ppcb-logout'); if (lo) lo.onclick = function (e) { e.preventDefault(); logout(); };
|
var lo = document.getElementById('ppcb-logout'); if (lo) lo.onclick = function (e) { e.preventDefault(); logout(); };
|
||||||
dispatchEvent(new Event('ppcb:auth'));
|
dispatchEvent(new Event('ppcb:auth'));
|
||||||
}
|
}
|
||||||
|
|
@ -34,9 +33,10 @@
|
||||||
var t = localStorage.getItem(LS);
|
var t = localStorage.getItem(LS);
|
||||||
if (!t) return gate();
|
if (!t) return gate();
|
||||||
try {
|
try {
|
||||||
var r = await fetch(API + '/auth/tenant/me', { headers: { Authorization: 'Bearer ' + t } });
|
var r = await fetch(AUTH + '/api/auth/sso/verify', { headers: { Authorization: 'Bearer ' + t } });
|
||||||
if (!r.ok) return gate();
|
if (!r.ok) return gate();
|
||||||
var u = await r.json(); window.PPCB.token = t; authed(u);
|
var u = await r.json(); if (!u.valid) return gate();
|
||||||
|
window.PPCB.token = t; authed({ email: u.email, name: u.name });
|
||||||
} catch (e) { gate(); }
|
} catch (e) { gate(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,13 +48,14 @@
|
||||||
'<div class="gate-card">' +
|
'<div class="gate-card">' +
|
||||||
'<div class="gate-brand"><span class="mk"></span> PromptPCB <small>/ parts</small></div>' +
|
'<div class="gate-brand"><span class="mk"></span> PromptPCB <small>/ parts</small></div>' +
|
||||||
'<div class="gate-h">Sign in to the part library</div>' +
|
'<div class="gate-h">Sign in to the part library</div>' +
|
||||||
'<div class="gate-sub">One PromptPCB account. Every part—real specs, 3D, SPICE—once you’re in.</div>' +
|
'<div class="gate-sub">Your PromptPCB account — the same one you use at app.promptpcb.ai. Real specs, 3D, SPICE for every part, once you’re in.</div>' +
|
||||||
'<div class="gate-tabs"><button data-m="login" class="on">Sign in</button><button data-m="signup">Create account</button></div>' +
|
'<div class="gate-tabs"><button data-m="login" class="on">Sign in</button><button data-m="signup">Create account</button></div>' +
|
||||||
'<input id="g-name" placeholder="Display name" style="display:none">' +
|
'<input id="g-name" placeholder="Your name" style="display:none">' +
|
||||||
'<input id="g-email" type="email" placeholder="you@example.com" autocomplete="email">' +
|
'<input id="g-email" type="email" placeholder="you@example.com" autocomplete="email">' +
|
||||||
'<input id="g-pass" type="password" placeholder="Password (8+ characters)" autocomplete="current-password">' +
|
'<input id="g-pass" type="password" placeholder="Password (8+ characters)" autocomplete="current-password">' +
|
||||||
'<button class="btn gate-go" id="g-go">Sign in</button>' +
|
'<button class="btn gate-go" id="g-go">Sign in</button>' +
|
||||||
'<div class="gate-msg" id="g-msg"></div>' +
|
'<div class="gate-msg" id="g-msg"></div>' +
|
||||||
|
'<div style="margin-top:18px;font-family:var(--mono);font-size:12px;color:var(--dim2)">One account across all of PromptPCB · <a href="https://app.promptpcb.ai" style="color:var(--dim)">app.promptpcb.ai ↗</a></div>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
document.body.appendChild(el);
|
document.body.appendChild(el);
|
||||||
var mode = 'login';
|
var mode = 'login';
|
||||||
|
|
@ -71,14 +72,14 @@
|
||||||
async function go() {
|
async function go() {
|
||||||
var email = document.getElementById('g-email').value.trim(), pass = document.getElementById('g-pass').value;
|
var email = document.getElementById('g-email').value.trim(), pass = document.getElementById('g-pass').value;
|
||||||
var msg = document.getElementById('g-msg'); msg.style.color = 'var(--dim)'; msg.innerHTML = '<span class="spin"></span> …';
|
var msg = document.getElementById('g-msg'); msg.style.color = 'var(--dim)'; msg.innerHTML = '<span class="spin"></span> …';
|
||||||
var path = mode === 'signup' ? '/auth/tenant/register' : '/auth/tenant/login';
|
var path = mode === 'signup' ? '/api/auth/signup' : '/api/auth/login';
|
||||||
var body = { tenant_id: SITE, email: email, password: pass };
|
var body = { email: email, password: pass };
|
||||||
if (mode === 'signup') body.display_name = document.getElementById('g-name').value.trim();
|
if (mode === 'signup') body.name = document.getElementById('g-name').value.trim();
|
||||||
try {
|
try {
|
||||||
var r = await fetch(API + path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
|
var r = await fetch(AUTH + path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
|
||||||
var d = await r.json();
|
var d = await r.json();
|
||||||
if (!r.ok) { msg.style.color = 'var(--bad,#ff6b6b)'; msg.textContent = d.error || 'failed'; return; }
|
if (!r.ok || !d.token) { msg.style.color = '#ff6b6b'; msg.textContent = d.error || 'failed'; return; }
|
||||||
localStorage.setItem(LS, d.token); window.PPCB.token = d.token; authed(d.user);
|
localStorage.setItem(LS, d.token); window.PPCB.token = d.token; authed({ email: d.user.email, name: d.user.name });
|
||||||
} catch (e) { msg.style.color = '#ff6b6b'; msg.textContent = 'network error'; }
|
} catch (e) { msg.style.color = '#ff6b6b'; msg.textContent = 'network error'; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue