mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-03 08:55:10 +02:00
add fingerprint view to both scenarios
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
admin_model "gitea.dev/models/admin"
|
||||
"gitea.dev/models/db"
|
||||
"gitea.dev/models/organization"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/git"
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
"gitea.dev/modules/lfs"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/setting"
|
||||
ssh_module "gitea.dev/modules/ssh"
|
||||
"gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/templates"
|
||||
"gitea.dev/modules/util"
|
||||
@@ -67,10 +69,43 @@ func Migrate(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
ctx.Data["ContextUser"] = ctxUser
|
||||
setManagedSSHKeyFingerprints(ctx, ctxUser)
|
||||
|
||||
ctx.HTML(http.StatusOK, templates.TplName("repo/migrate/"+serviceType.Name()))
|
||||
}
|
||||
|
||||
// setManagedSSHKeyFingerprints pre-loads the SignedUser's and each candidate
|
||||
// org's managed SSH key fingerprint, so the migrate form can display the
|
||||
// fingerprint that will be used to authenticate an SSH clone. The keypair is
|
||||
// created lazily by GetOrCreateSSHKeypair, so this also doubles as a primer.
|
||||
func setManagedSSHKeyFingerprints(ctx *context.Context, ctxUser *user_model.User) {
|
||||
if ctx.Doer == nil {
|
||||
return
|
||||
}
|
||||
if kp, err := ssh_module.GetOrCreateSSHKeypair(ctx, ctx.Doer.ID); err == nil {
|
||||
ctx.Data["SignedUserSSHFingerprint"] = kp.Fingerprint
|
||||
}
|
||||
|
||||
fingerprints := map[int64]string{}
|
||||
if orgs, ok := ctx.Data["Orgs"].([]*organization.Organization); ok {
|
||||
for _, org := range orgs {
|
||||
if kp, err := ssh_module.GetOrCreateSSHKeypair(ctx, org.ID); err == nil {
|
||||
fingerprints[org.ID] = kp.Fingerprint
|
||||
}
|
||||
}
|
||||
}
|
||||
if ctxUser != nil && ctxUser.ID != ctx.Doer.ID {
|
||||
if _, seen := fingerprints[ctxUser.ID]; !seen {
|
||||
if kp, err := ssh_module.GetOrCreateSSHKeypair(ctx, ctxUser.ID); err == nil {
|
||||
fingerprints[ctxUser.ID] = kp.Fingerprint
|
||||
}
|
||||
}
|
||||
}
|
||||
if data, err := json.Marshal(fingerprints); err == nil {
|
||||
ctx.Data["OwnerSSHFingerprintsJSON"] = string(data)
|
||||
}
|
||||
}
|
||||
|
||||
func handleMigrateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl templates.TplName, form *forms.MigrateRepoForm) {
|
||||
if setting.Repository.DisableMigrations {
|
||||
ctx.HTTPError(http.StatusForbidden, "MigrateError: the site administrator has disabled migrations")
|
||||
@@ -169,6 +204,7 @@ func MigratePost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
ctx.Data["ContextUser"] = ctxUser
|
||||
setManagedSSHKeyFingerprints(ctx, ctxUser)
|
||||
|
||||
tpl := templates.TplName("repo/migrate/" + form.Service.Name())
|
||||
|
||||
|
||||
@@ -5,15 +5,35 @@
|
||||
<a href="{{AppSubUrl}}/user/settings/keys" target="_blank">{{ctx.Locale.Tr "repo.migrate.ssh_helper_link"}}</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="inline field ssh-key-owner-selector tw-hidden" data-signed-user-id="{{.SignedUser.ID}}">
|
||||
<div class="inline field ssh-key-fingerprint-only tw-hidden">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_label"}}</label>
|
||||
<div class="inline-right">
|
||||
<span>{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_personal" .SignedUser.Name}}</span>
|
||||
<code class="tw-text-12">{{.SignedUserSSHFingerprint}}</code>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field ssh-key-owner-selector tw-hidden"
|
||||
data-signed-user-id="{{.SignedUser.ID}}"
|
||||
data-signed-user-fingerprint="{{.SignedUserSSHFingerprint}}"
|
||||
data-owner-fingerprints="{{.OwnerSSHFingerprintsJSON}}">
|
||||
<label>{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_label"}}</label>
|
||||
<div class="ui selection dropdown">
|
||||
<input id="ssh_key_owner_id" name="ssh_key_owner_id" type="hidden" value="0">
|
||||
<div class="default text">{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_org_default"}}</div>
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="menu">
|
||||
<div class="item" data-value="0">{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_org_default"}}</div>
|
||||
<div class="item" data-value="{{.SignedUser.ID}}">{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_personal" .SignedUser.Name}}</div>
|
||||
<div class="item" data-value="0" data-text="{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_org_default"}}">
|
||||
<div class="tw-flex tw-flex-col tw-gap-1">
|
||||
<span>{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_org_default"}}</span>
|
||||
<code class="item-fingerprint tw-text-12"></code>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item" data-value="{{.SignedUser.ID}}" data-text="{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_personal" .SignedUser.Name}}">
|
||||
<div class="tw-flex tw-flex-col tw-gap-1">
|
||||
<span>{{ctx.Locale.Tr "repo.migrate.ssh_key_owner_personal" .SignedUser.Name}}</span>
|
||||
<code class="item-fingerprint tw-text-12">{{.SignedUserSSHFingerprint}}</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1967,3 +1967,7 @@ tbody.commit-list {
|
||||
.branch-selector-dropdown .scrolling.menu .loading-indicator {
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
.ssh-key-owner-selector .item-fingerprint:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -99,35 +99,47 @@ export function initRepoMigrationForm() {
|
||||
initSSHKeyOwnerSelector(cloneAddrInput);
|
||||
}
|
||||
|
||||
// initSSHKeyOwnerSelector wires the "managed SSH key owner" selector. It is
|
||||
// hidden by default and only shown when an SSH URL is entered AND the chosen
|
||||
// target owner is an organisation (i.e. not the signed-in user) — in that case
|
||||
// the user can pick between the org's managed key (default) and their personal
|
||||
// managed key. The hidden #ssh_key_owner_id field is submitted with the form.
|
||||
// initSSHKeyOwnerSelector wires the managed SSH key UI on the migrate form.
|
||||
// For SSH URLs it shows either a single fingerprint line (personal target —
|
||||
// no choice) or a dropdown with "this org's key" vs "your personal key", and
|
||||
// updates the org default item with the current org's fingerprint so the user
|
||||
// always sees which key will be used. For non-SSH URLs everything stays hidden.
|
||||
function initSSHKeyOwnerSelector(cloneAddrInput: HTMLInputElement) {
|
||||
const container = document.querySelector<HTMLElement>('.ssh-key-owner-selector');
|
||||
const selector = document.querySelector<HTMLElement>('.ssh-key-owner-selector');
|
||||
const fingerprintOnly = document.querySelector<HTMLElement>('.ssh-key-fingerprint-only');
|
||||
const hiddenId = document.querySelector<HTMLInputElement>('#ssh_key_owner_id');
|
||||
const uidInput = document.querySelector<HTMLInputElement>('#uid');
|
||||
if (!container || !hiddenId || !uidInput) return;
|
||||
if (!selector || !hiddenId || !uidInput) return;
|
||||
|
||||
const signedUserID = container.getAttribute('data-signed-user-id') ?? '';
|
||||
const signedUserID = selector.getAttribute('data-signed-user-id') ?? '';
|
||||
const ownerFingerprints: Record<string, string> = JSON.parse(selector.getAttribute('data-owner-fingerprints') || '{}');
|
||||
const orgDefaultFingerprintEl = selector.querySelector<HTMLElement>('.menu .item[data-value="0"] .item-fingerprint');
|
||||
|
||||
function update() {
|
||||
const isSSH = isSSHURL(cloneAddrInput.value.trim());
|
||||
const targetUid = uidInput!.value;
|
||||
|
||||
// No choice: non-SSH URL, or migrating into the user's own account
|
||||
if (!isSSH || targetUid === signedUserID) {
|
||||
hideElem(container!);
|
||||
if (!isSSH) {
|
||||
hideElem(selector!);
|
||||
if (fingerprintOnly) hideElem(fingerprintOnly);
|
||||
hiddenId!.value = '0';
|
||||
return;
|
||||
}
|
||||
|
||||
// Target is an organisation — show selector (Fomantic dropdown wires the hidden input itself)
|
||||
showElem(container!);
|
||||
// Personal target — no choice to make, just surface the fingerprint.
|
||||
if (targetUid === signedUserID) {
|
||||
hideElem(selector!);
|
||||
if (fingerprintOnly) showElem(fingerprintOnly);
|
||||
hiddenId!.value = '0';
|
||||
return;
|
||||
}
|
||||
|
||||
// Org target — show dropdown; populate the org-default item's fingerprint.
|
||||
if (fingerprintOnly) hideElem(fingerprintOnly);
|
||||
if (orgDefaultFingerprintEl) orgDefaultFingerprintEl.textContent = ownerFingerprints[targetUid] ?? '';
|
||||
showElem(selector!);
|
||||
}
|
||||
|
||||
// Semantic UI updates the #uid hidden input via menu item clicks
|
||||
for (const item of document.querySelectorAll<HTMLElement>('.owner.dropdown .menu .item')) {
|
||||
item.addEventListener('click', () => setTimeout(update, 0));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user