ssh_scan_api 0.0.1.pre2 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/mozilla/ssh_scan_api.png)](http://travis-ci.org/mozilla/ssh_scan_api)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/mozilla/ssh_scan_api.png)](https://codeclimate.com/github/mozilla/ssh_scan_api)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/ssh_scan.svg)](https://badge.fury.io/rb/ssh_scan_api)
|
6
|
+
[![Join the chat at https://gitter.im/mozilla-ssh_scan/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mozilla-ssh_scan/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
7
|
+
[![Coverage Status](https://coveralls.io/repos/github/mozilla/ssh_scan_api/badge.svg?branch=master)](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
|