From 11c86006b7ff9ad3e050bd2ad3960008e52b5405 Mon Sep 17 00:00:00 2001 From: Aeris Date: Wed, 26 Aug 2015 14:30:46 +0200 Subject: [PATCH] Check for SMTP and XMPP too --- Gemfile | 2 - app/assets/javascripts/check.coffee | 0 app/assets/javascripts/https.coffee | 0 app/assets/javascripts/site.coffee.erb | 13 +++-- app/assets/javascripts/smtp.coffee | 3 ++ app/assets/javascripts/xmpp.coffee | 3 ++ app/assets/stylesheets/check.scss | 0 app/assets/stylesheets/https.scss | 0 app/assets/stylesheets/smtp.scss | 3 ++ app/assets/stylesheets/xmpp.scss | 3 ++ app/controllers/check_controller.rb | 39 +++++++++++++++ app/controllers/https_controller.rb | 10 ++++ app/controllers/site_controller.rb | 37 +------------- app/controllers/smtp_controller.rb | 10 ++++ app/controllers/xmpp_controller.rb | 10 ++++ app/helpers/check_helper.rb | 2 + app/helpers/https_helper.rb | 2 + app/helpers/site_helper.rb | 41 +++++++++++----- app/helpers/smtp_helper.rb | 2 + app/helpers/xmpp_helper.rb | 2 + app/views/application/_headers.erb | 3 ++ .../no_tls.html => check/no_tls.html.erb} | 0 app/views/{site => check}/processing.html.erb | 4 +- .../result.html.erb => check/show.html.erb} | 4 +- app/views/site/ciphers.html.erb | 35 ++++++++++++++ app/views/site/index.html.erb | 21 ++++---- app/workers/check_worker.rb | 48 +++++++++++++++++++ app/workers/https_worker.rb | 45 ++++------------- app/workers/smtp_worker.rb | 12 +++++ app/workers/xmpp_worker.rb | 12 +++++ config/application.rb | 19 ++++++-- config/environments/development.rb | 6 --- config/environments/production.rb | 3 -- config/routes.rb | 18 ++++++- test/controllers/check_controller_test.rb | 14 ++++++ test/controllers/https_controller_test.rb | 14 ++++++ test/controllers/smtp_controller_test.rb | 14 ++++++ test/controllers/xmpp_controller_test.rb | 14 ++++++ 38 files changed, 352 insertions(+), 116 deletions(-) create mode 100644 app/assets/javascripts/check.coffee create mode 100644 app/assets/javascripts/https.coffee create mode 100644 app/assets/javascripts/smtp.coffee create mode 100644 app/assets/javascripts/xmpp.coffee create mode 100644 app/assets/stylesheets/check.scss create mode 100644 app/assets/stylesheets/https.scss create mode 100644 app/assets/stylesheets/smtp.scss create mode 100644 app/assets/stylesheets/xmpp.scss create mode 100644 app/controllers/check_controller.rb create mode 100644 app/controllers/https_controller.rb create mode 100644 app/controllers/smtp_controller.rb create mode 100644 app/controllers/xmpp_controller.rb create mode 100644 app/helpers/check_helper.rb create mode 100644 app/helpers/https_helper.rb create mode 100644 app/helpers/smtp_helper.rb create mode 100644 app/helpers/xmpp_helper.rb rename app/views/{site/no_tls.html => check/no_tls.html.erb} (100%) rename app/views/{site => check}/processing.html.erb (85%) rename app/views/{site/result.html.erb => check/show.html.erb} (95%) create mode 100644 app/views/site/ciphers.html.erb create mode 100644 app/workers/check_worker.rb create mode 100644 app/workers/smtp_worker.rb create mode 100644 app/workers/xmpp_worker.rb create mode 100644 test/controllers/check_controller_test.rb create mode 100644 test/controllers/https_controller_test.rb create mode 100644 test/controllers/smtp_controller_test.rb create mode 100644 test/controllers/xmpp_controller_test.rb diff --git a/Gemfile b/Gemfile index f0284ca..0a1cba7 100644 --- a/Gemfile +++ b/Gemfile @@ -2,11 +2,9 @@ source 'https://rubygems.org' gem 'rails', '4.2.1' -gem 'sqlite3' gem 'cryptcheck', '~> 1.0.0', path: File.expand_path(File.join File.dirname(__FILE__), '../cryptcheck') gem 'sidekiq', '~> 3.4.2' gem 'stretcher', '~> 1.21.1' -#gem 'mongo', '~> 2.0.6' gem 'faraday', '~> 0.8.9' # For stretcher compatibility gem 'simpleidn', '~> 0.0.5' diff --git a/app/assets/javascripts/check.coffee b/app/assets/javascripts/check.coffee new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/javascripts/https.coffee b/app/assets/javascripts/https.coffee new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/javascripts/site.coffee.erb b/app/assets/javascripts/site.coffee.erb index b799323..645db99 100644 --- a/app/assets/javascripts/site.coffee.erb +++ b/app/assets/javascripts/site.coffee.erb @@ -1,5 +1,12 @@ $ -> - $('#check_form').submit -> + submit = -> host = $('#check_host').val() - window.location.href = "<%= path :result, %i(host) %>" - false + type = $('#check_type').val() + window.location.href = "<%= Rails.configuration.relative_url_root %>/#{type}/#{host}" + + $('#check_host').keypress (e) -> + submit() if e.which == 13 + return + $('#check_submit').click -> + submit() + return diff --git a/app/assets/javascripts/smtp.coffee b/app/assets/javascripts/smtp.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/smtp.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/xmpp.coffee b/app/assets/javascripts/xmpp.coffee new file mode 100644 index 0000000..24f83d1 --- /dev/null +++ b/app/assets/javascripts/xmpp.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/check.scss b/app/assets/stylesheets/check.scss new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/stylesheets/https.scss b/app/assets/stylesheets/https.scss new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/stylesheets/smtp.scss b/app/assets/stylesheets/smtp.scss new file mode 100644 index 0000000..b32f95d --- /dev/null +++ b/app/assets/stylesheets/smtp.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Smtp controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/xmpp.scss b/app/assets/stylesheets/xmpp.scss new file mode 100644 index 0000000..1b007cd --- /dev/null +++ b/app/assets/stylesheets/xmpp.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Xmpp 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 new file mode 100644 index 0000000..5f87953 --- /dev/null +++ b/app/controllers/check_controller.rb @@ -0,0 +1,39 @@ +class CheckController < ApplicationController + before_action :check_host + + def check_host + @host = params[:id] + @idn = SimpleIDN.to_ascii @host + if /[^a-zA-Z0-9.-]/.match @idn + flash[:danger] = "Hôte #{@host} invalide" + redirect_to :root + return false + end + @result = Datastore.host self.type, @idn + end + + def show + enqueue_host unless @result + return render :processing if @result.pending + return render :no_tls if @result.no_tls + 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 self.type, @host + self.worker.perform_async @idn + @result = OpenStruct.new pending: true , date: Time.now + end +end diff --git a/app/controllers/https_controller.rb b/app/controllers/https_controller.rb new file mode 100644 index 0000000..032ef2c --- /dev/null +++ b/app/controllers/https_controller.rb @@ -0,0 +1,10 @@ +class HttpsController < CheckController + protected + def type + :https + end + + def worker + HTTPSWorker + end +end diff --git a/app/controllers/site_controller.rb b/app/controllers/site_controller.rb index 75cb725..4b0a771 100644 --- a/app/controllers/site_controller.rb +++ b/app/controllers/site_controller.rb @@ -1,42 +1,7 @@ class SiteController < ApplicationController - before_action :check_host, only: %i(result refresh) - - def check_host - @host = params[:id] - @idn = SimpleIDN.to_ascii @host - if /[^a-zA-Z0-9.-]/.match @idn - flash[:danger] = "Hôte #{@host} invalide" - redirect_to :root - return false - end - @result = Datastore.host :https, @idn - end - def index end - def result - enqueue_host unless @result - return render :processing if @result.pending - return render :no_tls if @result.no_tls - 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 :result - end - - private - def enqueue_host - Datastore.pending :https, @host - HTTPSWorker.perform_async @idn - @result = OpenStruct.new pending: true , date: Time.now + def ciphers end end diff --git a/app/controllers/smtp_controller.rb b/app/controllers/smtp_controller.rb new file mode 100644 index 0000000..63ccfaf --- /dev/null +++ b/app/controllers/smtp_controller.rb @@ -0,0 +1,10 @@ +class SmtpController < CheckController + protected + def type + :smtp + end + + def worker + SMTPWorker + end +end diff --git a/app/controllers/xmpp_controller.rb b/app/controllers/xmpp_controller.rb new file mode 100644 index 0000000..4d4de8c --- /dev/null +++ b/app/controllers/xmpp_controller.rb @@ -0,0 +1,10 @@ +class XmppController < CheckController + protected + def type + :xmpp + end + + def worker + XMPPWorker + end +end diff --git a/app/helpers/check_helper.rb b/app/helpers/check_helper.rb new file mode 100644 index 0000000..09d5a13 --- /dev/null +++ b/app/helpers/check_helper.rb @@ -0,0 +1,2 @@ +module CheckHelper +end diff --git a/app/helpers/https_helper.rb b/app/helpers/https_helper.rb new file mode 100644 index 0000000..37d34c5 --- /dev/null +++ b/app/helpers/https_helper.rb @@ -0,0 +1,2 @@ +module HttpsHelper +end diff --git a/app/helpers/site_helper.rb b/app/helpers/site_helper.rb index 3f305a2..1ac54db 100644 --- a/app/helpers/site_helper.rb +++ b/app/helpers/site_helper.rb @@ -35,7 +35,7 @@ module SiteHelper end def protocol_label(protocol) - color = case protocol + color = case protocol.to_s when 'TLSv1_2' then :success when 'SSLv3', 'SSLv2' then :danger else :default @@ -57,8 +57,9 @@ module SiteHelper keys.sort { |a, b| -1 * (a.rsa_size <=> b.rsa_size)} .collect { |k| key_label k }.join("\n").html_safe end - def cipher_label(cipher) - "\">#{cipher['size']} bits".html_safe + def cipher_size_label(cipher) + size = cipher.kind_of?(CryptCheck::Tls::Cipher) ? cipher.size : cipher['size'] + "\">#{size} bits".html_safe end def color_key(key) @@ -72,20 +73,38 @@ module SiteHelper def cipher_color(key) case key - when 0...112 then :error + when 0...112 then :danger when 112...128 then :warning when 128...256 then :success else :primary end end + def cipher_name_label(cipher, state) + color = case + when !state[:danger].empty? then :danger + when !state[:warning].empty? then :warning + when !state[:success].empty? then :success + else :default + end + color = :primary if color == :success and cipher.size >= 256 + "\">#{cipher.name}".html_safe + end + def cipher_labels(cipher) - { success: %i(pfs), - warning: %i(des3 sha1), - danger: %i(md5 psk srp anonymous null export des rc2 rc4) - }.collect do |color, types| - types.select { |t| CryptCheck::Tls::Cipher.send "#{t}?", cipher.name } - .collect { |t| "#{t.upcase}" } - end.flatten(1).join("\n").html_safe + case cipher + when Hashie::Mash + { success: %i(pfs), + warning: %i(des3 sha1), + danger: %i(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 + when Hash + cipher.collect { |c, ts| ts.collect { |t| [c, t] } } + end + .flatten(1) + .collect { |c, t| "#{t.upcase}" } + .join("\n").html_safe end end diff --git a/app/helpers/smtp_helper.rb b/app/helpers/smtp_helper.rb new file mode 100644 index 0000000..7fb720b --- /dev/null +++ b/app/helpers/smtp_helper.rb @@ -0,0 +1,2 @@ +module SmtpHelper +end diff --git a/app/helpers/xmpp_helper.rb b/app/helpers/xmpp_helper.rb new file mode 100644 index 0000000..6022b1f --- /dev/null +++ b/app/helpers/xmpp_helper.rb @@ -0,0 +1,2 @@ +module XmppHelper +end diff --git a/app/views/application/_headers.erb b/app/views/application/_headers.erb index 4d6858f..45442ba 100644 --- a/app/views/application/_headers.erb +++ b/app/views/application/_headers.erb @@ -4,6 +4,9 @@ + + <% + context.ciphers = 'ALL:COMPLEMENTOFALL' + context.ciphers.collect { |c| CryptCheck::Tls::Cipher.new protocol, c } + .sort { |a, b| -1 * (a.size <=> b.size)}.each do |cipher| %> + + <% state = cipher.state %> + <%= cipher_name_label cipher, state %> + <%= cipher_size_label cipher %> + <%= cipher_labels state %> + + <% end %> + <% end %> + + + + diff --git a/app/views/site/index.html.erb b/app/views/site/index.html.erb index 6794006..5b6dd48 100644 --- a/app/views/site/index.html.erb +++ b/app/views/site/index.html.erb @@ -1,17 +1,18 @@
-
+

Vérifier votre domaine

-
-
-
- <%= text_field_tag :check_host, nil, class: %i(form-control input-lg), placeholder: 'your-site.com' %> -
-
- <%= submit_tag 'Test-moi !', class: %i(form-control btn btn-primary input-lg pull-right) %> -
+
+
+ <%= text_field_tag :check_host, nil, class: %i(form-control input-lg), placeholder: 'your-site.com' %>
- +
+ <%= select_tag :check_type, options_for_select({'HTTPS' => :https, 'SMTP' => :smtp, 'XMPP' => :xmpp}), class: %i(form-control input-lg) %> +
+
+ <%= submit_tag 'Test-moi !', id: 'check_submit', class: %i(form-control btn btn-primary input-lg pull-right) %> +
+
diff --git a/app/workers/check_worker.rb b/app/workers/check_worker.rb new file mode 100644 index 0000000..7ff25f0 --- /dev/null +++ b/app/workers/check_worker.rb @@ -0,0 +1,48 @@ +require 'simpleidn' +require 'cryptcheck' + +class CheckWorker + include Sidekiq::Worker + sidekiq_options retry: false + + def key_to_json(key) + key.nil? ? nil : { type: key.type, size: key.size, rsa_size: key.rsa_equivalent_size } + end + + def perform(host) + idn = SimpleIDN.to_ascii host + result = begin + server = self.module::Server.new idn + grade = self.module::Grade.new server + result = { + key: key_to_json(server.key), + dh: server.dh.collect { |k| key_to_json k }, + protocols: server.supported_protocols, + ciphers: server.supported_ciphers.collect { |c| { protocol: c.protocol, name: c.name, size: c.size, dh: key_to_json(c.dh) } }, + score: { + rank: grade.grade, + details: { + score: grade.score, + protocol: grade.protocol_score, + key_exchange: grade.key_exchange_score, + cipher_strengths: grade.cipher_strengths_score + }, + error: grade.error, + warning: grade.warning, + success: grade.success + } + } + + + self.result server, grade, result + rescue CryptCheck::Tls::Server::TLSNotAvailableException + { no_tls: true } + end + Datastore.post self.type, host, result + end + + protected + def result(_, _, result) + result + end +end diff --git a/app/workers/https_worker.rb b/app/workers/https_worker.rb index 42326ec..148f91c 100644 --- a/app/workers/https_worker.rb +++ b/app/workers/https_worker.rb @@ -1,42 +1,17 @@ -require 'simpleidn' -require 'cryptcheck' - -class HTTPSWorker - include Sidekiq::Worker +class HTTPSWorker < CheckWorker sidekiq_options retry: false - def key_to_json(key) - key.nil? ? nil : { type: key.type, size: key.size, rsa_size: key.rsa_equivalent_size } + protected + def module + CryptCheck::Tls::Https end - def perform(host) - idn = SimpleIDN.to_ascii host - result = begin - server = CryptCheck::Tls::Https::Server.new idn - grade = CryptCheck::Tls::Https::Grade.new server + def type + :https + end - { - key: key_to_json(server.key), - dh: server.dh.collect { |k| key_to_json k }, - protocols: server.supported_protocols, - ciphers: server.supported_ciphers.collect { |c| { protocol: c.protocol, name: c.name, size: c.size, dh: key_to_json(c.dh) } }, - hsts: server.hsts, - score: { - rank: grade.grade, - details: { - score: grade.score, - protocol: grade.protocol_score, - key_exchange: grade.key_exchange_score, - cipher_strengths: grade.cipher_strengths_score - }, - error: grade.error, - warning: grade.warning, - success: grade.success - } - } - rescue CryptCheck::Tls::Server::TLSNotAvailableException - { no_tls: true } - end - Datastore.post :https, host, result + def result(server, _, hash) + hash[:hsts] = server.hsts + hash end end diff --git a/app/workers/smtp_worker.rb b/app/workers/smtp_worker.rb new file mode 100644 index 0000000..319f70e --- /dev/null +++ b/app/workers/smtp_worker.rb @@ -0,0 +1,12 @@ +class SMTPWorker < CheckWorker + sidekiq_options retry: false + + protected + def module + CryptCheck::Tls::Smtp + end + + def type + :smtp + end +end diff --git a/app/workers/xmpp_worker.rb b/app/workers/xmpp_worker.rb new file mode 100644 index 0000000..9fd0bd8 --- /dev/null +++ b/app/workers/xmpp_worker.rb @@ -0,0 +1,12 @@ +class XMPPWorker < CheckWorker + sidekiq_options retry: false + + protected + def module + CryptCheck::Tls::Xmpp + end + + def type + :xmpp + end +end diff --git a/config/application.rb b/config/application.rb index c48bbb3..823cf46 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,6 +1,20 @@ require File.expand_path('../boot', __FILE__) -require 'rails/all' +%w( + action_controller + action_view + active_job + rails/test_unit + sprockets +).each do |framework| + begin + require "#{framework}/railtie" + rescue LoadError + end +end + + + # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. @@ -26,9 +40,6 @@ module CryptcheckRails # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] config.i18n.default_locale = :fr - # Do not swallow errors in after_commit/after_rollback callbacks. - config.active_record.raise_in_transactional_callbacks = true - config.refresh_delay = 1.hour end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 2928d6c..161962f 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -13,15 +13,9 @@ Rails.application.configure do config.consider_all_requests_local = true config.action_controller.perform_caching = false - # Don't care if the mailer can't send. - config.action_mailer.raise_delivery_errors = false - # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log - # Raise an error on page load if there are pending migrations. - config.active_record.migration_error = :page_load - # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. diff --git a/config/environments/production.rb b/config/environments/production.rb index 5c1b32e..a008b61 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -73,7 +73,4 @@ Rails.application.configure do # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new - - # Do not dump schema after migrations. - config.active_record.dump_schema_after_migration = false end diff --git a/config/routes.rb b/config/routes.rb index bc4ebb8..5d10e97 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,19 @@ Rails.application.routes.draw do + namespace :https, id: /[^\/]*/ do + get ':id/', action: :show + get ':id/refresh', action: :refresh, as: :refresh + end + + namespace :smtp, id: /[^\/]*/ do + get ':id/', action: :show + get ':id/refresh', action: :refresh, as: :refresh + end + + namespace :xmpp, id: /[^\/]*/ do + get ':id/', action: :show + get ':id/refresh', action: :refresh, as: :refresh + end + root 'site#index' - get '/:id/refresh' => 'site#refresh', as: :refresh, id: /.*/ - get '/:id' => 'site#result', as: :result, id: /.*/ + get '/ciphers' => 'site#ciphers' end diff --git a/test/controllers/check_controller_test.rb b/test/controllers/check_controller_test.rb new file mode 100644 index 0000000..761ee84 --- /dev/null +++ b/test/controllers/check_controller_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class CheckControllerTest < ActionController::TestCase + test "should get result" do + get :show + assert_response :success + end + + test "should get refresh" do + get :refresh + assert_response :success + end + +end diff --git a/test/controllers/https_controller_test.rb b/test/controllers/https_controller_test.rb new file mode 100644 index 0000000..056cd91 --- /dev/null +++ b/test/controllers/https_controller_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class HttpsControllerTest < ActionController::TestCase + test "should get result" do + get :show + assert_response :success + end + + test "should get refresh" do + get :refresh + assert_response :success + end + +end diff --git a/test/controllers/smtp_controller_test.rb b/test/controllers/smtp_controller_test.rb new file mode 100644 index 0000000..d6039ed --- /dev/null +++ b/test/controllers/smtp_controller_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class SmtpControllerTest < ActionController::TestCase + test "should get show" do + get :show + assert_response :success + end + + test "should get refresh" do + get :refresh + assert_response :success + end + +end diff --git a/test/controllers/xmpp_controller_test.rb b/test/controllers/xmpp_controller_test.rb new file mode 100644 index 0000000..fbf1123 --- /dev/null +++ b/test/controllers/xmpp_controller_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class XmppControllerTest < ActionController::TestCase + test "should get show" do + get :show + assert_response :success + end + + test "should get refresh" do + get :refresh + assert_response :success + end + +end