From f1bc7b6eb5cb9beab55e4edac87cc5e0b7ceb069 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Mon, 12 Nov 2018 10:52:48 +0000 Subject: SSH public-key authentication for push mirroring --- .../mirrors/_authentication_method.html.haml | 36 ++++++++++++++++++++++ app/views/projects/mirrors/_mirror_repos.html.haml | 2 ++ .../projects/mirrors/_mirror_repos_form.html.haml | 15 +-------- .../projects/mirrors/_mirror_repos_push.html.haml | 8 +++++ ...generate_public_ssh_key_confirm_modal.html.haml | 13 ++++++++ app/views/projects/mirrors/_show.html.haml | 1 - .../projects/mirrors/_ssh_host_keys.html.haml | 33 ++++++++++++++++++++ .../projects/settings/repository/show.html.haml | 2 +- 8 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 app/views/projects/mirrors/_authentication_method.html.haml create mode 100644 app/views/projects/mirrors/_mirror_repos_push.html.haml create mode 100644 app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml delete mode 100644 app/views/projects/mirrors/_show.html.haml create mode 100644 app/views/projects/mirrors/_ssh_host_keys.html.haml (limited to 'app/views') diff --git a/app/views/projects/mirrors/_authentication_method.html.haml b/app/views/projects/mirrors/_authentication_method.html.haml new file mode 100644 index 00000000000..8dc042d87d1 --- /dev/null +++ b/app/views/projects/mirrors/_authentication_method.html.haml @@ -0,0 +1,36 @@ +- mirror = f.object +- is_push = local_assigns.fetch(:is_push, false) +- auth_options = [[_('Password'), 'password'], [_('SSH public key'), 'ssh_public_key']] +- regen_data = { auth_method: 'ssh_public_key', regenerate_ssh_private_key: true } +- ssh_public_key_present = mirror.ssh_public_key.present? + +.form-group + = f.label :auth_method, _('Authentication method'), class: 'label-bold' + = f.select :auth_method, + options_for_select(auth_options, mirror.auth_method), + {}, { class: "form-control js-mirror-auth-type" } + +.form-group + .collapse.js-well-changing-auth + .changing-auth-method= icon('spinner spin lg') + .well-password-auth.collapse.js-well-password-auth + = f.label :password, _("Password"), class: "label-bold" + = f.password_field :password, value: mirror.password, class: 'form-control' + - unless is_push + .well-ssh-auth.collapse.js-well-ssh-auth + %p.js-ssh-public-key-present{ class: ('collapse' unless ssh_public_key_present) } + = _('Here is the public SSH key that needs to be added to the remote server. For more information, please refer to the documentation.') + %p.js-ssh-public-key-pending{ class: ('collapse' if ssh_public_key_present) } + = _('An SSH key will be automatically generated when the form is submitted. For more information, please refer to the documentation.') + + .clearfix.js-ssh-public-key-wrap{ class: ('collapse' unless ssh_public_key_present) } + %code.prepend-top-10.ssh-public-key + = mirror.ssh_public_key + = clipboard_button(text: mirror.ssh_public_key, title: _("Copy SSH public key to clipboard"), class: 'prepend-top-10 btn-copy-ssh-public-key') + + = button_tag type: 'button', + data: { endpoint: project_mirror_path(@project), project_data: { import_data_attributes: regen_data } }, + class: "btn btn-inverted btn-warning prepend-top-10 js-btn-regenerate-ssh-key#{ ' collapse' unless ssh_public_key_present }" do + = icon('spinner spin', class: 'js-spinner d-none') + = _('Regenerate key') + = render 'projects/mirrors/regenerate_public_ssh_key_confirm_modal' diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml index d523df1cd90..2f9bd5b04b6 100644 --- a/app/views/projects/mirrors/_mirror_repos.html.haml +++ b/app/views/projects/mirrors/_mirror_repos.html.haml @@ -59,5 +59,7 @@ .badge.mirror-error-badge{ data: { toggle: 'tooltip', html: 'true' }, title: html_escape(mirror.last_error.try(:strip)) }= _('Error') %td.mirror-action-buttons .btn-group.mirror-actions-group.pull-right{ role: 'group' } + - if mirror.ssh_key_auth? + = clipboard_button(text: mirror.ssh_public_key, class: 'btn btn-default', title: _('Copy SSH public key')) = render 'shared/remote_mirror_update_button', remote_mirror: mirror %button.js-delete-mirror.btn.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= icon('trash-o') diff --git a/app/views/projects/mirrors/_mirror_repos_form.html.haml b/app/views/projects/mirrors/_mirror_repos_form.html.haml index 93994cb30ac..a2cce83bfab 100644 --- a/app/views/projects/mirrors/_mirror_repos_form.html.haml +++ b/app/views/projects/mirrors/_mirror_repos_form.html.haml @@ -1,18 +1,5 @@ -- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') - .form-group = label_tag :mirror_direction, _('Mirror direction'), class: 'label-light' = select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control js-mirror-direction', disabled: true -= f.fields_for :remote_mirrors, @project.remote_mirrors.build do |rm_f| - = rm_f.hidden_field :enabled, value: '1' - = rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+" - = rm_f.hidden_field :only_protected_branches, class: 'js-mirror-protected-hidden' - -.form-group - = label_tag :auth_method, _('Authentication method'), class: 'label-bold' - = select_tag :auth_method, options_for_select([[_('None'), 'none'], [_('Password'), 'password']], 'none'), { class: "form-control js-auth-method" } - -.form-group.js-password-group.collapse - = label_tag :password, _('Password'), class: 'label-bold' - = text_field_tag :password, '', class: 'form-control js-password' += render partial: "projects/mirrors/mirror_repos_push", locals: { f: f } diff --git a/app/views/projects/mirrors/_mirror_repos_push.html.haml b/app/views/projects/mirrors/_mirror_repos_push.html.haml new file mode 100644 index 00000000000..1d9c83653fe --- /dev/null +++ b/app/views/projects/mirrors/_mirror_repos_push.html.haml @@ -0,0 +1,8 @@ +- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|') + += f.fields_for :remote_mirrors, @project.remote_mirrors.build do |rm_f| + = rm_f.hidden_field :enabled, value: '1' + = rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+" + = rm_f.hidden_field :only_protected_branches, class: 'js-mirror-protected-hidden' + = render partial: 'projects/mirrors/ssh_host_keys', locals: { f: rm_f } + = render partial: 'projects/mirrors/authentication_method', locals: { f: rm_f, is_push: true } diff --git a/app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml b/app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml new file mode 100644 index 00000000000..327552c9b2c --- /dev/null +++ b/app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml @@ -0,0 +1,13 @@ +.modal.js-regenerate-public-ssh-key-confirm-modal{ tabindex: -1 } + .modal-dialog + .modal-content + .modal-header + %h3.modal-title.page-title + Regenerate public SSH key? + %button.close.js-cancel{ type: 'button', 'data-dismiss': 'modal', 'aria-label' => _('Close') } + %span{ 'aria-hidden': true } × + .modal-body + %p= _('Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again.') + .form-actions.modal-footer + = button_tag _('Cancel'), type: 'button', class: 'btn js-cancel' + = button_tag _('Regenerate key'), type: 'button', class: 'btn btn-inverted btn-warning js-confirm' diff --git a/app/views/projects/mirrors/_show.html.haml b/app/views/projects/mirrors/_show.html.haml deleted file mode 100644 index 8318d5898a1..00000000000 --- a/app/views/projects/mirrors/_show.html.haml +++ /dev/null @@ -1 +0,0 @@ -= render 'projects/mirrors/mirror_repos' diff --git a/app/views/projects/mirrors/_ssh_host_keys.html.haml b/app/views/projects/mirrors/_ssh_host_keys.html.haml new file mode 100644 index 00000000000..f61aa6ecd11 --- /dev/null +++ b/app/views/projects/mirrors/_ssh_host_keys.html.haml @@ -0,0 +1,33 @@ +- mirror = f.object +- verified_by = mirror.ssh_known_hosts_verified_by +- verified_at = mirror.ssh_known_hosts_verified_at + +.form-group.js-ssh-host-keys-section{ class: ('collapse' unless mirror.ssh_mirror_url?) } + %button.btn.btn-inverted.btn-success.inline.js-detect-host-keys.append-right-10{ type: 'button' } + = icon('spinner spin', class: 'js-spinner d-none') + = _('Detect host keys') + .fingerprint-ssh-info.js-fingerprint-ssh-info.prepend-top-10.append-bottom-10{ class: ('collapse' unless mirror.ssh_mirror_url?) } + %label.label-bold + = _('Fingerprints') + .fingerprints-list.js-fingerprints-list + - mirror.ssh_known_hosts_fingerprints.each do |fp| + %code= fp.fingerprint + - if verified_at + .form-text.text-muted.js-fingerprint-verification + %i.fa.fa-check.fingerprint-verified + Verified by + - if verified_by + = link_to verified_by.name, user_path(verified_by) + - else + = _('a deleted user') + #{time_ago_in_words(verified_at)} ago + + .js-ssh-hosts-advanced.inline + %button.btn.btn-default.btn-show-advanced.show-advanced{ type: 'button' } + %span.label-show + = _('Input host keys manually') + %span.label-hide + = _('Hide host keys manual input') + .js-ssh-known-hosts.collapse.prepend-top-default + = f.label :ssh_known_hosts, _('SSH host keys'), class: 'label-bold' + = f.text_area :ssh_known_hosts, class: 'form-control known-hosts js-known-hosts', rows: '10' diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml index a0bcaaf3c54..c14e95a382c 100644 --- a/app/views/projects/settings/repository/show.html.haml +++ b/app/views/projects/settings/repository/show.html.haml @@ -3,7 +3,7 @@ - @content_class = "limit-container-width" unless fluid_layout = render "projects/default_branch/show" -= render "projects/mirrors/show" += render "projects/mirrors/mirror_repos" -# Protected branches & tags use a lot of nested partials. -# The shared parts of the views can be found in the `shared` directory. -- cgit v1.2.3