osa 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/lib/osa/scripts/dashboard_server.rb +9 -1
- data/lib/osa/scripts/scan_junk_folder.rb +14 -1
- data/lib/osa/util/db.rb +1 -1
- data/lib/osa/version.rb +1 -1
- data/lib/osa/views/index.erb +31 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3bc9c2b204260bd0cecd1650fdbfca0676c53e6e44c59aef8926caf9a5f0246
|
4
|
+
data.tar.gz: f32d6566bc6195847fc12fe680f8c22e6cbfe91f587bc7a35937efb1582eaccc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76462c72b811ecb6b2224725ec954aa3ff3c6d2fc99a4cc91ae66698d72de709c740683ce6c4690095853199c7ef67c836ddc0bf6c0d3c4eb33751ee0fec3058
|
7
|
+
data.tar.gz: f4e79f61caa68f2c1ecd646ffa3d127070addf334f827bb33066bfdefc1e44f8b2986b6983c120c94867fa907e65184fd679ef73ad0eaa6b1b34f49956d5393d
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
osa (0.2.
|
4
|
+
osa (0.2.2)
|
5
5
|
activerecord (~> 6.0)
|
6
6
|
faraday (~> 1.1)
|
7
7
|
mail (~> 2.7.1)
|
@@ -37,7 +37,7 @@ GEM
|
|
37
37
|
mail (2.7.1)
|
38
38
|
mini_mime (>= 0.1.1)
|
39
39
|
mini_mime (1.0.2)
|
40
|
-
minitest (5.14.
|
40
|
+
minitest (5.14.4)
|
41
41
|
multi_json (1.15.0)
|
42
42
|
multipart-post (2.1.1)
|
43
43
|
mustermann (1.1.1)
|
@@ -6,6 +6,7 @@ require 'osa/util/db'
|
|
6
6
|
class DashboardServer < Sinatra::Base
|
7
7
|
set :views, File.absolute_path(File.dirname(__FILE__) + '/../views')
|
8
8
|
set :port, ENV['SERVER_PORT'] || 8080
|
9
|
+
after { ActiveRecord::Base.connection.close }
|
9
10
|
|
10
11
|
get '/' do
|
11
12
|
erb :index
|
@@ -54,7 +55,11 @@ class DashboardServer < Sinatra::Base
|
|
54
55
|
end
|
55
56
|
|
56
57
|
get '/api/stats/spammers' do
|
57
|
-
spammers = OSA::Report.select('sender_domain as domain', 'COUNT(*) as count')
|
58
|
+
spammers = OSA::Report.select('sender_domain as domain', 'COUNT(*) as count')
|
59
|
+
unless params[:interval].blank?
|
60
|
+
spammers = spammers.where('received_at > ?', Time.now - params[:interval].to_i.days)
|
61
|
+
end
|
62
|
+
spammers = spammers.limit(50).order(count: :desc).group(:sender_domain)
|
58
63
|
json spammers
|
59
64
|
end
|
60
65
|
|
@@ -63,6 +68,9 @@ class DashboardServer < Sinatra::Base
|
|
63
68
|
unless params[:spammer].blank?
|
64
69
|
historical_data = historical_data.where(sender: params[:spammer]).or(OSA::Report.where(sender_domain: params[:spammer]))
|
65
70
|
end
|
71
|
+
unless params[:interval].blank?
|
72
|
+
historical_data = historical_data.where('received_at > ?', Time.now - params[:interval].to_i.days)
|
73
|
+
end
|
66
74
|
json historical_data.group(:date)
|
67
75
|
end
|
68
76
|
end
|
@@ -21,13 +21,26 @@ def resolve_blacklist(mail_id, email_address, domain, context, dns_blacklists)
|
|
21
21
|
dns_blacklists.find { |bl| bl.blacklisted?(ip) }&.server
|
22
22
|
end
|
23
23
|
|
24
|
+
def extract_email_address(mail)
|
25
|
+
email_address = mail['sender']['emailAddress']['address']
|
26
|
+
return email_address unless email_address.nil?
|
27
|
+
|
28
|
+
# Sometimes the SMTP From header is misformatted and the email address is
|
29
|
+
# parsed as part of the name by Outlook. Try to extract the email address
|
30
|
+
# from the name.
|
31
|
+
sender_name = mail['sender']['emailAddress']['name']
|
32
|
+
return nil if sender_name.nil?
|
33
|
+
|
34
|
+
sender_name.scan(/<(.+@.+)>/).first&.first
|
35
|
+
end
|
36
|
+
|
24
37
|
while continue
|
25
38
|
mails = context.graph_client.mails(context.config.junk_folder_id)
|
26
39
|
continue = false
|
27
40
|
loop do
|
28
41
|
break if mails.nil?
|
29
42
|
mails['value'].each do |mail|
|
30
|
-
email_address = mail
|
43
|
+
email_address = extract_email_address(mail)
|
31
44
|
next if email_address.nil?
|
32
45
|
domain = PublicSuffix.domain(email_address.split('@', 2)[1])
|
33
46
|
|
data/lib/osa/util/db.rb
CHANGED
data/lib/osa/version.rb
CHANGED
data/lib/osa/views/index.erb
CHANGED
@@ -77,6 +77,15 @@
|
|
77
77
|
<!-- ./col -->
|
78
78
|
</div>
|
79
79
|
|
80
|
+
<div class="row">
|
81
|
+
<div id="interval-btn-group" class="btn-group">
|
82
|
+
<button onclick="updateInterval(this, '')" type="button" class="btn btn-info active">All time</button>
|
83
|
+
<button onclick="updateInterval(this, '1')" type="button" class="btn btn-info">1 day</button>
|
84
|
+
<button onclick="updateInterval(this, '7')" type="button" class="btn btn-info">7 days</button>
|
85
|
+
<button onclick="updateInterval(this, '30')" type="button" class="btn btn-info">30 days</button>
|
86
|
+
</div>
|
87
|
+
</div>
|
88
|
+
|
80
89
|
<div class="row">
|
81
90
|
<div class="card">
|
82
91
|
<div class="card-header">
|
@@ -136,6 +145,21 @@
|
|
136
145
|
|
137
146
|
<script>
|
138
147
|
let totalReportCount = 0;
|
148
|
+
let interval = "";
|
149
|
+
|
150
|
+
function updateInterval(element, newInterval) {
|
151
|
+
interval = newInterval;
|
152
|
+
let children = Array.from(document.getElementById("interval-btn-group").children);
|
153
|
+
console.log(children);
|
154
|
+
children.forEach((child) => {
|
155
|
+
if (child === element) {
|
156
|
+
child.classList.add("active");
|
157
|
+
} else {
|
158
|
+
child.classList.remove("active");
|
159
|
+
}
|
160
|
+
});
|
161
|
+
update();
|
162
|
+
}
|
139
163
|
|
140
164
|
function sec2time(timeInSeconds) {
|
141
165
|
const time = parseFloat(timeInSeconds).toFixed(3);
|
@@ -179,7 +203,7 @@
|
|
179
203
|
}
|
180
204
|
|
181
205
|
async function updateSpammers() {
|
182
|
-
const response = await fetch(
|
206
|
+
const response = await fetch(`/api/stats/spammers?interval=${interval}`);
|
183
207
|
if (response.ok) {
|
184
208
|
const body = await response.json();
|
185
209
|
|
@@ -270,7 +294,7 @@
|
|
270
294
|
const historicalChart = createHistoricalChart();
|
271
295
|
|
272
296
|
async function updateHistoricalChart() {
|
273
|
-
const response = await fetch(
|
297
|
+
const response = await fetch(`/api/stats/reports/historical?interval=${interval}`);
|
274
298
|
if (response.ok) {
|
275
299
|
const body = await response.json();
|
276
300
|
|
@@ -285,11 +309,11 @@
|
|
285
309
|
|
286
310
|
function update() {
|
287
311
|
updateStats()
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
312
|
+
.then(updateSpammers)
|
313
|
+
.then(updateHistoricalChart)
|
314
|
+
.then(() => {
|
315
|
+
setTimeout(update, 10 * 60 * 1000);
|
316
|
+
})
|
293
317
|
}
|
294
318
|
|
295
319
|
update();
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: osa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moray Baruh
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|