chore: v2.8.15 — Oh My Pi login sharing, omp --allow-home, Markdown Preview default, first-login password
- omp-share.js: an admin's switch (S3) runs omp's own auth broker + gateway as the host on loopback; a member's omp pane reaches it as a scoped client keyed by its pane token (clients file = live omp panes only), runs on --model agenthub/<model>, never holds a credential. - omp catalog: --allow-home, so a workspace at the account's home keeps its sessions there (they were recorded under a temp dir and dropped). - Settings → Appearance → Open Markdown as: Preview (default) or Raw, for Files/Changes, the config viewer and a chat's file panel. - First-login password change and password rules, avatar URLs, Artifacts "Mine" includes installed shared skills/plugins, a member's own hook pages.
This commit is contained in:
+31
-4
@@ -18,14 +18,18 @@
|
||||
* `/account` (server mode) is the signed-in account itself for Settings →
|
||||
* Account: GET its profile, workspace/session counts and logins; PATCH its
|
||||
* display name and email; `POST /password` changes its own password (the old
|
||||
* one required, throttled like a step-up; every OTHER login ends);
|
||||
* one required, throttled like a step-up; every OTHER login ends; the new one
|
||||
* must pass every rule of `auth.passwordProblems` and differ from the old —
|
||||
* EWEAKPASSWORD with the failed `rules` — and it clears the "pick your own
|
||||
* password" flag an admin's create/reset sets);
|
||||
* `POST /sign-out-others` ends every login but this one. These writes take the
|
||||
* account from the login COOKIE only — a pane token (an agent acting as its
|
||||
* owner) may not change the owner's login. Each change is audited.
|
||||
* `/avatar` (server mode) is the account's own picture (server/lib/avatars.js):
|
||||
* GET serves it (`nosniff`, `sandbox` CSP), PUT takes the raw image bytes
|
||||
* (PNG/JPEG/GIF/WebP, at most 1 MB) and DELETE removes it — both writes are
|
||||
* account writes like the profile's. The sidebar shows it beside the name.
|
||||
* (PNG/JPEG/GIF/WebP, at most 1 MB), `POST /avatar/url` downloads the same
|
||||
* from an https link (public addresses only, server/lib/avatar-url.js) and
|
||||
* DELETE removes it — all writes are account writes like the profile's. The sidebar shows it beside the name.
|
||||
*
|
||||
* S3 (one Linux user per account): an account's dark/light choice also becomes
|
||||
* the theme in their own Claude Code settings, written as them.
|
||||
@@ -63,6 +67,7 @@ const PREF_KEYS = [
|
||||
"agenthub.tour",
|
||||
"agenthub.chatUi",
|
||||
"agenthub.workspace.allTabs",
|
||||
"agenthub.markdown.view",
|
||||
];
|
||||
const MAX_VALUE = 8 * 1024;
|
||||
|
||||
@@ -170,7 +175,11 @@ const ACCOUNT_STATUS = {
|
||||
EBADFIELD: 400,
|
||||
EBADEMAIL: 400,
|
||||
EBADPASSWORD: 400,
|
||||
EWEAKPASSWORD: 400,
|
||||
EBADIMAGE: 400,
|
||||
EBADURL: 400,
|
||||
EPRIVATEURL: 400,
|
||||
EFETCH: 502,
|
||||
ETOOBIG: 413,
|
||||
EREAUTH: 403,
|
||||
ETOOMANY: 429,
|
||||
@@ -206,7 +215,10 @@ function accountWrite(handler) {
|
||||
} catch (err) {
|
||||
const status = ACCOUNT_STATUS[err.code];
|
||||
if (!status) return res.status(500).json({ error: { message: err.message } });
|
||||
res.status(status).json({ error: { code: err.code, message: err.message } });
|
||||
// EWEAKPASSWORD names the rules the password failed.
|
||||
res.status(status).json({
|
||||
error: { code: err.code, message: err.message, ...(err.rules && { rules: err.rules }) },
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -233,6 +245,10 @@ router.post(
|
||||
sameOriginGuard,
|
||||
accountWrite(async (req, user, body) => {
|
||||
await auth.confirmPassword(user, body.currentPassword);
|
||||
// The account's own choice: every rule, and not the one it has now. This
|
||||
// also clears a "pick your own password" flag an admin's reset left.
|
||||
auth.validateOwnPassword(body.newPassword, user.username);
|
||||
await auth.assertNotCurrent(user.id, body.newPassword);
|
||||
await auth.setPassword(user.username, body.newPassword, { keepToken: auth.cookieToken(req) });
|
||||
return { out: { ok: true }, action: "own password changed" };
|
||||
})
|
||||
@@ -273,6 +289,17 @@ router.put(
|
||||
})
|
||||
);
|
||||
|
||||
// The same picture from a link: the server downloads it (server/lib/avatar-url.js).
|
||||
router.post(
|
||||
"/avatar/url",
|
||||
sameOriginGuard,
|
||||
accountWrite(async (_req, user, body) => {
|
||||
const buf = await require("../lib/avatar-url").fetchAvatarImage(body.url);
|
||||
avatars.setAvatar(user.id, buf);
|
||||
return { out: accountView(user.id), action: "own avatar set from a link" };
|
||||
})
|
||||
);
|
||||
|
||||
router.delete(
|
||||
"/avatar",
|
||||
sameOriginGuard,
|
||||
|
||||
Reference in New Issue
Block a user