feat(git identity): one section per git host; CodeCommit SSH key ID makes a plain ssh:// clone work
AWS CodeCommit logs an SSH key in by its IAM SSH key ID (APKA…), so a plain `git clone ssh://git-codecommit.<region>.amazonaws.com/v1/repos/x` was refused as the Linux account name. The account can now save an SSH user per host — PUT/DELETE /api/me/git/ssh-user, listed as `sshUsers` — written as `url."ssh://<user>@<host>/".insteadOf "ssh://<host>/"` in its own ~/.gitconfig (as the member under S3), so the plain URL works in a pane, in Clone and in the git bar. Only rules of exactly that shape are listed or removed; any other insteadOf is the user's and left alone. Settings → Git → Your git identity now shows the SSH keys one section per kind of host, each with only its own numbered steps: GitHub · GitLab · Gitea · Bitbucket (ED25519) and AWS CodeCommit (RSA: copy → upload in IAM → paste the key ID and pick the region, then a "Ready" clone line), plus a collapsed "Other SSH hosts (advanced)". The shared key-type picker is gone: each section has its own Generate/Replace/Delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
* 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`), and the commit author (`user.name` /
|
||||
* 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` /
|
||||
* `user.email` of the account's global git config — a member's commits fail
|
||||
* without one). The account is the signed-in user's
|
||||
* own Linux account under S3, else the host's, which only an admin (or local
|
||||
@@ -29,6 +30,7 @@ const STATUS = {
|
||||
ESTOREUNREADABLE: 409,
|
||||
EBADKEYTYPE: 400,
|
||||
EFOREIGNSSH: 409,
|
||||
EBADSSHUSER: 400,
|
||||
};
|
||||
|
||||
function fail(res, e) {
|
||||
@@ -47,6 +49,7 @@ async function view(account) {
|
||||
ssh: keys[0] ? { ...keys[0], terminal } : null,
|
||||
sshKeys: keys,
|
||||
sshTerminal: terminal ?? null,
|
||||
sshUsers: await identity.listSshUsers(account),
|
||||
https: identity.listHttps(account),
|
||||
author: await identity.getAuthor(account),
|
||||
};
|
||||
@@ -115,6 +118,32 @@ 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.
|
||||
*/
|
||||
router.put("/ssh-user", sameOriginGuard, async (req, res) => {
|
||||
try {
|
||||
const account = accountOf(req, { write: true });
|
||||
await identity.setSshUser(account, req.body || {});
|
||||
res.json(await view(account));
|
||||
} catch (e) {
|
||||
fail(res, e);
|
||||
}
|
||||
});
|
||||
|
||||
router.delete("/ssh-user/:host", sameOriginGuard, async (req, res) => {
|
||||
try {
|
||||
const account = accountOf(req, { write: true });
|
||||
if (!(await identity.removeSshUser(account, req.params.host))) {
|
||||
return res.status(404).json({ error: { code: "ENOTFOUND", message: "no such SSH user" } });
|
||||
}
|
||||
res.json(await view(account));
|
||||
} catch (e) {
|
||||
fail(res, e);
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/https", sameOriginGuard, async (req, res) => {
|
||||
try {
|
||||
const account = accountOf(req, { write: true });
|
||||
|
||||
Reference in New Issue
Block a user