repsheet_visualizer 0.1.0 → 0.1.1
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.
- data/lib/repsheet_visualizer/application/app.rb +28 -11
- data/lib/repsheet_visualizer/application/public/javascripts/application.js +8 -4
- data/lib/repsheet_visualizer/application/views/activity.erb +28 -16
- data/lib/repsheet_visualizer/application/views/actors.erb +115 -34
- data/lib/repsheet_visualizer/version.rb +1 -1
- data/script/fill +26 -0
- metadata +3 -2
|
@@ -10,8 +10,11 @@ class RepsheetVisualizer < Sinatra::Base
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
helpers do
|
|
13
|
-
def action(
|
|
14
|
-
|
|
13
|
+
def action(ip, blacklist=nil)
|
|
14
|
+
puts ip.inspect
|
|
15
|
+
puts blacklist.inspect
|
|
16
|
+
blacklist = redis_connection.get("#{ip}:repsheet:blacklist") if blacklist.nil?
|
|
17
|
+
if blacklist.nil? || blacklist == "false"
|
|
15
18
|
"blacklist"
|
|
16
19
|
else
|
|
17
20
|
"allow"
|
|
@@ -39,17 +42,31 @@ class RepsheetVisualizer < Sinatra::Base
|
|
|
39
42
|
|
|
40
43
|
# TODO: These methods should get moved out to another place
|
|
41
44
|
def summary(connection)
|
|
42
|
-
|
|
45
|
+
suspects = {}
|
|
46
|
+
blacklisted = {}
|
|
47
|
+
|
|
43
48
|
connection.keys("*:requests").map {|d| d.split(":").first}.reject {|ip| ip.empty?}.each do |actor|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
detected = connection.smembers("#{actor}:detected").join(", ")
|
|
50
|
+
blacklist = connection.get("#{actor}:repsheet:blacklist")
|
|
51
|
+
|
|
52
|
+
if !detected.empty? && blacklist != "true"
|
|
53
|
+
suspects[actor] = Hash.new 0
|
|
54
|
+
suspects[actor][:detected] = detected
|
|
55
|
+
connection.smembers("#{actor}:detected").each do |rule|
|
|
56
|
+
suspects[actor][:total] += connection.get("#{actor}:#{rule}:count").to_i
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
if blacklist == "true"
|
|
61
|
+
blacklisted[actor] = Hash.new 0
|
|
62
|
+
blacklisted[actor][:detected] = detected
|
|
63
|
+
connection.smembers("#{actor}:detected").each do |rule|
|
|
64
|
+
blacklisted[actor][:total] += connection.get("#{actor}:#{rule}:count").to_i
|
|
65
|
+
end
|
|
50
66
|
end
|
|
51
67
|
end
|
|
52
|
-
|
|
68
|
+
|
|
69
|
+
[suspects.sort_by{|k,v| -v[:total]}.take(10), blacklisted]
|
|
53
70
|
end
|
|
54
71
|
|
|
55
72
|
def breakdown(connection)
|
|
@@ -83,7 +100,7 @@ class RepsheetVisualizer < Sinatra::Base
|
|
|
83
100
|
|
|
84
101
|
# This is the actual application
|
|
85
102
|
get '/' do
|
|
86
|
-
@
|
|
103
|
+
@suspects, @blacklisted = summary(redis_connection)
|
|
87
104
|
erb :actors
|
|
88
105
|
end
|
|
89
106
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
$(document).ready(function() {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
$("#
|
|
2
|
+
$("#suspects").tablesorter({sortList: [[2,1]],widgets: ['zebra']});
|
|
3
|
+
$("#blacklisted").tablesorter({sortList: [[2,1]],widgets: ['zebra']});
|
|
4
|
+
|
|
5
|
+
$("#search-button").click(function() {
|
|
6
|
+
ip = $("#ip").val();
|
|
7
|
+
if (ip === "") return;
|
|
8
|
+
window.location = "activity/" + ip;
|
|
9
|
+
});
|
|
6
10
|
});
|
|
7
11
|
|
|
8
12
|
function angle(d) {
|
|
@@ -10,19 +10,20 @@
|
|
|
10
10
|
<link href="<%= @mount %>css/bootstrap.css" rel="stylesheet">
|
|
11
11
|
<style>
|
|
12
12
|
body {
|
|
13
|
-
|
|
13
|
+
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
|
14
14
|
}
|
|
15
15
|
</style>
|
|
16
16
|
<link href="<%= @mount %>css/bootstrap-responsive.css" rel="stylesheet">
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
|
|
19
19
|
<!--[if lt IE 9]>
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
<script src="<%= @mount %>javascripts/html5shiv.js"></script>
|
|
21
|
+
<![endif]-->
|
|
22
22
|
|
|
23
23
|
<link rel="shortcut icon" href="/<%= @mount %>/images/favicon.ico">
|
|
24
24
|
|
|
25
|
-
<script src="<%= @mount %>javascripts/
|
|
25
|
+
<script src="<%= @mount %>javascripts/jquery-latest.js" type="text/javascript"></script>
|
|
26
|
+
<script src="<%= @mount %>javascripts/jquery.tablesorter.min.js" type="text/javascript"></script>
|
|
26
27
|
<script src="<%= @mount %>javascripts/application.js" type="text/javascript"></script>
|
|
27
28
|
</head>
|
|
28
29
|
|
|
@@ -31,24 +32,35 @@
|
|
|
31
32
|
<div class="navbar-inner">
|
|
32
33
|
<div class="container">
|
|
33
34
|
<a class="brand" href="<%= @mount %>">Repsheet</a>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
<div class="nav-collapse collapse">
|
|
36
|
+
<ul class="nav">
|
|
37
|
+
<li><a href="<%= @mount %>">Actors</a></li>
|
|
38
|
+
<li><a href="<%= @mount %>breakdown">Breakdown</a></li>
|
|
39
|
+
<li><a href="<%= @mount %>worldview">Worldview</a></li>
|
|
40
|
+
</ul>
|
|
41
|
+
</div>
|
|
41
42
|
</div>
|
|
42
43
|
</div>
|
|
43
44
|
</div>
|
|
44
45
|
|
|
45
46
|
<div class="container">
|
|
46
47
|
<h2>Activity for <%= @ip %></h2>
|
|
47
|
-
<
|
|
48
|
+
<form method="post" action="<%= @mount %>action" class="button_to">
|
|
49
|
+
<div>
|
|
50
|
+
<input value="<%= action(@ip) %>" type="submit" />
|
|
51
|
+
<input type="hidden" name="ip" value="<%= @ip %>"/>
|
|
52
|
+
<input type="hidden" name="action" value="<%= action(@ip) %>"/>
|
|
53
|
+
</div>
|
|
54
|
+
</form>
|
|
55
|
+
|
|
56
|
+
<div>
|
|
57
|
+
<a href="<%= @mount %>">Back</a>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
48
60
|
<ul>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
<% @data.each do |action| %>
|
|
62
|
+
<li><%= action %></li>
|
|
63
|
+
<% end %>
|
|
52
64
|
</ul>
|
|
53
65
|
</div>
|
|
54
66
|
</body>
|
|
@@ -15,9 +15,45 @@
|
|
|
15
15
|
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
#search {
|
|
19
|
+
padding-bottom: 20px;
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
.actors {
|
|
19
23
|
border-color: #FFF;
|
|
20
24
|
}
|
|
25
|
+
|
|
26
|
+
#suspects-wrapper {
|
|
27
|
+
float: left;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#suspects-table-wrapper {
|
|
31
|
+
overflow: auto;
|
|
32
|
+
max-height: 800px;
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#suspects {
|
|
37
|
+
width: 550px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#blacklisted-wrapper {
|
|
41
|
+
float: right;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#blacklisted-table-wrapper {
|
|
45
|
+
overflow: auto;
|
|
46
|
+
max-height: 570px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#blacklisted {
|
|
50
|
+
width: 550px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.clearfix {
|
|
54
|
+
display: inline-block;
|
|
55
|
+
clear: both;
|
|
56
|
+
}
|
|
21
57
|
</style>
|
|
22
58
|
|
|
23
59
|
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
|
|
@@ -49,40 +85,85 @@
|
|
|
49
85
|
</div>
|
|
50
86
|
|
|
51
87
|
<div class="container">
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
<
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
<div id="search">
|
|
89
|
+
<label-for="ip"><b>Find Activity For an IP</b> </label>
|
|
90
|
+
<input name="ip" id="ip" type="text-field"/>
|
|
91
|
+
<input type="submit" id="search-button" value="Search"/>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div id="suspects-wrapper">
|
|
95
|
+
<h2>Top 10 Suspect Actors</h2>
|
|
96
|
+
<div id="suspects-table-wrapper">
|
|
97
|
+
<table id="suspects" class="tablesorter actors">
|
|
98
|
+
<thead>
|
|
99
|
+
<tr>
|
|
100
|
+
<th>IP</th>
|
|
101
|
+
<th>Triggered Rules</th>
|
|
102
|
+
<th>Offenses</th>
|
|
103
|
+
<th>Activity</th>
|
|
104
|
+
<th>Action</th>
|
|
105
|
+
</tr>
|
|
106
|
+
</thead>
|
|
107
|
+
<tbody>
|
|
108
|
+
<% @suspects.each do |actor,details| %>
|
|
109
|
+
<tr>
|
|
110
|
+
<td><%= actor %></td>
|
|
111
|
+
<td><%= details[:detected] %></td>
|
|
112
|
+
<td><%= details[:total] %></td>
|
|
113
|
+
<td width=100><a href="<%= @mount %>activity/<%= actor %>">Click to see activity</a>
|
|
114
|
+
<td width=90>
|
|
115
|
+
<form method="post" action="<%= @mount %>action" class="button_to">
|
|
116
|
+
<div>
|
|
117
|
+
<input value="<%= action(actor) %>" type="submit" />
|
|
118
|
+
<input type="hidden" name="ip" value="<%= actor %>"/>
|
|
119
|
+
<input type="hidden" name="action" value="<%= action(actor) %>"/>
|
|
120
|
+
</div>
|
|
121
|
+
</form>
|
|
122
|
+
</td>
|
|
123
|
+
</tr>
|
|
124
|
+
<% end %>
|
|
125
|
+
</tbody>
|
|
126
|
+
</table>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<div class="clearfix"></div>
|
|
131
|
+
|
|
132
|
+
<div id="blacklisted-wrapper">
|
|
133
|
+
<h2>Blacklisted Actors</h2>
|
|
134
|
+
<div id="blacklisted-table-wrapper">
|
|
135
|
+
<table id="blacklisted" class="tablesorter actors">
|
|
136
|
+
<thead>
|
|
137
|
+
<tr>
|
|
138
|
+
<th>IP</th>
|
|
139
|
+
<th>Triggered Rules</th>
|
|
140
|
+
<th>Offenses</th>
|
|
141
|
+
<th>Activity</th>
|
|
142
|
+
<th>Action</th>
|
|
143
|
+
</tr>
|
|
144
|
+
</thead>
|
|
145
|
+
<tbody>
|
|
146
|
+
<% @blacklisted.each do |actor,details| %>
|
|
147
|
+
<tr>
|
|
148
|
+
<td><%= actor %></td>
|
|
149
|
+
<td><%= details[:detected] %></td>
|
|
150
|
+
<td><%= details[:total] %></td>
|
|
151
|
+
<td width=100><a href="<%= @mount %>activity/<%= actor %>">Click to see activity</a>
|
|
152
|
+
<td width=70>
|
|
153
|
+
<form method="post" action="<%= @mount %>action" class="button_to">
|
|
154
|
+
<div>
|
|
155
|
+
<input value="<%= action(actor, details[:blacklist]) %>" type="submit" />
|
|
156
|
+
<input type="hidden" name="ip" value="<%= actor %>"/>
|
|
157
|
+
<input type="hidden" name="action" value="<%= action(actor, details[:blacklist]) %>"/>
|
|
158
|
+
</div>
|
|
159
|
+
</form>
|
|
160
|
+
</td>
|
|
161
|
+
</tr>
|
|
162
|
+
<% end %>
|
|
163
|
+
</tbody>
|
|
164
|
+
</table>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
86
167
|
</div>
|
|
87
168
|
</body>
|
|
88
169
|
</html>
|
data/script/fill
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'redis'
|
|
4
|
+
|
|
5
|
+
r = Redis.new
|
|
6
|
+
r.flushdb
|
|
7
|
+
|
|
8
|
+
255.times do |i|
|
|
9
|
+
r.set("1.1.1.#{i}:950001:count", rand(1000))
|
|
10
|
+
r.lpush("1.1.1.#{i}:requests", "request")
|
|
11
|
+
r.sadd("1.1.1.#{i}:detected", "950001")
|
|
12
|
+
if i > 220
|
|
13
|
+
r.set("1.1.1.#{i}:repsheet:blacklist", "true")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
255.times do |i|
|
|
18
|
+
r.lpush("2.2.2.#{i}:requests", "request")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
20.times do |i|
|
|
23
|
+
r.sadd("1.1.1.1:detected", "9900#{i + 10}")
|
|
24
|
+
r.set("1.1.1.1:9900#{i + 10}:count", 1000)
|
|
25
|
+
end
|
|
26
|
+
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: repsheet_visualizer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2013-06-
|
|
12
|
+
date: 2013-06-12 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: geoip
|
|
@@ -161,6 +161,7 @@ files:
|
|
|
161
161
|
- lib/repsheet_visualizer/application/views/worldview.erb
|
|
162
162
|
- lib/repsheet_visualizer/version.rb
|
|
163
163
|
- repsheet_visualizer.gemspec
|
|
164
|
+
- script/fill
|
|
164
165
|
homepage: https://github.com/Repsheet/visualizer
|
|
165
166
|
licenses:
|
|
166
167
|
- MIT
|