Compare commits
8 Commits
d1eed36b6e
...
b79153d477
Author | SHA1 | Date |
---|---|---|
|
b79153d477 | 8 months ago |
|
4280db5e4c | 8 months ago |
|
e6a36dc056 | 8 months ago |
|
089a3b98be | 8 months ago |
|
792bdf6d24 | 10 months ago |
|
8d58fa62c2 | 10 months ago |
|
a1a7f4ce95 | 10 months ago |
|
ac4345856c | 10 months ago |
@ -0,0 +1,3 @@ |
||||
--require spec_helper |
||||
--format progress |
||||
--format html --out tmp/rspec.html |
@ -0,0 +1,2 @@ |
||||
sidekiq: bundle exec sidekiq -q default |
||||
sidekiq_1_0: BUNDLE_GEMFILE=Gemfile-2.3 bin/sidekiq 1.0 -q tls_1_0 |
@ -0,0 +1,14 @@ |
||||
class SitesController < ApplicationController |
||||
@@sites = YAML.load_file Rails.root.join 'config/sites.yml' |
||||
@@sites.keys.each do |name| |
||||
define_method(name) { sites name } |
||||
end |
||||
|
||||
private |
||||
|
||||
def sites(name) |
||||
@name = name |
||||
@sites = Stat[:"sites_#{name}"].data |
||||
render :sites |
||||
end |
||||
end |
@ -0,0 +1,23 @@ |
||||
class StatisticsController < ApplicationController |
||||
TODAY = Date.today |
||||
|
||||
def show |
||||
service = params.fetch :id |
||||
respond_to do |format| |
||||
format.json do |
||||
json = Stat["grades_for_#{service}"].data |
||||
render json: json, status: :ok |
||||
end |
||||
end |
||||
end |
||||
|
||||
def ciphers |
||||
service = params.fetch :id |
||||
render json: Stat["ciphers_for_#{service}"].data |
||||
end |
||||
|
||||
def tls |
||||
service = params.fetch :id |
||||
render json: Stat["tls_for_#{service}"].data |
||||
end |
||||
end |
@ -0,0 +1,14 @@ |
||||
class StatsController < ApplicationController |
||||
@@sites = YAML.load_file Rails.root.join 'config/sites.yml' |
||||
|
||||
def banks |
||||
sites :banks |
||||
end |
||||
|
||||
private |
||||
|
||||
def sites(name) |
||||
@sites = @@sites.fetch name.to_s |
||||
render 'stats/sites' |
||||
end |
||||
end |
@ -1,2 +0,0 @@ |
||||
module ApplicationHelper |
||||
end |
@ -0,0 +1,2 @@ |
||||
module StatisticsHelper |
||||
end |
@ -0,0 +1,40 @@ |
||||
document.addEventListener("DOMContentLoaded", () => { |
||||
let gradesChart = document.getElementById('gradesChart').getContext('2d') |
||||
|
||||
let background = [ |
||||
'rgba(255, 99, 132, 1)', |
||||
'rgba(54, 162, 235, 1)', |
||||
'rgba(255, 206, 86, 1)', |
||||
'rgba(75, 192, 192, 1)', |
||||
'rgba(153, 102, 255, 1)', |
||||
'rgba(255, 159, 64, 1)' |
||||
] |
||||
|
||||
let createGradesChart = new Chart(gradesChart, { |
||||
type: 'bar' |
||||
}) |
||||
|
||||
let generateGraphs = function () { |
||||
fetch(window.location.href, { |
||||
method: "GET", |
||||
headers: { |
||||
"Accept": "application/json", |
||||
"Content-Type": "application/json", |
||||
}, |
||||
}).then((response) => { |
||||
response.json().then((data) => { |
||||
if (response.status === 200) { |
||||
createGradesChart.data.labels = data["labels"] |
||||
createGradesChart.data.datasets = [{ |
||||
label: 'Number', |
||||
data: data["dataset"], |
||||
backgroundColor: background |
||||
}] |
||||
createGradesChart.update() |
||||
} |
||||
}) |
||||
}); |
||||
} |
||||
|
||||
generateGraphs() |
||||
}); |
@ -0,0 +1,72 @@ |
||||
document.addEventListener("DOMContentLoaded", () => { |
||||
let background = [ |
||||
'#5cb85c', // A+
|
||||
'#5cb85c', // A
|
||||
'#8db457', // B+
|
||||
'#8db457', // B
|
||||
'#beb052', // C+
|
||||
'#beb052', // C
|
||||
'#6c757d', // D
|
||||
'#f0ad4e', // E
|
||||
'#e4804e', // F
|
||||
'#d9534f' // G
|
||||
] |
||||
|
||||
for (const service of ["https", "smtp", "tls", "xmpp"]) { |
||||
const name = service.replace(/^\w/, c => c.toUpperCase()) |
||||
console.info(`grades${name}Chart`) |
||||
const canvas = document.getElementById(`grades${name}Chart`).getContext('2d') |
||||
// const chart = new Chart(canvas, {
|
||||
// type: 'pie',
|
||||
// options: {
|
||||
// interaction: {
|
||||
// intersect: false,
|
||||
// mode: 'dataset',
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
const chart = new Chart(canvas, { |
||||
type: 'bar', |
||||
options: { |
||||
interaction: { |
||||
intersect: false, |
||||
mode: 'dataset', |
||||
}, |
||||
plugins: { |
||||
datalabels: { |
||||
anchor: 'end', |
||||
align: 'top', |
||||
formatter: ((value, context) => { |
||||
const index = context.dataIndex |
||||
const keys = Object.keys(context.dataset.data) |
||||
value = context.dataset.data[keys[index]] |
||||
return value |
||||
}), |
||||
color: "black", |
||||
font: { |
||||
weight: "bold", |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
|
||||
fetch(`/statistics/${service}.json`).then((response) => { |
||||
if (response.status === 200) { |
||||
response.json().then((data) => { |
||||
const labels = ["A+", "A", "B+", "B", "C+", "C", "D", "E", "F", "G"] |
||||
const dataset = JSON.parse(JSON.stringify(data, labels, 0)) |
||||
chart.data.labels = labels |
||||
chart.data.datasets = [{ |
||||
label: 'Number of request', |
||||
data: dataset, |
||||
backgroundColor: background |
||||
}] |
||||
chart.update() |
||||
}) |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
) |
||||
; |
@ -1 +1,8 @@ |
||||
import 'css/application' |
||||
|
||||
import Chart from 'chart.js/auto' |
||||
import ChartDataLabels from 'chartjs-plugin-datalabels' |
||||
global.Chart = Chart |
||||
Chart.register(ChartDataLabels) |
||||
|
||||
import 'js/stats/grades' |
||||
|
@ -1,36 +1,67 @@ |
||||
class Analysis < ApplicationRecord |
||||
enum service: %i[https smtp xmpp tls ssh].collect { |e| [e, e.to_s] }.to_h |
||||
validates :service, presence: true |
||||
validates :host, presence: true |
||||
|
||||
def self.[](service, host, args) |
||||
key = self.key service, host, args |
||||
self.find_by key |
||||
end |
||||
|
||||
def self.pending!(service, host, args) |
||||
key = self.key service, host, args |
||||
analysis = self.find_or_create_by! key |
||||
analysis.pending! |
||||
end |
||||
|
||||
def pending! |
||||
self.update! pending: true |
||||
self |
||||
end |
||||
|
||||
def self.post!(service, host, args, result) |
||||
analysis = self[service, host, args] |
||||
analysis.post! result |
||||
end |
||||
|
||||
def post!(result) |
||||
self.update! pending: false, result: result |
||||
end |
||||
|
||||
private |
||||
|
||||
def self.key(service, host, args) |
||||
{ service: service, host: host, args: args } |
||||
end |
||||
enum service: %i[https smtp xmpp tls ssh].collect { |e| [e, e.to_s] }.to_h |
||||
validates :service, presence: true |
||||
validates :host, presence: true |
||||
|
||||
def self.[](service, host, args) |
||||
key = self.key service, host, args |
||||
self.find_by key |
||||
end |
||||
|
||||
def self.pending!(service, host, args) |
||||
key = self.key service, host, args |
||||
analysis = self.find_or_create_by! key |
||||
analysis.pending! |
||||
end |
||||
|
||||
def pending! |
||||
self.update! pending: true |
||||
self |
||||
end |
||||
|
||||
def self.post!(service, host, args, result) |
||||
analysis = self[service, host, args] |
||||
analysis.post! result |
||||
end |
||||
|
||||
RESOLVER = ::Resolv::DNS.new |
||||
DNS_TXT_FORMAT = /^cryptcheck=(.*)/ |
||||
DEBUG = 'debug' |
||||
DEFAULT_REFRESH_DELAY = Rails.configuration.refresh_delay |
||||
|
||||
def find_refresh_delay |
||||
host = self.host |
||||
loop do |
||||
break unless host && PublicSuffix.valid?(host) |
||||
RESOLVER.getresources(host, ::Resolv::DNS::Resource::IN::TXT).each do |txt| |
||||
txt.strings.each do |value| |
||||
if match = DNS_TXT_FORMAT.match(value) |
||||
match = match[1] |
||||
return if match == DEBUG |
||||
begin |
||||
delay = ::ActiveSupport::Duration.parse match |
||||
delay = DEFAULT_REFRESH_DELAY if delay > DEFAULT_REFRESH_DELAY |
||||
return delay |
||||
rescue ActiveSupport::Duration::ISO8601Parser::ParsingError |
||||
end |
||||
end |
||||
end |
||||
end |
||||
_, host = host.split '.', 2 |
||||
end |
||||
DEFAULT_REFRESH_DELAY |
||||
rescue |
||||
DEFAULT_REFRESH_DELAY |
||||
end |
||||
|
||||
def post!(result) |
||||
refresh_at = self.find_refresh_delay&.since |
||||
self.update! pending: false, refresh_at: refresh_at, result: result |
||||
end |
||||
|
||||
private |
||||
|
||||
def self.key(service, host, args) |
||||
{ service: service, host: host, args: args } |
||||
end |
||||
end |
||||
|
@ -0,0 +1,10 @@ |
||||
class Stat < ApplicationRecord |
||||
def self.create!(name, data, date = Date.today) |
||||
self.delete_by name: name, date: date |
||||
super name: name, date: date, data: data |
||||
end |
||||
|
||||
def self.[](name) |
||||
self.where(name: name).order(date: :desc).limit(1).first |
||||
end |
||||
end |
@ -0,0 +1,164 @@ |
||||
<% colors = { |
||||
"A+" => 'great', |
||||
"good" => 'great', |
||||
"A" => 'great', |
||||
"B+" => 'best', |
||||
"B" => 'best', |
||||
"C+" => 'good', |
||||
"C" => 'good', |
||||
"D" => 'effort', |
||||
"E" => 'warning', |
||||
"F" => 'error', |
||||
"G" => 'critical', |
||||
"bad" => 'critical', |
||||
"ssl" => 'critical', |
||||
"tls" => 'error', |
||||
"tls1_2" => 'effort', |
||||
"tls1_2_only" => 'great' |
||||
} %> |
||||
|
||||
<ul class="nav nav-pills nav-fill" id="pills-tab" role="Navigation stats list"> |
||||
<% %i[https smtp tls xmpp].each do |service| %> |
||||
<li class="nav-item" role="presentation"> |
||||
<button class="nav-link<%= " active btn-dark" if service.to_s == "https" %>" |
||||
id="nav-<%= service %>-pill" data-bs-toggle="pill" |
||||
data-bs-target="#nav-<%= service %>" type="button" role="Button to show <%= service %> stats" aria-controls="nav-<%= service %>" aria-selected="true"> |
||||
<%= service.to_s.upcase %> |
||||
</button> |
||||
</li> |
||||
<% end %> |
||||
</ul> |
||||
|
||||
<div class="tab-content p-2 mb-4" id="nav-pillsContent"> |
||||
<% %i[https smtp tls xmpp].each do |service| %> |
||||
<div class="tab-pane fade show <%= "active" if service.to_s == "https" %>" |
||||
id="nav-<%= service %>" role="<%= service.to_s %>> stats" |
||||
aria-labelledby="nav-<%= service %>-pill"> |
||||
<h2>Grades for service <%= service.to_s.upcase %></h2> |
||||
|
||||
<% |
||||
grades = Stat["grades_for_#{service}"] |
||||
total = grades.data.collect { _2 }.sum |
||||
%> |
||||
|
||||
<p>Over <%= total %> URL tested with a grade.</p> |
||||
|
||||
<table class="table table-bordered table-striped"> |
||||
<thead class="bg-dark text-light"> |
||||
<tr> |
||||
<th>Grade</th> |
||||
<th>Percent</th> |
||||
<th>Number</th> |
||||
<th>Visual</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<% sorted_grades = grades.data.keys.sort &CryptCheck::Grade.method(:compare) |
||||
sorted_grades.each do |grade| |
||||
unless %w(T V).include?(grade) |
||||
number = grades.data[grade].to_i |
||||
percent = (number.to_f / total.to_f) * 100.0 |
||||
color = CryptCheck::Grade::GRADE_STATUS.fetch grade.to_sym %> |
||||
<tr> |
||||
<td><%= grade %></td> |
||||
<td><%= percent.round %>%</td> |
||||
<td><%= number %></td> |
||||
<td> |
||||
<div class="progress bg-light"> |
||||
<div class="progress-bar progress-<%= color %> border-dark" |
||||
style="width: <%= percent.round %>%" role="progressbar" |
||||
aria-valuenow="<%= percent.round %>" aria-valuemin="0" |
||||
aria-valuemax="100"></div> |
||||
</div> |
||||
</td> |
||||
</tr> |
||||
<% end |
||||
end %> |
||||
</tbody> |
||||
</table> |
||||
|
||||
<h2>Ciphers for service <%= service.to_s.upcase %></h2> |
||||
|
||||
<% |
||||
ciphers = Stat["ciphers_for_#{service}"] |
||||
total = ciphers.data.collect { _2 }.sum |
||||
%> |
||||
<p>Over <%= total %> URL tested with a cipher.</p> |
||||
|
||||
<table class="table table-bordered table-striped"> |
||||
<thead class="bg-dark text-light"> |
||||
<tr> |
||||
<th>Grade</th> |
||||
<th>Percent</th> |
||||
<th>Number</th> |
||||
<th>Visual</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<% sorted_grades = ciphers.data.keys.sort &CryptCheck::Grade.method(:compare) |
||||
sorted_grades.each do |grade| |
||||
number = ciphers.data[grade] |
||||
percent = (number.to_f / total.to_f) * 100.0 |
||||
color = colors[grade] |
||||
%> |
||||
<tr> |
||||
<td><%= grade.capitalize %></td> |
||||
<td><%= percent.round %>%</td> |
||||
<td><%= number %></td> |
||||
<td> |
||||
<div class="progress bg-light"> |
||||
<div class="progress-bar progress-<%= color %>" |
||||
style="width: <%= percent.round %>%" role="progressbar" |
||||
aria-valuenow="<%= percent.round %>" aria-valuemin="0" |
||||
aria-valuemax="100"></div> |
||||
</div> |
||||
</td> |
||||
</tr> |
||||
<% end %> |
||||
</tbody> |
||||
</table> |
||||
|
||||
<h2>TLS for service <%= service.to_s.upcase %></h2> |
||||
|
||||
<% tls = Stat["tls_for_#{service}"] |
||||
total = tls.data.collect { _2 }.sum |
||||
%> |
||||
<p>Over <%= total %> URL tested with TLS.</p> |
||||
|
||||
<table class="table table-bordered table-striped"> |
||||
<thead class="bg-dark text-light"> |
||||
<tr> |
||||
<th>Grade</th> |
||||
<th>Percent</th> |
||||
<th>Number</th> |
||||
<th>Visual</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<% |
||||
sorted_grades = tls.data.keys.sort &CryptCheck::Grade.method(:compare) |
||||
sorted_grades.each do |grade| |
||||
number = tls.data[grade] |
||||
percent = (number.to_f / total.to_f) * 100.0 |
||||
color = colors[grade] |
||||
%> |
||||
<tr> |
||||
<td><%= grade.capitalize %></td> |
||||
<td><%= percent.round %>%</td> |
||||
<td><%= number %></td> |
||||
<td> |
||||
<div class="progress bg-light"> |
||||
<div class="progress-bar progress-<%= color %>" |
||||
style="width: <%= percent.round %>%" role="progressbar" |
||||
aria-valuenow="<%= percent.round %>" aria-valuemin="0" |
||||
aria-valuemax="100"></div> |
||||
</div> |
||||
</td> |
||||
</tr> |
||||
<% end %> |
||||
</tbody> |
||||
</table> |
||||
|
||||
</div> |
||||
<% end %> |
||||
</div> |
@ -0,0 +1,167 @@ |
||||
<% colors = { |
||||
"A+" => 'great', |
||||
"good" => 'great', |
||||
"A" => 'great', |
||||
"B+" => 'best', |
||||
"B" => 'best', |
||||
"C+" => 'good', |
||||
"C" => 'good', |
||||
"D" => 'effort', |
||||
"E" => 'warning', |
||||
"F" => 'error', |
||||
"G" => 'critical', |
||||
"bad" => 'critical', |
||||
"ssl" => 'critical', |
||||
"tls" => 'error', |
||||
"tls1_2" => 'effort', |
||||
"tls1_2_only" => 'great' |
||||
} %> |
||||
|
||||
<ul class="nav nav-pills nav-fill" id="pills-tab" role="Navigation stats list"> |
||||
<% %i[https smtp tls xmpp].each do |service| %> |
||||
<li class="nav-item" role="presentation"> |
||||
<button class="nav-link<%= " active btn-dark" if service.to_s == "https" %>" |
||||
id="nav-<%= service %>-pill" data-bs-toggle="pill" |
||||
data-bs-target="#nav-<%= service %>" type="button" role="Button to show <%= service %> stats" aria-controls="nav-<%= service %>" aria-selected="true"> |
||||
<%= service.to_s.upcase %> |
||||
</button> |
||||
</li> |
||||
<% end %> |
||||
</ul> |
||||
|
||||
<div class="tab-content p-2 mb-4" id="nav-pillsContent"> |
||||
<% %i[https smtp tls xmpp].each do |service| %> |
||||
<div class="tab-pane fade show <%= "active" if service.to_s == "https" %>" |
||||
id="nav-<%= service %>" role="<%= service.to_s %>> stats" |
||||
aria-labelledby="nav-<%= service %>-pill"> |
||||
<h2>Grades for service <%= service.to_s.upcase %></h2> |
||||
|
||||
<% |
||||
grades = Stat["grades_for_#{service}"] |
||||
total = grades.data.collect { _2 }.sum |
||||
%> |
||||
|
||||
<p>Over <%= total %> URL tested with a grade.</p> |
||||
|
||||
<table class="table table-bordered table-striped"> |
||||
<thead class="bg-dark text-light"> |
||||
<tr> |
||||
<th>Grade</th> |
||||
<th>Count</th> |
||||
<th></th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<% sorted_grades = grades.data.keys.sort &CryptCheck::Grade.method(:compare) |
||||
sorted_grades.each do |grade| |
||||
unless %w(T V).include?(grade) |
||||
count = grades.data[grade].to_i |
||||
percent = (count.to_f / total.to_f) * 100.0 |
||||
color = CryptCheck::Grade::GRADE_STATUS.fetch grade.to_sym %> |
||||
<tr> |
||||
<td class="col-4"><%= grade.capitalize %></td> |
||||
<td class="col-4"><%= count %> |
||||
(<%= percent.round %>%) |
||||
</td> |
||||
<td class="col-4"> |
||||
<div class="progress bg-light"> |
||||
<div class="progress-bar progress-<%= color %> border-dark" |
||||
style="width: <%= percent.round %>%" role="progressbar" |
||||
aria-valuenow="<%= percent.round %>" aria-valuemin="0" |
||||
aria-valuemax="100"></div> |
||||
</div> |
||||
</td> |
||||
</tr> |
||||
<% end |
||||
end %> |
||||
</tbody> |
||||
</table> |
||||
|
||||
<h2>Ciphers for service <%= service.to_s.upcase %></h2> |
||||
|
||||
<% |
||||
name = "ciphers_for_#{service}" |
||||
ciphers = Stat[name] |
||||
total = ciphers.data.collect { _2 }.sum |
||||
%> |
||||
<p>Over <%= total %> URL tested with a cipher.</p> |
||||
|
||||
<table class="table table-bordered table-striped"> |
||||
<thead class="bg-dark text-light"> |
||||
<tr> |
||||
<%= content_tag :th, t(:'.ciphers.title') %> |
||||
<th>Count</th> |
||||
<th></th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<% |
||||
ciphers = ciphers.data |
||||
%w[good bad].each do |grade| |
||||
count = ciphers.fetch grade |
||||
percent = (count.to_f / total.to_f) * 100.0 |
||||
color = colors[grade] |
||||
%> |
||||
<tr> |
||||
<td class="col-4"><%= t ".ciphers.#{grade}" %></td> |
||||
<td class="col-4"><%= count %> (<%= percent.round %> |
||||
%) |
||||
</td> |
||||
<td class="col-4"> |
||||
<div class="progress bg-light"> |
||||
<div class="progress-bar progress-<%= color %>" |
||||
style="width: <%= percent.round %>%" role="progressbar" |
||||
aria-valuenow="<%= percent.round %>" aria-valuemin="0" |
||||
aria-valuemax="100"></div> |
||||
</div> |
||||
</td> |
||||
</tr> |
||||
<% end %> |
||||
</tbody> |
||||
</table> |
||||
|
||||
<h2>TLS for service <%= service.to_s.upcase %></h2> |
||||
|
||||
<% |
||||
name = "tls_for_#{service}" |
||||
tls = Stat[name] |
||||
total = tls.data.collect { _2 }.sum |
||||
%> |
||||
<p>Over <%= total %> URL tested with TLS.</p> |
||||
|
||||
<table class="table table-bordered table-striped"> |
||||
<thead class="bg-dark text-light"> |
||||
<tr> |
||||
<%= content_tag :th, t(:'.tls.title') %> |
||||
<th>Count</th> |
||||
<th></th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<% |
||||
tls = tls.data |
||||
%w[tls1_2_only tls1_2 tls ssl].each do |grade| |
||||
count = tls.fetch grade |
||||
percent = (count.to_f / total.to_f) * 100.0 |
||||
color = colors[grade] |
||||
%> |
||||
<tr> |
||||
<td class="col-4"><%= t ".tls.#{grade}" %></td> |
||||
<td class="col-4"><%= count %> (<%= percent.round %> |
||||
%) |
||||
</td> |
||||
<td class="col-4"> |
||||
<div class="progress bg-light"> |
||||
<div class="progress-bar progress-<%= color %>" |
||||
style="width: <%= percent.round %>%" role="progressbar" |
||||
aria-valuenow="<%= percent.round %>" aria-valuemin="0" |
||||
aria-valuemax="100"></div> |
||||
</div> |
||||
</td> |
||||
</tr> |
||||
<% end %> |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
<% end %> |
||||
</div> |
@ -0,0 +1,29 @@ |
||||
#!/usr/bin/env ruby |
||||
# frozen_string_literal: true |
||||
|
||||
# |
||||
# This file was generated by Bundler. |
||||
# |
||||
# The application 'rspec' is installed as part of a gem, and |
||||
# this file is here to facilitate running it. |
||||
# |
||||
|
||||
require "pathname" |
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", |
||||
Pathname.new(__FILE__).realpath) |
||||
|
||||
bundle_binstub = File.expand_path("../bundle", __FILE__) |
||||
|
||||
if File.file?(bundle_binstub) |
||||
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ |
||||
load(bundle_binstub) |
||||
else |
||||
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. |
||||
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") |
||||
end |
||||
end |
||||
|
||||
require "rubygems" |
||||
require "bundler/setup" |
||||
|
||||
load Gem.bin_path("rspec-core", "rspec") |
@ -0,0 +1,116 @@ |
||||
#!./bin/rails runner |
||||
|
||||
# Profit from open class to add stats methods only on this script |
||||
class Analysis |
||||
def grade |
||||
grades = self.result.collect { _1['grade'] }.compact |
||||
CryptCheck::Grade.worst grades |
||||
end |
||||
|
||||
def tls |
||||
return unless (result = self.result) |
||||
protocols = result.collect { |r| r.dig('handshakes', 'protocols') |
||||
&.collect { |p| p['protocol'].to_sym } } |
||||
.compact.flatten.uniq |
||||
|
||||
return :ssl unless (protocols & %i[SSLv2 SSLv3]).empty? |
||||
return :tls unless protocols.include? :TLSv1_2 |
||||
return :tls1_2_only if protocols == %i[TLSv1_2] |
||||
:tls1_2 |
||||
end |
||||
|
||||
def ciphers |
||||
return unless (result = self.result) |
||||
status = result.collect do |r| |
||||
r.dig('handshakes', 'ciphers')&.collect do |c| |
||||
s = CryptCheck::Tls::Cipher |
||||
.new(nil, c.fetch('name')).status |
||||
CryptCheck::State.good_or_bad s |
||||
end |
||||
end.compact.flatten.uniq |
||||
|
||||
return :bad if status.include? :bad |
||||
:good |
||||
end |
||||
|
||||
def pfs |
||||
return unless (result = self.result) |
||||
ciphers = result.collect do |r| |
||||
r.dig('handshakes', 'ciphers')&.collect do |c| |
||||
CryptCheck::Tls::Cipher |
||||
.new(nil, c.fetch('name')) |
||||
.pfs? |
||||
end |
||||
end.compact.flatten.uniq |
||||
|
||||
return :no_pfs unless ciphers.include? true |
||||
return :pfs_only unless ciphers.include? false |
||||
:pfs |
||||
end |
||||
end |
||||
|
||||
sites = YAML.load_file Rails.root.join 'config/sites.yml' |
||||
|
||||
workflows = [] |
||||
sites.each do |type, domains| |
||||
domains.each do |domain| |
||||
puts "Refreshing #{domain}" |
||||
@analysis = Analysis.pending! :https, domain, 443 |
||||
workflows << CheckWorkflow.start!(:https, @analysis.host, *@analysis.args) |
||||
end |
||||
end |
||||
workflows.each &:wait |
||||
|
||||
sites.each do |type, domains| |
||||
domains = domains.collect do |domain| |
||||
analysis = Analysis[:https, domain, 443] |
||||
stats = { |
||||
grade: analysis.grade, |
||||
tls: analysis.tls, |
||||
ciphers: analysis.ciphers, |
||||
pfs: analysis.pfs |
||||
} |
||||
[domain, stats] |
||||
end.to_h |
||||
|
||||
Stat.create! :"sites_#{type}", domains |
||||
end |
||||
|
||||
# general stat |
||||
services = Analysis.group(:service).order(service: :asc).count |
||||
Stat.create! :request_per_service, { labels: services.keys, dataset: services.values } |
||||
|
||||
# grade per service for https, smtp, tls and xmpp |
||||
%i[https smtp tls xmpp].each do |service_name| |
||||
services = Analysis.where service: service_name, pending: false |
||||
|
||||
services.each do |service| |
||||
if (g = service.grade) |
||||
grades[g] += 1 |
||||
end |
||||
|
||||
if (t = service.tls) |
||||
tls[t] += 1 |
||||
end |
||||
|
||||
if (c = service.ciphers) |
||||
ciphers[c] += 1 |
||||
end |
||||
|
||||
if (p = service.pfs) |
||||
pfs[p] += 1 |
||||
end |
||||
end |
||||
|
||||
ap "grades_for_#{service}" => grades |
||||
Stat.create! "grades_for_#{service}", grades |
||||
|
||||
ap "tls_for_#{service}" => tls |
||||
Stat.create! "tls_for_#{service}", tls |
||||
|
||||
ap "ciphers_for_#{service}" => ciphers |
||||
Stat.create! "ciphers_for_#{service}", ciphers |
||||
|
||||
ap "pfs_for_#{service}" => pfs |
||||
Stat.create! "pfs_for_#{service}", pfs |
||||
end |
@ -1 +0,0 @@ |
||||
require 'matomo' |
@ -0,0 +1,67 @@ |
||||
banks: |
||||
- admin.vybecard.com |
||||
- app.n26.com |
||||
- app.nickel.eu |
||||
- app.qonto.com |
||||
- clients.boursorama.com |
||||
- clients.cmavignon.com |
||||
- connexion-mabanque.bnpparibas |
||||
- ebanking-ch3.ubs.com |
||||
- epargnants.interepargne.natixis.fr |
||||
- espace-client.hellobank.fr |
||||
- espace-client.lanef.com |
||||
- espaceclient.axa.fr |
||||
- linxea-zen.avepargne.fr |
||||
- m.ing.fr |
||||
- mabanque.bnpparibas |
||||
- mabanque.fortuneo.fr |
||||
- mon.cmb.fr |
||||
- monespace.lcl.fr |
||||
- particuliers.societegenerale.fr |
||||
- secure.bforbank.com |
||||
- transatplan.banquetransatlantique.com |
||||
- voscomptesenligne.labanquepostale.fr |
||||
- www.altaprofits.com |
||||
- www.aviva.fr |
||||
- www.banque-rhone-alpes.fr |
||||
- www.banquepopulaire.fr |
||||
- www.bred.fr |
||||
- www.caisse-epargne.fr |
||||
- www.cic.fr |
||||
- www.credit-agricole.fr |
||||
- www.credit-cooperatif.coop |
||||
- www.creditmutuel.fr |
||||
- www.hsbc.fr |
||||
- www.ibps.sud.banquepopulaire.fr |
||||
- www.icgauth.banquebcp.fr |
||||
- www.labanquepostale.fr |
||||
- www.mgen.fr |
||||
- www.monabanq.com |
||||
- www.previ-direct.com |
||||
insurances: |
||||
- adherent.gie-afer.fr |
||||
- authentification.groupama.fr |
||||
- connect.axa.fr |
||||
- connect.maif.fr |
||||
- connect.sogarep.fr |
||||
- epargnant.amundi-ee.com |
||||
- espace-assure.gmf.fr |
||||
- espace-client.allianz.fr |
||||
- espace-client.mma.fr |
||||
- espace-personnel.direct-assurance.fr |
||||
- espaceperso.mutuelledesmotards.fr |
||||
- harmonie-et-moi.fr |
||||
- myswisslife.fr |