ssh_scan_api 0.0.1.pre2 → 0.0.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.
- checksums.yaml +5 -5
- data/.gitignore +7 -2
- data/.travis.yml +57 -10
- data/Gemfile +1 -2
- data/README.md +14 -16
- data/Rakefile +7 -1
- data/bin/ssh_scan_api +2 -12
- data/lib/ssh_scan_api.rb +6 -7
- data/lib/ssh_scan_api/api.rb +251 -186
- data/lib/ssh_scan_api/authenticator.rb +25 -19
- data/lib/ssh_scan_api/constants.rb +58 -0
- data/lib/ssh_scan_api/models/scan.rb +7 -0
- data/lib/ssh_scan_api/target_validator.rb +50 -0
- data/lib/ssh_scan_api/version.rb +3 -1
- data/ssh_scan_api.gemspec +8 -8
- metadata +38 -26
- data/lib/ssh_scan_api/database.rb +0 -61
- data/lib/ssh_scan_api/database/mongo.rb +0 -67
- data/lib/ssh_scan_api/database/sqlite.rb +0 -91
- data/lib/ssh_scan_api/job_queue.rb +0 -24
- data/lib/ssh_scan_api/stats.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 986e1fa32154fb3713c610f3339be18b71a9d4fa2306f7eebd7b427ebd0dc737
|
4
|
+
data.tar.gz: 785a82839c62ffe80e18576c6d0dbc47c1690c387f2f338ee32314b727cf8b02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bf3fe77b3a2b3f3e9e9c4a0ad33ff5480712926a44eb546026d0cc91bdfa52350817dc9c238f4c379d3cba0ecf9e07070d7837ada598d1b1c9a216ff4aec869
|
7
|
+
data.tar.gz: 61a0ec0dfd5ad4bee3d548aea9a061d67d09f6f03bf14a05f0e720dc9ef96cc5c897c2e08a35a690c5923ce8857d7081b28783330a8f9548fcff40891d4a50f8
|
data/.gitignore
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
*.db
|
3
3
|
/coverage/
|
4
4
|
|
5
|
+
config/api/config.yml
|
6
|
+
config/policies/mozilla_modern.yml
|
7
|
+
config/worker/config.yml
|
8
|
+
postgres-data/*
|
9
|
+
|
5
10
|
## Documentation cache and generated files:
|
6
11
|
/.yardoc/
|
7
12
|
/_yardoc/
|
@@ -16,8 +21,8 @@
|
|
16
21
|
# for a library or gem, you might want to ignore these files since the code is
|
17
22
|
# intended to run in multiple environments; otherwise, check them in:
|
18
23
|
Gemfile.lock
|
19
|
-
|
20
|
-
|
24
|
+
.ruby-version
|
25
|
+
.ruby-gemset
|
21
26
|
|
22
27
|
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
23
28
|
.rvmrc
|
data/.travis.yml
CHANGED
@@ -1,30 +1,77 @@
|
|
1
1
|
language: ruby
|
2
|
+
sudo: false
|
3
|
+
dist: trusty
|
4
|
+
before_install: gem update --system
|
5
|
+
addons:
|
6
|
+
postgresql: "9.6"
|
2
7
|
matrix:
|
3
8
|
include:
|
4
9
|
- rvm: ruby-head
|
5
10
|
env:
|
6
11
|
- LABEL=unit_tests
|
12
|
+
- SSHSCAN_API_HOST=127.0.0.1
|
13
|
+
- SSHSCAN_API_PORT=8000
|
14
|
+
- SSHSCAN_API_ALLOWED_PORTS=22
|
15
|
+
- SSHSCAN_API_AUTHENTICATION=false
|
16
|
+
- SSHSCAN_DATABASE_HOST=database
|
17
|
+
- SSHSCAN_DATABASE_NAME=ssh_observatory
|
18
|
+
- SSHSCAN_DATABASE_USERNAME=sshobs
|
7
19
|
services:
|
8
|
-
-
|
20
|
+
- postgres
|
21
|
+
before_script:
|
22
|
+
- chmod u+x database/init-user-db-travis.sh
|
23
|
+
- database/init-user-db-travis.sh
|
9
24
|
after_success:
|
10
25
|
- coveralls
|
11
|
-
- rvm: 2.
|
26
|
+
- rvm: 2.5.0
|
12
27
|
env:
|
13
28
|
- LABEL=unit_tests
|
29
|
+
- SSHSCAN_API_HOST=127.0.0.1
|
30
|
+
- SSHSCAN_API_PORT=8000
|
31
|
+
- SSHSCAN_API_ALLOWED_PORTS=22
|
32
|
+
- SSHSCAN_API_AUTHENTICATION=false
|
33
|
+
- SSHSCAN_DATABASE_HOST=database
|
34
|
+
- SSHSCAN_DATABASE_NAME=ssh_observatory
|
35
|
+
- SSHSCAN_DATABASE_USERNAME=sshobs
|
14
36
|
services:
|
15
|
-
-
|
16
|
-
|
37
|
+
- postgres
|
38
|
+
before_script:
|
39
|
+
- chmod u+x database/init-user-db-travis.sh
|
40
|
+
- database/init-user-db-travis.sh
|
41
|
+
- rvm: 2.3.6
|
17
42
|
env:
|
18
43
|
- LABEL=unit_tests
|
44
|
+
- SSHSCAN_API_HOST=127.0.0.1
|
45
|
+
- SSHSCAN_API_PORT=8000
|
46
|
+
- SSHSCAN_API_ALLOWED_PORTS=22
|
47
|
+
- SSHSCAN_API_AUTHENTICATION=false
|
48
|
+
- SSHSCAN_DATABASE_HOST=database
|
49
|
+
- SSHSCAN_DATABASE_NAME=ssh_observatory
|
50
|
+
- SSHSCAN_DATABASE_USERNAME=sshobs
|
19
51
|
services:
|
20
|
-
-
|
21
|
-
|
52
|
+
- postgres
|
53
|
+
before_script:
|
54
|
+
- chmod u+x database/init-user-db-travis.sh
|
55
|
+
- database/init-user-db-travis.sh
|
56
|
+
- rvm: 2.2.9
|
22
57
|
env:
|
58
|
+
- SSHSCAN_API_HOST=127.0.0.1
|
59
|
+
- SSHSCAN_API_PORT=8000
|
60
|
+
- SSHSCAN_API_ALLOWED_PORTS=22
|
61
|
+
- SSHSCAN_API_AUTHENTICATION=false
|
62
|
+
- SSHSCAN_DATABASE_HOST=database
|
63
|
+
- SSHSCAN_DATABASE_NAME=ssh_observatory
|
64
|
+
- SSHSCAN_DATABASE_USERNAME=sshobs
|
23
65
|
- LABEL=unit_tests
|
24
66
|
services:
|
25
|
-
-
|
26
|
-
|
67
|
+
- postgres
|
68
|
+
before_script:
|
69
|
+
- chmod u+x database/init-user-db-travis.sh
|
70
|
+
- database/init-user-db-travis.sh
|
71
|
+
- rvm: 2.5.0
|
27
72
|
env:
|
28
|
-
- LABEL=
|
73
|
+
- LABEL=docker_build_tests
|
29
74
|
services:
|
30
|
-
-
|
75
|
+
- docker
|
76
|
+
script:
|
77
|
+
- docker-compose build
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
# ssh_scan_api
|
2
2
|
|
3
|
+
[](http://travis-ci.org/mozilla/ssh_scan_api)
|
4
|
+
[](https://codeclimate.com/github/mozilla/ssh_scan_api)
|
5
|
+
[](https://badge.fury.io/rb/ssh_scan_api)
|
6
|
+
[](https://gitter.im/mozilla-ssh_scan/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
7
|
+
[](https://coveralls.io/github/mozilla/ssh_scan_api?branch=master)
|
8
|
+
|
3
9
|
A web api to scale ssh_scan operations
|
4
10
|
|
5
11
|
## Setup
|
6
12
|
|
7
|
-
To install and run as a gem, type:
|
8
|
-
|
9
|
-
```bash
|
10
|
-
gem install ssh_scan_api
|
11
|
-
ssh_scan_api
|
12
|
-
```
|
13
|
-
|
14
13
|
To install and run from source, type:
|
15
14
|
|
16
15
|
```bash
|
@@ -35,18 +34,17 @@ bundle install
|
|
35
34
|
./bin/ssh_scan_api
|
36
35
|
```
|
37
36
|
|
38
|
-
##
|
37
|
+
## ssh_scan as a command-line tool?
|
38
|
+
|
39
|
+
This project is focused on providing ssh_scan as a service/API.
|
39
40
|
|
40
|
-
|
41
|
+
If you would like to run ssh_scan from command-line, checkout the [ssh_scan](https://github.com/mozilla/ssh_scan) project.
|
42
|
+
|
43
|
+
## Rubies Supported
|
41
44
|
|
42
|
-
|
43
|
-
* [2.3.0](https://github.com/ruby/ruby/tree/ruby_2_1)
|
44
|
-
* [2.2.0](https://github.com/ruby/ruby/tree/ruby_2_1)
|
45
|
-
* [2.1.3](https://github.com/ruby/ruby/tree/ruby_2_1)
|
46
|
-
* [2.1.0](https://github.com/ruby/ruby/tree/ruby_2_1)
|
47
|
-
* [2.0.0](https://github.com/ruby/ruby/tree/ruby_2_0_0)
|
45
|
+
This project is integrated with [travis-ci](http://about.travis-ci.org/) and is regularly tested to work with multiple rubies.
|
48
46
|
|
49
|
-
To checkout the current build status for these rubies, click [here](https://travis-ci.org/#!/mozilla/
|
47
|
+
To checkout the current build status for these rubies, click [here](https://travis-ci.org/#!/mozilla/ssh_scan_api).
|
50
48
|
|
51
49
|
## Contributing
|
52
50
|
|
data/Rakefile
CHANGED
@@ -5,7 +5,13 @@ require 'rspec'
|
|
5
5
|
require 'rspec/core'
|
6
6
|
require 'rspec/core/rake_task'
|
7
7
|
require 'bundler/setup'
|
8
|
-
require
|
8
|
+
require "sinatra/activerecord/rake"
|
9
|
+
|
10
|
+
namespace :db do
|
11
|
+
task :load_config do
|
12
|
+
require "./lib/ssh_scan_api/api"
|
13
|
+
end
|
14
|
+
end
|
9
15
|
|
10
16
|
$:.unshift File.join(File.dirname(__FILE__), "lib")
|
11
17
|
|
data/bin/ssh_scan_api
CHANGED
@@ -1,16 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
$:.unshift File.join(File.dirname(__FILE__), "../lib")
|
4
|
-
|
5
3
|
require 'ssh_scan_api'
|
6
4
|
|
7
|
-
#
|
8
|
-
|
9
|
-
File.join(
|
10
|
-
File.dirname(__FILE__),
|
11
|
-
"../config/api/config.yml"
|
12
|
-
)
|
13
|
-
opts = YAML.load_file(config_file)
|
14
|
-
opts["config_file"] = config_file
|
15
|
-
|
16
|
-
SSHScan::API.run!(opts)
|
5
|
+
# Usage: ruby ./bin/ssh_scan_api
|
6
|
+
SSHScan::Api::Api.run!()
|
data/lib/ssh_scan_api.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
#External Deps
|
1
|
+
# #External Deps
|
2
2
|
require 'timeout'
|
3
3
|
require 'resolv'
|
4
4
|
require 'ssh_scan'
|
5
5
|
|
6
|
-
#Internal Deps
|
7
|
-
require 'ssh_scan_api/api'
|
6
|
+
# #Internal Deps
|
8
7
|
require 'ssh_scan_api/version'
|
9
|
-
require 'ssh_scan_api/
|
10
|
-
require 'ssh_scan_api/
|
11
|
-
require 'ssh_scan_api/
|
12
|
-
require 'ssh_scan_api/
|
8
|
+
require 'ssh_scan_api/api'
|
9
|
+
require 'ssh_scan_api/authenticator'
|
10
|
+
require 'ssh_scan_api/target_validator'
|
11
|
+
require 'ssh_scan_api/constants'
|
data/lib/ssh_scan_api/api.rb
CHANGED
@@ -1,231 +1,296 @@
|
|
1
|
-
require 'sinatra
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sinatra/activerecord'
|
2
3
|
require 'sinatra/namespace'
|
3
|
-
require 'json'
|
4
|
-
require 'haml'
|
5
|
-
require 'secure_headers'
|
6
|
-
require 'thin'
|
7
4
|
require 'securerandom'
|
8
|
-
require '
|
9
|
-
require 'ssh_scan_api/
|
10
|
-
require 'ssh_scan_api/
|
5
|
+
require 'secure_headers'
|
6
|
+
require 'ssh_scan_api/models/scan'
|
7
|
+
require 'ssh_scan_api/target_validator'
|
8
|
+
require 'ssh_scan_api/authenticator'
|
9
|
+
require 'pg'
|
11
10
|
|
12
11
|
module SSHScan
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
module Api
|
13
|
+
|
14
|
+
class Api < Sinatra::Base
|
15
|
+
if ENV['RACK_ENV'] == 'test'
|
16
|
+
configure do
|
17
|
+
set :database_file, "lib/config/database.yml"
|
18
|
+
set :authentication, false
|
19
|
+
set :authenticator, SSHScan::Api::Authenticator.new()
|
20
|
+
set :target_validator, SSHScan::Api::TargetValidator.new()
|
21
|
+
set :allowed_ports, 22
|
22
|
+
set :protection, false
|
23
|
+
end
|
22
24
|
end
|
23
|
-
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
config.cookies = {
|
29
|
-
secure: true, # mark all cookies as "Secure"
|
30
|
-
httponly: true, # mark all cookies as "HttpOnly"
|
31
|
-
}
|
32
|
-
config.hsts = "max-age=31536000; includeSubdomains; preload"
|
33
|
-
config.x_frame_options = "DENY"
|
34
|
-
config.x_content_type_options = "nosniff"
|
35
|
-
config.x_xss_protection = "1; mode=block"
|
36
|
-
config.x_download_options = "noopen"
|
37
|
-
config.x_permitted_cross_domain_policies = "none"
|
38
|
-
config.referrer_policy = "no-referrer"
|
39
|
-
config.csp = {
|
40
|
-
default_src: ["'none'"],
|
41
|
-
frame_ancestors: ["'none'"],
|
42
|
-
upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
|
43
|
-
}
|
44
|
-
end
|
26
|
+
include SSHScan
|
27
|
+
register Sinatra::Namespace
|
28
|
+
register Sinatra::ActiveRecordExtension
|
45
29
|
|
46
|
-
|
30
|
+
before do
|
31
|
+
content_type :json
|
32
|
+
end
|
47
33
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
34
|
+
# Configure all the secure headers we want to use
|
35
|
+
use SecureHeaders::Middleware
|
36
|
+
SecureHeaders::Configuration.default do |config|
|
37
|
+
config.cookies = {
|
38
|
+
secure: true, # mark all cookies as "Secure"
|
39
|
+
httponly: true, # mark all cookies as "HttpOnly"
|
40
|
+
}
|
41
|
+
config.hsts = "max-age=31536000; includeSubdomains; preload"
|
42
|
+
config.x_frame_options = "DENY"
|
43
|
+
config.x_content_type_options = "nosniff"
|
44
|
+
config.x_xss_protection = "1; mode=block"
|
45
|
+
config.x_download_options = "noopen"
|
46
|
+
config.x_permitted_cross_domain_policies = "none"
|
47
|
+
config.referrer_policy = "no-referrer"
|
48
|
+
config.csp = {
|
49
|
+
default_src: ["'none'"],
|
50
|
+
script_src: ["'none'"],
|
51
|
+
frame_ancestors: ["'none'"],
|
52
|
+
upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
|
53
|
+
}
|
54
|
+
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
before do
|
57
|
+
headers "Access-Control-Allow-Methods" => "GET, POST"
|
58
|
+
headers "Access-Control-Allow-Origin" => "*"
|
59
|
+
headers "Access-Control-Max-Age" => "86400"
|
60
|
+
headers "Cache-control" => "no-store"
|
61
|
+
headers "Pragma" => "no-cache"
|
62
|
+
headers "Server" => "ssh_scan_api"
|
57
63
|
end
|
58
|
-
end
|
59
64
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
65
|
+
# Custom 404 handling
|
66
|
+
not_found do
|
67
|
+
content_type "text/plain"
|
68
|
+
"Invalid request, see API documentation here: https://github.com/mozilla/ssh_scan_api/wiki/ssh_scan-Web-API\n"
|
69
|
+
end
|
66
70
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
71
|
+
get '/' do
|
72
|
+
content_type "text/plain"
|
73
|
+
"See API documentation here: https://github.com/mozilla/ssh_scan_api/wiki/ssh_scan-Web-API\n"
|
74
|
+
end
|
72
75
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
get '/robots.txt' do
|
77
|
+
content_type "text/plain"
|
78
|
+
"User-agent: *\nDisallow: /\n"
|
79
|
+
end
|
77
80
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
get '/contribute.json' do
|
82
|
+
content_type :json
|
83
|
+
SSHScan::Api::Constants::CONTRIBUTE_JSON.to_json
|
84
|
+
end
|
82
85
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
86
|
+
get '/__version__' do
|
87
|
+
{
|
88
|
+
:api_version => SSHScan::Api::VERSION,
|
89
|
+
}.to_json
|
90
|
+
end
|
89
91
|
|
90
|
-
|
91
|
-
before do
|
92
|
-
content_type :json
|
93
|
-
if settings.authentication == true
|
94
|
-
token = request.env['HTTP_SSH_SCAN_AUTH_TOKEN']
|
92
|
+
namespace "/api/v1" do
|
95
93
|
|
96
|
-
|
97
|
-
|
98
|
-
|
94
|
+
post '/scan' do
|
95
|
+
port = params["port"] || 22
|
96
|
+
|
97
|
+
# Check to see if there is a recent scan we offer
|
98
|
+
begin
|
99
|
+
latest_scan = Scan.where(["target = ? and port = ?", params["target"], port]).last
|
100
|
+
|
101
|
+
# Return prior scan results if run within 2min of now
|
102
|
+
if latest_scan && (Time.now - latest_scan.creation_time < 120)
|
103
|
+
return {"uuid": latest_scan.scan_id}.to_json
|
104
|
+
end
|
105
|
+
rescue
|
106
|
+
ActiveRecord::Base.connection_pool.release_connection
|
99
107
|
end
|
100
108
|
|
101
|
-
#
|
102
|
-
|
103
|
-
|
109
|
+
# Perform a new scan
|
110
|
+
begin
|
111
|
+
scan = Scan.new do |s|
|
112
|
+
s.scan_id = SecureRandom.uuid
|
113
|
+
s.creation_time = Time.now
|
114
|
+
s.target = params["target"]
|
115
|
+
s.port = port
|
116
|
+
s.state = "QUEUED"
|
117
|
+
s.save
|
118
|
+
end
|
119
|
+
ensure
|
120
|
+
ActiveRecord::Base.connection_pool.release_connection
|
104
121
|
end
|
122
|
+
|
123
|
+
return {"uuid": scan.scan_id}.to_json
|
105
124
|
end
|
106
|
-
end
|
107
125
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
get '/scan/results' do
|
127
|
+
uuid = params[:uuid]
|
128
|
+
|
129
|
+
# If we don't get a uuid, we don't know what scan to pick up
|
130
|
+
return {"error" => "no uuid specified"}.to_json if uuid.nil? || uuid.empty?
|
131
|
+
|
132
|
+
begin
|
133
|
+
scan = Scan.find_by("scan_id": uuid)
|
134
|
+
|
135
|
+
if scan.nil?
|
136
|
+
return {"scan" => "UNKNOWN"}.to_json
|
137
|
+
end
|
138
|
+
|
139
|
+
case scan.state
|
140
|
+
when "QUEUED"
|
141
|
+
return {"status" => "QUEUED"}.to_json
|
142
|
+
when "ERRORED"
|
143
|
+
return {"status" => "ERRORED"}.to_json
|
144
|
+
when "RUNNNING"
|
145
|
+
return {"status" => "RUNNNING"}.to_json
|
146
|
+
when "COMPLETED"
|
147
|
+
return scan.raw_scan
|
148
|
+
else
|
149
|
+
return {"status" => "UNKNOWN"}.to_json
|
129
150
|
end
|
151
|
+
ensure
|
152
|
+
ActiveRecord::Base.connection_pool.release_connection
|
130
153
|
end
|
131
154
|
end
|
132
|
-
options[:uuid] = SecureRandom.uuid
|
133
|
-
settings.job_queue.add(options)
|
134
|
-
{
|
135
|
-
uuid: options[:uuid]
|
136
|
-
}.to_json
|
137
|
-
end
|
138
155
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
return result.to_json
|
145
|
-
end
|
156
|
+
get '/work' do
|
157
|
+
# Always require authentication for this route
|
158
|
+
#authenticated?
|
159
|
+
|
160
|
+
worker_id = params[:worker_id]
|
146
161
|
|
147
|
-
|
148
|
-
|
162
|
+
#uuid = settings.db.next_scan_in_queue
|
163
|
+
scan = SSHScan::Scan.find_by("state": "QUEUED")
|
149
164
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
return {
|
165
|
+
if scan
|
166
|
+
scan.state = "RUNNING"
|
167
|
+
scan.worker_id = worker_id
|
168
|
+
scan.save
|
169
|
+
|
170
|
+
return {
|
171
|
+
"work" => {
|
172
|
+
"uuid" => scan.scan_id,
|
173
|
+
"target" => scan.target,
|
174
|
+
"port" => scan.port,
|
175
|
+
}
|
176
|
+
}.to_json
|
156
177
|
else
|
157
|
-
|
158
|
-
return {"deleted" => "true"}.to_json
|
178
|
+
return {"work" => false}.to_json
|
159
179
|
end
|
160
180
|
end
|
161
|
-
end
|
162
181
|
|
163
|
-
|
164
|
-
|
165
|
-
|
182
|
+
post '/work/results/:worker_id/:uuid' do
|
183
|
+
# Always require authentication for this route
|
184
|
+
#authenticated?
|
185
|
+
|
186
|
+
worker_id = params[:worker_id]
|
187
|
+
uuid = params[:uuid]
|
188
|
+
result = JSON.parse(request.body.first).first
|
189
|
+
|
190
|
+
if worker_id.empty? || uuid.empty?
|
191
|
+
return {"accepted" => "false"}.to_json
|
192
|
+
end
|
193
|
+
|
194
|
+
begin
|
195
|
+
scan = Scan.find_by("scan_id": uuid)
|
196
|
+
|
197
|
+
# Make sure we have a relevant match scan
|
198
|
+
return {"accepted" => "false"}.to_json unless scan
|
199
|
+
|
200
|
+
if result["error"]
|
201
|
+
scan.state = "ERRORED"
|
202
|
+
scan.worker_id = worker_id
|
203
|
+
scan.raw_scan = result.to_json
|
204
|
+
scan.save
|
205
|
+
else
|
206
|
+
scan.state = "COMPLETED"
|
207
|
+
scan.worker_id = worker_id
|
208
|
+
scan.raw_scan = result.to_json
|
209
|
+
scan.save
|
210
|
+
end
|
211
|
+
ensure
|
212
|
+
ActiveRecord::Base.connection_pool.release_connection
|
213
|
+
end
|
166
214
|
|
167
|
-
|
168
|
-
worker_id = params[:worker_id]
|
169
|
-
logger.warn("Worker #{worker_id} polls for Job")
|
170
|
-
job = settings.job_queue.next
|
171
|
-
if job.nil?
|
172
|
-
logger.warn("Worker #{worker_id} didn't get any work")
|
173
|
-
{"work" => false}.to_json
|
174
|
-
else
|
175
|
-
logger.warn("Worker #{worker_id} got job #{job[:uuid]}")
|
176
|
-
{"work" => job}.to_json
|
215
|
+
return {"accepted" => "true"}
|
177
216
|
end
|
178
|
-
end
|
179
217
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
218
|
+
get '/stats' do
|
219
|
+
queued_max_age = 0
|
220
|
+
|
221
|
+
begin
|
222
|
+
oldest = Scan.where(state: "QUEUED").minimum(:creation_time)
|
223
|
+
ensure
|
224
|
+
ActiveRecord::Base.connection_pool.release_connection
|
225
|
+
end
|
226
|
+
|
227
|
+
if oldest
|
228
|
+
queued_max_age = (Time.now - oldest).to_i
|
229
|
+
end
|
187
230
|
|
188
|
-
|
189
|
-
|
231
|
+
begin
|
232
|
+
report = {
|
233
|
+
"SCAN_STATES" => {
|
234
|
+
"QUEUED" => Scan.where(state: "QUEUED").count,
|
235
|
+
"BATCH_QUEUED" => Scan.where(state: "BATCH_QUEUED").count,
|
236
|
+
"RUNNING" => Scan.where(state: "RUNNING").count,
|
237
|
+
"ERRORED" => Scan.where(state: "ERRORED").count,
|
238
|
+
"COMPLETED" => Scan.where(state: "COMPLETED").count,
|
239
|
+
},
|
240
|
+
"QUEUED_MAX_AGE" => queued_max_age,
|
241
|
+
"GRADE_REPORT" => {
|
242
|
+
"A" => Scan.where(grade: "A").count,
|
243
|
+
"B" => Scan.where(grade: "B").count,
|
244
|
+
"C" => Scan.where(grade: "C").count,
|
245
|
+
"D" => Scan.where(grade: "D").count,
|
246
|
+
"F" => Scan.where(grade: "F").count,
|
247
|
+
}
|
248
|
+
# "AUTH_METHOD_REPORT" => settings.db.auth_method_report
|
249
|
+
}
|
250
|
+
ensure
|
251
|
+
ActiveRecord::Base.connection_pool.release_connection
|
252
|
+
end
|
253
|
+
|
254
|
+
return report.to_json
|
190
255
|
end
|
191
|
-
settings.stats.new_scan_request
|
192
|
-
settings.db.add_scan(worker_id, uuid, result, socket)
|
193
|
-
end
|
194
256
|
|
195
|
-
|
196
|
-
|
257
|
+
get '/__lbheartbeat__' do
|
258
|
+
{
|
259
|
+
:status => "OK",
|
260
|
+
:message => "Keep sending requests. I am still alive."
|
261
|
+
}.to_json
|
262
|
+
end
|
197
263
|
end
|
198
264
|
|
199
|
-
|
200
|
-
|
201
|
-
:status => "OK",
|
202
|
-
:message => "Keep sending requests. I am still alive."
|
203
|
-
}.to_json
|
204
|
-
end
|
205
|
-
end
|
265
|
+
def self.run!(options = {}, &block)
|
266
|
+
set options
|
206
267
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
set :logger, Logger.new(STDOUT)
|
215
|
-
set :job_queue, JobQueue.new()
|
216
|
-
set :db, SSHScan::Database.from_hash(options)
|
217
|
-
set :results, {}
|
218
|
-
set :stats, SSHScan::Stats.new
|
219
|
-
set :authentication, options["authentication"]
|
220
|
-
set :authenticator, SSHScan::Authenticator.from_config_file(
|
221
|
-
options["config_file"]
|
222
|
-
)
|
223
|
-
end
|
268
|
+
configure do
|
269
|
+
enable :logging
|
270
|
+
set :bind, ENV['SSHSCAN_API_HOST'] || '127.0.0.1'
|
271
|
+
set :port, (ENV['SSHSCAN_API_PORT'] || 8000).to_i
|
272
|
+
set :server, "thin"
|
273
|
+
set :logger, Logger.new(STDOUT)
|
274
|
+
#set :database_file, File.join(File.dirname(__FILE__),"../../config/database.yml")
|
224
275
|
|
225
|
-
|
226
|
-
|
227
|
-
|
276
|
+
database_adapter = 'postgresql'
|
277
|
+
database_host = ENV['SSHSCAN_DATABASE_HOST'] || '127.0.0.1'
|
278
|
+
database_name = ENV['SSHSCAN_DATABASE_NAME'] || 'ssh_observatory'
|
279
|
+
database_username = ENV['SSHSCAN_DATABASE_USERNAME'] || 'sshobs'
|
280
|
+
database_pool = 5
|
281
|
+
database_timeout = 5000
|
282
|
+
|
283
|
+
set :database, { adapter: database_adapter, database: database_name, username: database_username, host: database_host, pool: database_pool, timeout: database_timeout}
|
284
|
+
set :authentication, ENV['SSHSCAN_API_AUTHENTICATION'] == "true" || false
|
285
|
+
set :authenticator, SSHScan::Api::Authenticator.new()
|
286
|
+
set :target_validator, SSHScan::Api::TargetValidator.new()
|
287
|
+
set :allowed_ports, options["allowed_ports"]
|
288
|
+
set :protection, false
|
289
|
+
end
|
290
|
+
|
291
|
+
super
|
228
292
|
end
|
293
|
+
|
229
294
|
end
|
230
295
|
end
|
231
|
-
end
|
296
|
+
end
|