feat: right-click menus in Files/Users/Artifacts; several SSH keys and accounts per host
- Files: right-click a sidebar workspace (Open, Copy path) or home (Open, Open Trash), a path crumb (Open, Download as zip, Paste into, Copy path), a Trash row (Restore, Copy path, Delete forever), the Trash area (Refresh, Empty Trash) and an admin's per-user Trash folder (Open, Empty Trash). - Users: row menu (Edit + Open home in Files for an admin, Copy username/email). - Artifacts: card menu repeating its buttons, plus Copy link for a page. - Git identity: named SSH keys beside the default ones (id_<type>_<name>, max 10, DELETE ?id=); SSH logins per alias (`ssh://<alias>/` → `ssh://<user>@<host>/`, so several AWS CodeCommit accounts share a host), each optionally tied to one key (`agenthub.<from>.sshKey`) — a clone of that URL offers only that key and persists it. Terminal sshCommand follows the keys. Settings → Git: "More SSH keys" + account name/key in the AWS and other-host forms. Docs/API.md, OpenAPI updated.
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
/**
|
||||
* @file HTTP surface for a user's OWN git identity (`server/lib/git-identity.js`),
|
||||
* mounted at `/api/me/git`: the SSH keys a clone uses — ed25519 and/or rsa (make, replace, delete —
|
||||
* only the PUBLIC key is ever returned) and the HTTPS logins (save, delete —
|
||||
* `hasToken` only, never a password), whether the account's own terminal
|
||||
* git uses that key (`core.sshCommand`), the SSH login name per host
|
||||
* (`url.<…>.insteadOf` — AWS CodeCommit's SSH key ID), and the commit author (`user.name` /
|
||||
* mounted at `/api/me/git`: the SSH keys a clone uses — a default ed25519
|
||||
* and/or rsa one plus named ones (`name`, deleted by `?id=`) for more
|
||||
* accounts (make, replace, delete — only the PUBLIC key is ever returned) and
|
||||
* the HTTPS logins (save, delete — `hasToken` only, never a password),
|
||||
* whether the account's own terminal git uses the keys (`core.sshCommand`),
|
||||
* the SSH logins per host or alias (`url.<…>.insteadOf` — AWS CodeCommit's
|
||||
* SSH key ID — each optionally tied to one key), and the commit author (`user.name` /
|
||||
* `user.email` of the account's global git config — a member's commits fail
|
||||
* without one; a new SSH key is labelled with that email, else
|
||||
* `<username>@smartgift.vn`). The account is the signed-in user's
|
||||
@@ -33,6 +35,10 @@ const STATUS = {
|
||||
EBADKEYTYPE: 400,
|
||||
EFOREIGNSSH: 409,
|
||||
EBADSSHUSER: 400,
|
||||
EBADKEYNAME: 400,
|
||||
ETOOMANYKEYS: 409,
|
||||
EBADALIAS: 400,
|
||||
ENOKEY: 400,
|
||||
};
|
||||
|
||||
function fail(res, e) {
|
||||
@@ -87,9 +93,10 @@ router.post("/ssh-key", sameOriginGuard, async (req, res) => {
|
||||
await identity.generateSshKey(account, {
|
||||
replace: req.body?.replace === true,
|
||||
type: req.body?.type === "rsa" ? "rsa" : "ed25519",
|
||||
// A named key sits beside the default one of its type.
|
||||
name: typeof req.body?.name === "string" ? req.body.name : null,
|
||||
// The key is labelled with the commit author's email, else the default one.
|
||||
comment:
|
||||
(await identity.getAuthor(account)).email || identity.defaultEmail(usernameOf(req)),
|
||||
comment: (await identity.getAuthor(account)).email || identity.defaultEmail(usernameOf(req)),
|
||||
});
|
||||
res.status(201).json(await view(account, usernameOf(req)));
|
||||
} catch (e) {
|
||||
@@ -101,7 +108,8 @@ router.delete("/ssh-key", sameOriginGuard, async (req, res) => {
|
||||
try {
|
||||
const account = accountOf(req, { write: true });
|
||||
const type = req.query.type === undefined ? undefined : String(req.query.type);
|
||||
if (!(await identity.removeSshKey(account, type))) {
|
||||
const id = req.query.id === undefined ? undefined : String(req.query.id);
|
||||
if (!(await identity.removeSshKey(account, { type, id }))) {
|
||||
return res.status(404).json({ error: { code: "ENOTFOUND", message: "no SSH key" } });
|
||||
}
|
||||
res.json(await view(account, usernameOf(req)));
|
||||
@@ -128,8 +136,10 @@ router.put("/ssh-terminal", sameOriginGuard, async (req, res) => {
|
||||
});
|
||||
|
||||
/**
|
||||
* The SSH user name for one host (`{host, user}`) — e.g. AWS CodeCommit's SSH
|
||||
* key ID, so a plain `ssh://git-codecommit…/` URL logs in. DELETE drops it.
|
||||
* An SSH login (`{host, user, alias?, key?}`) — e.g. AWS CodeCommit's SSH key
|
||||
* ID, so a plain `ssh://git-codecommit…/` URL logs in; with `alias`, one more
|
||||
* account on that host (`ssh://<alias>/…`); with `key`, the only key it uses.
|
||||
* DELETE `/ssh-user/<host or alias>` drops it.
|
||||
*/
|
||||
router.put("/ssh-user", sameOriginGuard, async (req, res) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user