Browse Source

SSH support

Aeris 3 years ago
parent
commit
02e6367d17

+ 16
- 0
app/assets/javascripts/ssh.coffee.erb View File

@@ -0,0 +1,16 @@
1
+$ ->
2
+	ssh_submit = ->
3
+		host = $('#ssh_check_host').val()
4
+		port = $('#ssh_check_port').val()
5
+		port = 22 if port == ''
6
+		window.location.href = "<%= Rails.configuration.relative_url_root %>/ssh/#{host}:#{port}"
7
+
8
+	$('#ssh_check_host').keypress (e) ->
9
+		ssh_submit() if e.which == 13
10
+		return
11
+	$('#ssh_check_port').keypress (e) ->
12
+		ssh_submit() if e.which == 13
13
+		return
14
+	$('#ssh_check_submit').click ->
15
+		ssh_submit()
16
+		return

+ 3
- 0
app/assets/stylesheets/ssh.scss View File

@@ -0,0 +1,3 @@
1
+// Place all the styles related to the ssh controller here.
2
+// They will automatically be included in application.css.
3
+// You can use Sass (SCSS) here: http://sass-lang.com/

+ 1
- 0
app/controllers/check_controller.rb View File

@@ -1,5 +1,6 @@
1 1
 class CheckController < ApplicationController
2 2
 	before_action :check_host
3
+	helper_method :tls_type, :type
3 4
 
4 5
 	def check_host
5 6
 		@host = params[:id]

+ 4
- 0
app/controllers/https_controller.rb View File

@@ -7,4 +7,8 @@ class HttpsController < CheckController
7 7
 	def worker
8 8
 		HTTPSWorker
9 9
 	end
10
+
11
+	def tls_type
12
+		'HTTPS'
13
+	end
10 14
 end

+ 4
- 0
app/controllers/smtp_controller.rb View File

@@ -7,4 +7,8 @@ class SmtpController < CheckController
7 7
 	def worker
8 8
 		SMTPWorker
9 9
 	end
10
+
11
+	def tls_type
12
+		'STARTTLS'
13
+	end
10 14
 end

+ 43
- 0
app/controllers/ssh_controller.rb View File

@@ -0,0 +1,43 @@
1
+class SshController < ApplicationController
2
+	before_action :check_host, except: %i(index)
3
+
4
+	def check_host
5
+		@host, @port = params[:id].split ':'
6
+		@idn         = SimpleIDN.to_ascii @host
7
+		if /[^a-zA-Z0-9.-]/.match @idn
8
+			flash[:danger] = "Hôte #{@host} invalide"
9
+			redirect_to :index
10
+			return false
11
+		end
12
+		@host   = "#{@idn}:#{@port}"
13
+		@result = Datastore.host :ssh, @host
14
+	end
15
+
16
+	def index
17
+	end
18
+
19
+	def show
20
+		enqueue_host unless @result
21
+		return render :processing if @result.pending
22
+		return render :no_ssh if @result.no_ssh
23
+	end
24
+
25
+	def refresh
26
+		unless @result.pending
27
+			refresh_allowed = @result.date + Rails.configuration.refresh_delay
28
+			if Time.now < refresh_allowed
29
+				flash[:warning] = "Merci d’attendre au moins #{l refresh_allowed} pour rafraîchir"
30
+				return redirect_to result_path @host
31
+			end
32
+			enqueue_host
33
+		end
34
+		redirect_to action: :show
35
+	end
36
+
37
+	protected
38
+	def enqueue_host
39
+		Datastore.pending :ssh, @host
40
+		SSHWorker.perform_async @idn, @port
41
+		@result = OpenStruct.new pending: true, date: Time.now
42
+	end
43
+end

+ 4
- 0
app/controllers/xmpp_controller.rb View File

@@ -7,4 +7,8 @@ class XmppController < CheckController
7 7
 	def worker
8 8
 		XMPPWorker
9 9
 	end
10
+
11
+	def tls_type
12
+		'STARTTLS'
13
+	end
10 14
 end

+ 1
- 1
app/helpers/site_helper.rb View File

@@ -96,7 +96,7 @@ module SiteHelper
96 96
 			when Hashie::Mash
97 97
 				{ success: %i(pfs),
98 98
 				  warning: %i(des3 sha1),
99
-				  danger: %i(md5 psk srp anonymous null export des rc2 rc4)
99
+				  danger: %i(dss md5 psk srp anonymous null export des rc2 rc4)
100 100
 				}.collect do |c, ts|
101 101
 					ts.select { |t| CryptCheck::Tls::Cipher.send "#{t}?", cipher.name }.collect { |t| [c, t] }
102 102
 				end

+ 28
- 0
app/helpers/ssh_helper.rb View File

@@ -0,0 +1,28 @@
1
+module SshHelper
2
+	COLORS = { green: :success, yellow: :warning, red: :danger, nil => :default  }
3
+
4
+	def kex_label(key)
5
+		label key, COLORS[CryptCheck::Ssh::Server::KEX[key]]
6
+	end
7
+
8
+	def cipher_label(cipher)
9
+		label cipher, COLORS[CryptCheck::Ssh::Server::ENCRYPTION[cipher]]
10
+	end
11
+
12
+	def hmac_label(hmac)
13
+		label hmac, COLORS[CryptCheck::Ssh::Server::HMAC[hmac]]
14
+	end
15
+
16
+	def compression_label(compression)
17
+		label compression, COLORS[CryptCheck::Ssh::Server::COMPRESSION[compression]]
18
+	end
19
+
20
+	def key_label(key)
21
+		label key, COLORS[CryptCheck::Ssh::Server::KEY[key]]
22
+	end
23
+
24
+	private
25
+	def label(name, color)
26
+		"<span class=\"label label-#{color}\">&nbsp;</span>&nbsp;#{name}".html_safe
27
+	end
28
+end

+ 6
- 4
app/views/application/_headers.erb View File

@@ -2,13 +2,15 @@
2 2
 	<nav class="navbar navbar-inverse navbar-fixed-top">
3 3
 		<div class="container">
4 4
 			<div class="navbar-header">
5
-				<%= link_to 'CryptCheck', root_path, class: %i(navbar-brand) %>
5
+				<span class="navbar-brand">CryptCheck</span>
6 6
 			</div>
7 7
 			<ul class="nav navbar-nav">
8
-				<li><%= link_to 'Ciphers', ciphers_path %></li>
8
+				<li><%= link_to 'HTTPS / SMTP / XMPP', root_path %></li>
9
+				<li><%= link_to 'SSH', ssh_path %></li>
9 10
 			</ul>
10
-			<!--
11 11
 			<ul class="nav navbar-nav navbar-right">
12
+				<li><%= link_to 'Ciphers', ciphers_path %></li>
13
+				<!--
12 14
 				<li class="dropdown">
13 15
 					<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
14 16
 						Hall of f/sh·ame
@@ -24,8 +26,8 @@
24 26
 						<li><a href="#">US gov</a></li>
25 27
 					</ul>
26 28
 				</li>
29
+				-->
27 30
 			</ul>
28
-			-->
29 31
 		</div>
30 32
 	</nav>
31 33
 </header>

+ 4
- 1
app/views/check/no_tls.html.erb View File

@@ -2,8 +2,11 @@
2 2
 	<div class="row">
3 3
 		<div class="col-sm-8 col-sm-offset-2">
4 4
 			<h1>
5
-				<%= @host %> ne supporte pas HTTPS
5
+				[<%= self.type.to_s.upcase %>] <%= @host %> ne supporte pas <%= self.tls_type %>
6 6
 			</h1>
7
+			<% if Time.now - @result.date >= Rails.configuration.refresh_delay %>
8
+			<%= link_to 'Rafraîchir', {action: :refresh}, class: %i(btn btn-default pull-right) %>
9
+			<% end %>
7 10
 		</div>
8 11
 	</div>
9 12
 </div>

+ 1
- 1
app/views/check/processing.html.erb View File

@@ -6,7 +6,7 @@
6 6
 		<div class="col-sm-8 col-sm-offset-2">
7 7
 			<h1>
8 8
 				<i class="fa fa-spinner fa-pulse"></i>
9
-				Analyse en cours de <%= @host %>
9
+				[<%= self.type.to_s.upcase %>] Analyse en cours de <%= @host %>
10 10
 			</h1>
11 11
 			<p class="small">
12 12
 				Début de l’analyse : <%= l @result.date %>

+ 1
- 1
app/views/check/show.html.erb View File

@@ -2,7 +2,7 @@
2 2
 	<div class="row">
3 3
 		<div class="col-sm-11">
4 4
 			<h1>
5
-				Résultats pour <%= @host %> <span class="small">(<%= l @result.date %>)</span>
5
+				[<%= self.type.to_s.upcase %>] <%= @host %> <span class="small">(<%= l @result.date %>)</span>
6 6
 				<%= rank_label @result.score.rank %>
7 7
 			</h1>
8 8
 		</div>

+ 18
- 0
app/views/ssh/index.html.erb View File

@@ -0,0 +1,18 @@
1
+<div id="ssh_check" class="container">
2
+	<div class="row">
3
+		<div class="col-sm-12">
4
+			<h1>Vérifier votre serveur SSH</h1>
5
+			<div class="form-group">
6
+				<div class="col-sm-8">
7
+					<%= text_field_tag :ssh_check_host, nil, class: %i(form-control input-lg), placeholder: 'your-site.com' %>
8
+				</div>
9
+				<div class="col-sm-2">
10
+					<%= text_field_tag :ssh_check_port, nil, class: %i(form-control input-lg), placeholder: 'port' %>
11
+				</div>
12
+				<div class="col-sm-2">
13
+					<%= submit_tag 'Test-moi !', id: 'ssh_check_submit', class: %i(form-control btn btn-primary input-lg pull-right) %>
14
+				</div>
15
+			</div>
16
+		</div>
17
+	</div>
18
+</div>

+ 12
- 0
app/views/ssh/no_ssh.html.erb View File

@@ -0,0 +1,12 @@
1
+<div id="check" class="container">
2
+	<div class="row">
3
+		<div class="col-sm-8 col-sm-offset-2">
4
+			<h1>
5
+				<%= @host %> ne supporte pas SSH
6
+			</h1>
7
+			<% if Time.now - @result.date >= Rails.configuration.refresh_delay %>
8
+			<%= link_to 'Rafraîchir', {action: :refresh}, class: %i(btn btn-default pull-right) %>
9
+			<% end %>
10
+		</div>
11
+	</div>
12
+</div>

+ 20
- 0
app/views/ssh/processing.html.erb View File

@@ -0,0 +1,20 @@
1
+<% content_for :head do %>
2
+	<meta http-equiv="refresh" content="10">
3
+<% end %>
4
+<div id="check" class="container">
5
+	<div class="row">
6
+		<div class="col-sm-8 col-sm-offset-2">
7
+			<h1>
8
+				<i class="fa fa-spinner fa-pulse"></i>
9
+				[SSH] Analyse en cours de <%= @host %>
10
+			</h1>
11
+			<p class="small">
12
+				Début de l’analyse : <%= l @result.date %>
13
+			</p>
14
+			<p class="pull-right">
15
+				Merci de patienter…
16
+				<span class="small">(Cette page se rafraîchit automatiquement toutes les 10 secondes)</span>
17
+			</p>
18
+		</div>
19
+	</div>
20
+</div>

+ 67
- 0
app/views/ssh/show.html.erb View File

@@ -0,0 +1,67 @@
1
+<div class="container">
2
+	<div class="row">
3
+		<div class="col-sm-11">
4
+			<h1>
5
+				[SSH] <%= @host %> <span class="small">(<%= l @result.date %>)</span>
6
+			</h1>
7
+		</div>
8
+		<% if Time.now - @result.date >= Rails.configuration.refresh_delay %>
9
+		<div class="col-sm-1">
10
+			<%= link_to 'Rafraîchir', {action: :refresh}, class: %i(btn btn-default) %>
11
+		</div>
12
+		<% end %>
13
+	</div>
14
+	<br/>
15
+	<div class="row">
16
+		<div class="col-sm-12">
17
+			<table class="table table-bordered table-condensed table-striped">
18
+				<tbody>
19
+					<tr>
20
+						<th>Échange de clef</th>
21
+					</tr>
22
+					<% @result.kex.each do |kex| %>
23
+					<tr>
24
+						<td><%= kex_label kex %></td>
25
+					</tr>
26
+					<% end %>
27
+
28
+					<tr>
29
+						<th>Chiffrement</th>
30
+					</tr>
31
+					<% @result.encryption.each do |cipher| %>
32
+					<tr>
33
+						<td><%= cipher_label cipher %></td>
34
+					</tr>
35
+					<% end %>
36
+
37
+					<tr>
38
+						<th>HMAC</th>
39
+					</tr>
40
+					<% @result.hmac.each do |hmac| %>
41
+						<tr>
42
+							<td><%= hmac_label hmac %></td>
43
+						</tr>
44
+					<% end %>
45
+
46
+					<tr>
47
+						<th>Compression</th>
48
+					</tr>
49
+					<% @result.compression.each do |compression| %>
50
+						<tr>
51
+							<td><%= compression_label compression %></td>
52
+						</tr>
53
+					<% end %>
54
+
55
+					<tr>
56
+						<th>Clefs</th>
57
+					</tr>
58
+					<% @result['key'].each do |key| %>
59
+					<tr>
60
+						<td><%= key_label key %></td>
61
+					</tr>
62
+					<% end %>
63
+				</tbody>
64
+			</table>
65
+		</div>
66
+	</div>
67
+</div>

+ 24
- 0
app/workers/ssh_worker.rb View File

@@ -0,0 +1,24 @@
1
+require 'simpleidn'
2
+require 'cryptcheck'
3
+
4
+class SSHWorker
5
+	include Sidekiq::Worker
6
+	sidekiq_options retry: false
7
+
8
+	def perform(host, port)
9
+		idn    = SimpleIDN.to_ascii host
10
+		result = begin
11
+			server = CryptCheck::Ssh::Server.new idn, port
12
+			{
13
+					kex:         server.kex,
14
+					encryption:  server.encryption,
15
+					hmac:        server.hmac,
16
+					compression: server.compression,
17
+					key:         server.key
18
+			}
19
+		rescue CryptCheck::Ssh::Server::SshNotAvailableException
20
+			{ no_ssh: true }
21
+		end
22
+		Datastore.post :ssh, "#{host}:#{port}", result
23
+	end
24
+end

+ 10
- 0
config/routes.rb View File

@@ -1,4 +1,8 @@
1 1
 Rails.application.routes.draw do
2
+  get 'ssh/show'
3
+
4
+  get 'ssh/index'
5
+
2 6
 	namespace :https, id: /[^\/]*/ do
3 7
 		get ':id/', action: :show
4 8
 		get ':id/refresh', action: :refresh, as: :refresh
@@ -14,6 +18,12 @@ Rails.application.routes.draw do
14 18
 		get ':id/refresh', action: :refresh, as: :refresh
15 19
 	end
16 20
 
21
+	namespace :ssh, id: /[^\/]*/ do
22
+		get '/', action: :index
23
+		get ':id/', action: :show
24
+		get ':id/refresh', action: :refresh, as: :refresh
25
+	end
26
+
17 27
 	root 'site#index'
18 28
 	get '/ciphers' => 'site#ciphers'
19 29
 end

+ 14
- 0
test/controllers/ssh_controller_test.rb View File

@@ -0,0 +1,14 @@
1
+require 'test_helper'
2
+
3
+class SshControllerTest < ActionController::TestCase
4
+  test "should get show" do
5
+    get :show
6
+    assert_response :success
7
+  end
8
+
9
+  test "should get index" do
10
+    get :index
11
+    assert_response :success
12
+  end
13
+
14
+end

Loading…
Cancel
Save