mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-14 06:47:28 +00:00
fix(pwa): unbreak sign-out, and stop echoing $PUBLIC_ORIGIN in the CLI hint (#108)
Two bugs on the dashboard, both fixed by handing appBar/CLI_HINT the request. Sign-out was broken for everyone. csrfGuard rejects any POST whose _csrf does not match the mc_csrf cookie, and /auth/logout is a POST that is not on the exempt list, but the sign-out form carried no hidden field -- every click answered 403 "bad csrf token". appBar now takes the request rather than the user, because it needs the token as well as the identity. The field is written out instead of reusing csrfInput(): html.mjs is the view layer and imports nothing, and pulling in session.mjs would drag the database driver with it. The "Connect the CLI" snippet still printed $PUBLIC_ORIGIN, so users on app.logicsrc.com were told to point LOGICSRC_API at the generated Railway hostname. #105 added requestOrigin() for exactly this and fixed the device-flow URLs; the dashboard hint was missed. It now follows the request too, which is not a hardcode swap -- the same deployment answering on its Railway hostname still self-describes correctly. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3649f78fb6
commit
898d5503b8
4 changed files with 56 additions and 8 deletions
|
|
@ -36,7 +36,7 @@ cliRouter.get("/cli/authorize", requireAuth, (req, res) => {
|
|||
return res.status(400).type("html").send(page({ body: `<main class="wrap" style="padding-top:12vh"><h1>Bad CLI request</h1><p class="dim mono">missing/invalid redirect_uri, state, or code_challenge.</p></main>` }));
|
||||
}
|
||||
const name = String(req.query.name || "logicsrc cli").slice(0, 40);
|
||||
const body = `${appBar(req.user)}
|
||||
const body = `${appBar(req)}
|
||||
<main class="wrap" style="max-width:460px;padding-top:8vh">
|
||||
<div class="card"><div class="card-body" style="text-align:center">
|
||||
<div style="font-size:2rem">🔑</div>
|
||||
|
|
@ -142,7 +142,7 @@ cliRouter.post("/cli/device/code", async (req, res) => {
|
|||
});
|
||||
|
||||
const devicePage = (req, body) =>
|
||||
page({ title: "LogicSRC ▸ authorize CLI", body: `${appBar(req.user)}<main class="wrap" style="max-width:460px;padding-top:8vh">${body}</main>${footer}` });
|
||||
page({ title: "LogicSRC ▸ authorize CLI", body: `${appBar(req)}<main class="wrap" style="max-width:460px;padding-top:8vh">${body}</main>${footer}` });
|
||||
|
||||
const deviceResult = (req, res, status, heading, detail) =>
|
||||
res.status(status).type("html").send(devicePage(req, `<div class="card"><div class="card-body" style="text-align:center">
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { id, token, sha256 } from "../lib/crypto.mjs";
|
|||
import { page, footer, appBar, esc } from "../lib/html.mjs";
|
||||
import { requireAuth, csrfInput } from "../lib/session.mjs";
|
||||
import { createApiKey, listApiKeys, revokeApiKey } from "../lib/apikey.mjs";
|
||||
import { requestOrigin } from "../lib/origin.mjs";
|
||||
import { config } from "../config.mjs";
|
||||
|
||||
export const pagesRouter = Router();
|
||||
|
|
@ -60,10 +61,10 @@ export async function dashboardHandler(req, res) {
|
|||
for (const t of teams) cards += await teamCard(t, uid);
|
||||
cards = cards.split(CSRF).join(csrfInput(req));
|
||||
|
||||
const body = `${appBar(req.user)}
|
||||
const body = `${appBar(req)}
|
||||
<main class="wrap" style="max-width:820px;padding:26px 0 40px">
|
||||
<div class="section-title"><h1 style="font-size:1.6rem">Your teams</h1><span class="count">${teams.length}</span></div>
|
||||
${CLI_HINT(config.origin)}
|
||||
${CLI_HINT(requestOrigin(req, config.origin))}
|
||||
${cards || `<div class="card"><div class="card-body dim">You're not on any teams yet. Create one below or accept an invite.</div></div>`}
|
||||
<div class="card" style="margin-top:22px"><div class="card-head"><span class="h">New team</span></div>
|
||||
<div class="card-body"><form method="post" action="/teams" style="display:flex;gap:8px">${csrfInput(req)}
|
||||
|
|
@ -109,7 +110,7 @@ pagesRouter.get("/teams/accept", requireAuth, (req, res) => {
|
|||
const tok = String(req.query.token || "");
|
||||
const shared = req.query.shared;
|
||||
const err = req.query.err;
|
||||
const body = `${appBar(req.user)}
|
||||
const body = `${appBar(req)}
|
||||
<main class="wrap" style="max-width:460px;padding-top:8vh">
|
||||
<div class="card"><div class="card-body" style="text-align:center">
|
||||
<h1 style="font-size:1.4rem;margin-bottom:12px">Accept team invite</h1>
|
||||
|
|
@ -143,7 +144,7 @@ pagesRouter.get("/settings", requireAuth, async (req, res) => {
|
|||
<span style="flex:1">${esc(k.name)} <span class="faint">${esc(k.prefix)}…</span></span>
|
||||
<form method="post" action="/settings/apikeys/${k.id}/delete" style="margin:0">${csrfInput(req)}<button class="btn danger" style="padding:5px 10px;font-size:.72rem">revoke</button></form>
|
||||
</div>`).join("") : `<div class="faint mono" style="font-size:.78rem;padding:6px 0">no keys yet</div>`;
|
||||
const body = `${appBar(req.user)}
|
||||
const body = `${appBar(req)}
|
||||
<main class="wrap" style="max-width:640px;padding-top:30px">
|
||||
<h1 style="font-size:1.5rem;margin-bottom:20px">Settings</h1>
|
||||
${newKey ? `<div class="notice ok">New API key (copy it now — shown once):<br><b class="mono" style="word-break:break-all">${esc(newKey)}</b></div>` : ""}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue