From 02e6367d1762995e523e8d4565ec2f6e794efba7 Mon Sep 17 00:00:00 2001 From: Aeris Date: Thu, 27 Aug 2015 23:39:14 +0200 Subject: [PATCH] SSH support --- app/assets/javascripts/ssh.coffee.erb | 16 ++++++ app/assets/stylesheets/ssh.scss | 3 ++ app/controllers/check_controller.rb | 1 + app/controllers/https_controller.rb | 4 ++ app/controllers/smtp_controller.rb | 4 ++ app/controllers/ssh_controller.rb | 43 ++++++++++++++++ app/controllers/xmpp_controller.rb | 4 ++ app/helpers/site_helper.rb | 2 +- app/helpers/ssh_helper.rb | 28 +++++++++++ app/views/application/_headers.erb | 10 ++-- app/views/check/no_tls.html.erb | 5 +- app/views/check/processing.html.erb | 2 +- app/views/check/show.html.erb | 2 +- app/views/ssh/index.html.erb | 18 +++++++ app/views/ssh/no_ssh.html.erb | 12 +++++ app/views/ssh/processing.html.erb | 20 ++++++++ app/views/ssh/show.html.erb | 67 +++++++++++++++++++++++++ app/workers/ssh_worker.rb | 24 +++++++++ config/routes.rb | 10 ++++ test/controllers/ssh_controller_test.rb | 14 ++++++ 20 files changed, 281 insertions(+), 8 deletions(-) create mode 100644 app/assets/javascripts/ssh.coffee.erb create mode 100644 app/assets/stylesheets/ssh.scss create mode 100644 app/controllers/ssh_controller.rb create mode 100644 app/helpers/ssh_helper.rb create mode 100644 app/views/ssh/index.html.erb create mode 100644 app/views/ssh/no_ssh.html.erb create mode 100644 app/views/ssh/processing.html.erb create mode 100644 app/views/ssh/show.html.erb create mode 100644 app/workers/ssh_worker.rb create mode 100644 test/controllers/ssh_controller_test.rb diff --git a/app/assets/javascripts/ssh.coffee.erb b/app/assets/javascripts/ssh.coffee.erb new file mode 100644 index 0000000..d375461 --- /dev/null +++ b/app/assets/javascripts/ssh.coffee.erb @@ -0,0 +1,16 @@ +$ -> + ssh_submit = -> + host = $('#ssh_check_host').val() + port = $('#ssh_check_port').val() + port = 22 if port == '' + window.location.href = "<%= Rails.configuration.relative_url_root %>/ssh/#{host}:#{port}" + + $('#ssh_check_host').keypress (e) -> + ssh_submit() if e.which == 13 + return + $('#ssh_check_port').keypress (e) -> + ssh_submit() if e.which == 13 + return + $('#ssh_check_submit').click -> + ssh_submit() + return diff --git a/app/assets/stylesheets/ssh.scss b/app/assets/stylesheets/ssh.scss new file mode 100644 index 0000000..1a72257 --- /dev/null +++ b/app/assets/stylesheets/ssh.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the ssh controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/check_controller.rb b/app/controllers/check_controller.rb index 5f87953..e4549a3 100644 --- a/app/controllers/check_controller.rb +++ b/app/controllers/check_controller.rb @@ -1,5 +1,6 @@ class CheckController < ApplicationController before_action :check_host + helper_method :tls_type, :type def check_host @host = params[:id] diff --git a/app/controllers/https_controller.rb b/app/controllers/https_controller.rb index 032ef2c..899be82 100644 --- a/app/controllers/https_controller.rb +++ b/app/controllers/https_controller.rb @@ -7,4 +7,8 @@ class HttpsController < CheckController def worker HTTPSWorker end + + def tls_type + 'HTTPS' + end end diff --git a/app/controllers/smtp_controller.rb b/app/controllers/smtp_controller.rb index 63ccfaf..e36cafb 100644 --- a/app/controllers/smtp_controller.rb +++ b/app/controllers/smtp_controller.rb @@ -7,4 +7,8 @@ class SmtpController < CheckController def worker SMTPWorker end + + def tls_type + 'STARTTLS' + end end diff --git a/app/controllers/ssh_controller.rb b/app/controllers/ssh_controller.rb new file mode 100644 index 0000000..93b7a78 --- /dev/null +++ b/app/controllers/ssh_controller.rb @@ -0,0 +1,43 @@ +class SshController < ApplicationController + before_action :check_host, except: %i(index) + + def check_host + @host, @port = params[:id].split ':' + @idn = SimpleIDN.to_ascii @host + if /[^a-zA-Z0-9.-]/.match @idn + flash[:danger] = "Hôte #{@host} invalide" + redirect_to :index + return false + end + @host = "#{@idn}:#{@port}" + @result = Datastore.host :ssh, @host + end + + def index + end + + def show + enqueue_host unless @result + return render :processing if @result.pending + return render :no_ssh if @result.no_ssh + end + + def refresh + unless @result.pending + refresh_allowed = @result.date + Rails.configuration.refresh_delay + if Time.now < refresh_allowed + flash[:warning] = "Merci d’attendre au moins #{l refresh_allowed} pour rafraîchir" + return redirect_to result_path @host + end + enqueue_host + end + redirect_to action: :show + end + + protected + def enqueue_host + Datastore.pending :ssh, @host + SSHWorker.perform_async @idn, @port + @result = OpenStruct.new pending: true, date: Time.now + end +end diff --git a/app/controllers/xmpp_controller.rb b/app/controllers/xmpp_controller.rb index 4d4de8c..2fa08b1 100644 --- a/app/controllers/xmpp_controller.rb +++ b/app/controllers/xmpp_controller.rb @@ -7,4 +7,8 @@ class XmppController < CheckController def worker XMPPWorker end + + def tls_type + 'STARTTLS' + end end diff --git a/app/helpers/site_helper.rb b/app/helpers/site_helper.rb index 1ac54db..d0ceb79 100644 --- a/app/helpers/site_helper.rb +++ b/app/helpers/site_helper.rb @@ -96,7 +96,7 @@ module SiteHelper when Hashie::Mash { success: %i(pfs), warning: %i(des3 sha1), - danger: %i(md5 psk srp anonymous null export des rc2 rc4) + danger: %i(dss md5 psk srp anonymous null export des rc2 rc4) }.collect do |c, ts| ts.select { |t| CryptCheck::Tls::Cipher.send "#{t}?", cipher.name }.collect { |t| [c, t] } end diff --git a/app/helpers/ssh_helper.rb b/app/helpers/ssh_helper.rb new file mode 100644 index 0000000..ac78632 --- /dev/null +++ b/app/helpers/ssh_helper.rb @@ -0,0 +1,28 @@ +module SshHelper + COLORS = { green: :success, yellow: :warning, red: :danger, nil => :default } + + def kex_label(key) + label key, COLORS[CryptCheck::Ssh::Server::KEX[key]] + end + + def cipher_label(cipher) + label cipher, COLORS[CryptCheck::Ssh::Server::ENCRYPTION[cipher]] + end + + def hmac_label(hmac) + label hmac, COLORS[CryptCheck::Ssh::Server::HMAC[hmac]] + end + + def compression_label(compression) + label compression, COLORS[CryptCheck::Ssh::Server::COMPRESSION[compression]] + end + + def key_label(key) + label key, COLORS[CryptCheck::Ssh::Server::KEY[key]] + end + + private + def label(name, color) + "  #{name}".html_safe + end +end diff --git a/app/views/application/_headers.erb b/app/views/application/_headers.erb index 45442ba..de4661f 100644 --- a/app/views/application/_headers.erb +++ b/app/views/application/_headers.erb @@ -2,13 +2,15 @@ diff --git a/app/views/check/no_tls.html.erb b/app/views/check/no_tls.html.erb index 7f14446..dd4e33e 100644 --- a/app/views/check/no_tls.html.erb +++ b/app/views/check/no_tls.html.erb @@ -2,8 +2,11 @@

- <%= @host %> ne supporte pas HTTPS + [<%= self.type.to_s.upcase %>] <%= @host %> ne supporte pas <%= self.tls_type %>

+ <% if Time.now - @result.date >= Rails.configuration.refresh_delay %> + <%= link_to 'Rafraîchir', {action: :refresh}, class: %i(btn btn-default pull-right) %> + <% end %>
diff --git a/app/views/check/processing.html.erb b/app/views/check/processing.html.erb index 98806d5..3f52c63 100644 --- a/app/views/check/processing.html.erb +++ b/app/views/check/processing.html.erb @@ -6,7 +6,7 @@

- Analyse en cours de <%= @host %> + [<%= self.type.to_s.upcase %>] Analyse en cours de <%= @host %>

Début de l’analyse : <%= l @result.date %> diff --git a/app/views/check/show.html.erb b/app/views/check/show.html.erb index c9b1677..194e4be 100644 --- a/app/views/check/show.html.erb +++ b/app/views/check/show.html.erb @@ -2,7 +2,7 @@

- Résultats pour <%= @host %> (<%= l @result.date %>) + [<%= self.type.to_s.upcase %>] <%= @host %> (<%= l @result.date %>) <%= rank_label @result.score.rank %>

diff --git a/app/views/ssh/index.html.erb b/app/views/ssh/index.html.erb new file mode 100644 index 0000000..cee946c --- /dev/null +++ b/app/views/ssh/index.html.erb @@ -0,0 +1,18 @@ +
+
+
+

Vérifier votre serveur SSH

+
+
+ <%= text_field_tag :ssh_check_host, nil, class: %i(form-control input-lg), placeholder: 'your-site.com' %> +
+
+ <%= text_field_tag :ssh_check_port, nil, class: %i(form-control input-lg), placeholder: 'port' %> +
+
+ <%= submit_tag 'Test-moi !', id: 'ssh_check_submit', class: %i(form-control btn btn-primary input-lg pull-right) %> +
+
+
+
+
diff --git a/app/views/ssh/no_ssh.html.erb b/app/views/ssh/no_ssh.html.erb new file mode 100644 index 0000000..7a492d7 --- /dev/null +++ b/app/views/ssh/no_ssh.html.erb @@ -0,0 +1,12 @@ +
+
+
+

+ <%= @host %> ne supporte pas SSH +

+ <% if Time.now - @result.date >= Rails.configuration.refresh_delay %> + <%= link_to 'Rafraîchir', {action: :refresh}, class: %i(btn btn-default pull-right) %> + <% end %> +
+
+
diff --git a/app/views/ssh/processing.html.erb b/app/views/ssh/processing.html.erb new file mode 100644 index 0000000..fd96ecc --- /dev/null +++ b/app/views/ssh/processing.html.erb @@ -0,0 +1,20 @@ +<% content_for :head do %> + +<% end %> +
+
+
+

+ + [SSH] Analyse en cours de <%= @host %> +

+

+ Début de l’analyse : <%= l @result.date %> +

+

+ Merci de patienter… + (Cette page se rafraîchit automatiquement toutes les 10 secondes) +

+
+
+
diff --git a/app/views/ssh/show.html.erb b/app/views/ssh/show.html.erb new file mode 100644 index 0000000..1537adb --- /dev/null +++ b/app/views/ssh/show.html.erb @@ -0,0 +1,67 @@ +
+
+
+

+ [SSH] <%= @host %> (<%= l @result.date %>) +

+
+ <% if Time.now - @result.date >= Rails.configuration.refresh_delay %> +
+ <%= link_to 'Rafraîchir', {action: :refresh}, class: %i(btn btn-default) %> +
+ <% end %> +
+
+
+
+ + + + + + <% @result.kex.each do |kex| %> + + + + <% end %> + + + + + <% @result.encryption.each do |cipher| %> + + + + <% end %> + + + + + <% @result.hmac.each do |hmac| %> + + + + <% end %> + + + + + <% @result.compression.each do |compression| %> + + + + <% end %> + + + + + <% @result['key'].each do |key| %> + + + + <% end %> + +
Échange de clef
<%= kex_label kex %>
Chiffrement
<%= cipher_label cipher %>
HMAC
<%= hmac_label hmac %>
Compression
<%= compression_label compression %>
Clefs
<%= key_label key %>
+
+
+
diff --git a/app/workers/ssh_worker.rb b/app/workers/ssh_worker.rb new file mode 100644 index 0000000..7b221de --- /dev/null +++ b/app/workers/ssh_worker.rb @@ -0,0 +1,24 @@ +require 'simpleidn' +require 'cryptcheck' + +class SSHWorker + include Sidekiq::Worker + sidekiq_options retry: false + + def perform(host, port) + idn = SimpleIDN.to_ascii host + result = begin + server = CryptCheck::Ssh::Server.new idn, port + { + kex: server.kex, + encryption: server.encryption, + hmac: server.hmac, + compression: server.compression, + key: server.key + } + rescue CryptCheck::Ssh::Server::SshNotAvailableException + { no_ssh: true } + end + Datastore.post :ssh, "#{host}:#{port}", result + end +end diff --git a/config/routes.rb b/config/routes.rb index 5d10e97..75b547f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,8 @@ Rails.application.routes.draw do + get 'ssh/show' + + get 'ssh/index' + namespace :https, id: /[^\/]*/ do get ':id/', action: :show get ':id/refresh', action: :refresh, as: :refresh @@ -14,6 +18,12 @@ Rails.application.routes.draw do get ':id/refresh', action: :refresh, as: :refresh end + namespace :ssh, id: /[^\/]*/ do + get '/', action: :index + get ':id/', action: :show + get ':id/refresh', action: :refresh, as: :refresh + end + root 'site#index' get '/ciphers' => 'site#ciphers' end diff --git a/test/controllers/ssh_controller_test.rb b/test/controllers/ssh_controller_test.rb new file mode 100644 index 0000000..cf7df5c --- /dev/null +++ b/test/controllers/ssh_controller_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class SshControllerTest < ActionController::TestCase + test "should get show" do + get :show + assert_response :success + end + + test "should get index" do + get :index + assert_response :success + end + +end