Watch
0
0
Fork
You've already forked hyperhive
0

swarm-ui: linking a matrix account starts on the password login and warns before a pasted token

The form's credential choice now starts on 'log in with a password', listed
first, with a note that the swarm's own login gives the account a device of
its own. Choosing 'paste a token' shows a warning: a token from Element or
another client belongs to a device that is already logged in, so the agent
cannot use its encryption keys and the account will not decrypt encrypted
rooms.
This commit is contained in:
iris 2026-11-06 20:11:37 +01:00 • committed by mara
commit f276ee342c
2 changed files with 21 additions and 4 deletions

View file

@ -870,8 +870,13 @@ it carries an **own account** badge. The card requests the list again when
a link dialog closes.
- **link a matrix account** — `PUT /api/hives/{hive}/agents/{agent}/matrix-accounts/{account}`,
either a pasted bearer token or a user id + password that
swarm-controller logs in with, storing the token it gets back.
either a user id + password that swarm-controller logs in with, storing the
token it gets back, or a pasted bearer token. The form starts on the password
login: the account gets a device of its own, and the form notes that an
operator who also logs in to it appears to the agent as a second device. Choosing
**paste a token** shows a warning: a token from Element or another client
belongs to a device that's already logged in, so the agent can't use that
device's encryption keys and the account won't decrypt encrypted rooms.
- **link a forge account** — `PUT /api/hives/{hive}/agents/{agent}/forge-accounts/{label}`
with a forge URL and an access token, stored at
`swarm/agents/<agent>/forge/<label>`. The agent's

View file

@ -31,6 +31,7 @@ import { TextField } from "../ui/text-field/TextField.js";
import { SelectField } from "../ui/select-field/SelectField.js";
import { Button } from "../ui/button/Button.js";
import { FormStack } from "../ui/form-stack/FormStack.js";
import { Hint } from "../ui/hint/Hint.js";
import { FormResult } from "../ui/submit/FormResult.js";
import { useSubmit } from "../ui/submit/useSubmit.js";
@ -53,10 +54,18 @@ interface Linked {
}
const MODE_OPTIONS = [
{ value: "token", label: "paste a token" },
{ value: "password", label: "log in with a password" },
{ value: "token", label: "paste a token" },
];
// What the operator should know before choosing. A login the swarm makes
// gives the account a device of its own; a token belongs to a device that
// is already logged in somewhere, whose encryption keys the agent cannot use.
const PASSWORD_NOTE =
"The swarm logs in for the agent, so the account gets a device of its own. Link an account only the agent uses: if you also log in to it, you appear to the agent as a second device.";
const TOKEN_WARNING =
"A pasted token belongs to a device that is already logged in somewhere. If it came from Element or another client, the agent can't use that device's encryption keys, and the account won't decrypt encrypted rooms. Use a token only if the agent is the first thing to use that device. Prefer a password login.";
export function LinkMatrixAccountForm({
hive,
agent,
@ -70,7 +79,7 @@ export function LinkMatrixAccountForm({
onClose?: () => void;
}) {
const [account, setAccount] = useState("");
const [mode, setMode] = useState<Mode>("token");
const [mode, setMode] = useState<Mode>("password");
const [token, setToken] = useState("");
const [userId, setUserId] = useState("");
const [password, setPassword] = useState("");
@ -172,6 +181,9 @@ export function LinkMatrixAccountForm({
setMode(v as Mode);
}}
/>
<Hint tone={mode === "token" ? "warn" : "muted"}>
{mode === "token" ? TOKEN_WARNING : PASSWORD_NOTE}
</Hint>
{mode === "token" ? (
<TextField
id="matrix-account-token"