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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9e017981463ad9f0f6b8603541368d0cbbc21824
4
- data.tar.gz: 640d3e218c081b0bd08c4dba5ecc722b14831d6e
2
+ SHA256:
3
+ metadata.gz: 986e1fa32154fb3713c610f3339be18b71a9d4fa2306f7eebd7b427ebd0dc737
4
+ data.tar.gz: 785a82839c62ffe80e18576c6d0dbc47c1690c387f2f338ee32314b727cf8b02
5
5
  SHA512:
6
- metadata.gz: 09771fd4bed338ff605c8c499a9e7fc6b762e01793cc87ff050b53a58f13a90c2760681b919a4fc704ca0021d1d8d534ddf3d4ea64183290fbb7dc3eb51b62fa
7
- data.tar.gz: 8b21030f47a494ba2ae680de04f42916b3222a46ae9a4f41f1ca0a567bf4ed5fdcb401026648496d54438c7f522195c6d8c61db4d2721fccea0bdd82dd590789
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
- # .ruby-version
20
- # .ruby-gemset
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
@@ -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
- - mongodb
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.3.0
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
- - mongodb
16
- - rvm: 2.2.0
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
- - mongodb
21
- - rvm: 2.1.3
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
- - mongodb
26
- - rvm: 2.0.0
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=unit_tests
73
+ - LABEL=docker_build_tests
29
74
  services:
30
- - mongodb
75
+ - docker
76
+ script:
77
+ - docker-compose build
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem 'coveralls', require: false
4
- gemspec
3
+ gemspec
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
- ## Rubies Supported
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
- This project is integrated with [travis-ci](http://about.travis-ci.org/) and is regularly tested to work with the following rubies:
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
- * [ruby-head](https://github.com/ruby/ruby)
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/ssh_scan).
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 'ssh_scan_api/version'
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
 
@@ -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
- # Get the api config from command-line or via an example location
8
- config_file = ARGV[0] ||
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!()
@@ -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/job_queue'
10
- require 'ssh_scan_api/database'
11
- require 'ssh_scan_api/stats'
12
- require 'ssh_scan_api/authenticator'
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'
@@ -1,231 +1,296 @@
1
- require 'sinatra/base'
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 'ssh_scan'
9
- require 'ssh_scan_api/job_queue'
10
- require 'ssh_scan_api/database'
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
- class API < Sinatra::Base
14
- if ENV['RACK_ENV'] == 'test'
15
- configure do
16
- set :job_queue, SSHScan::JobQueue.new()
17
- set :authentication, false
18
- config_file = File.join(Dir.pwd, "./config/api/config.yml")
19
- opts = YAML.load_file(config_file)
20
- opts["config_file"] = config_file
21
- set :db, SSHScan::Database.from_hash(opts)
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
- # Configure all the secure headers we want to use
26
- use SecureHeaders::Middleware
27
- SecureHeaders::Configuration.default do |config|
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
- register Sinatra::Namespace
30
+ before do
31
+ content_type :json
32
+ end
47
33
 
48
- before do
49
- headers "Server" => "ssh_scan_api"
50
- headers "Cache-control" => "no-store"
51
- headers "Pragma" => "no-cache"
52
- end
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
- helpers do
55
- def cache_valid?(start_time)
56
- (Time.now - Time.parse(start_time.to_s)) / (60 * 60 * 24) < 1
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
- # Custom 404 handling
61
- not_found do
62
- content_type "text/plain"
63
- "Invalid request, see API documentation here: \
64
- https://github.com/mozilla/ssh_scan_api/wiki/ssh_scan-Web-API\n"
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
- get '/' do
68
- content_type "text/plain"
69
- "See API documentation here: \
70
- https://github.com/mozilla/ssh_scan_api/wiki/ssh_scan-Web-API\n"
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
- get '/robots.txt' do
74
- content_type "text/plain"
75
- "User-agent: *\nDisallow: /\n"
76
- end
76
+ get '/robots.txt' do
77
+ content_type "text/plain"
78
+ "User-agent: *\nDisallow: /\n"
79
+ end
77
80
 
78
- get '/contribute.json' do
79
- content_type :json
80
- SSHScan::Constants::CONTRIBUTE_JSON.to_json
81
- end
81
+ get '/contribute.json' do
82
+ content_type :json
83
+ SSHScan::Api::Constants::CONTRIBUTE_JSON.to_json
84
+ end
82
85
 
83
- get '/__version__' do
84
- {
85
- :ssh_scan_version => SSHScan::VERSION,
86
- :api_version => SSHScan::API_VERSION,
87
- }.to_json
88
- end
86
+ get '/__version__' do
87
+ {
88
+ :api_version => SSHScan::Api::VERSION,
89
+ }.to_json
90
+ end
89
91
 
90
- namespace "/api/v1" do
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
- # If a token is not provided, only localhost can proceed
97
- if token.nil? && request.ip != "127.0.0.1"
98
- halt '{"error" : "authentication failure"}'
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
- # If a token is provided, it must be valid to proceed
102
- if token && settings.authenticator.valid_token?(token) == false
103
- halt '{"error" : "authentication failure"}'
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
- post '/scan' do
109
- options = {
110
- :sockets => [],
111
- :policy => File.join(Dir.pwd,
112
- '/config/policies/mozilla_modern.yml'),
113
- :timeout => 2,
114
- :verbosity => nil,
115
- #:fingerprint_database => "fingerprints.db",
116
- }
117
- options[:sockets] <<
118
- "#{params[:target]}:#{params[:port] ? params[:port] : "22"}"
119
- options[:policy_file] = options[:policy]
120
- options[:force] = params[:force] ? params[:force] : false
121
-
122
- unless options[:force] == 'true'
123
- available_result = settings.db.fetch_cached_result(params)
124
- unless available_result.nil?
125
- if cache_valid?(available_result[:start_time])
126
- return {
127
- uuid: available_result[:uuid]
128
- }.to_json
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
- get '/scan/results' do
140
- uuid = params[:uuid]
141
- return {"scan" => "not found"}.to_json if uuid.nil? || uuid.empty?
142
- result = settings.db.find_scan_result(uuid)
143
- return {"scan" => "not found"}.to_json if result.nil?
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
- post '/scan/results/delete' do
148
- uuid = params[:uuid]
162
+ #uuid = settings.db.next_scan_in_queue
163
+ scan = SSHScan::Scan.find_by("state": "QUEUED")
149
164
 
150
- if uuid.nil? || uuid.empty?
151
- return {"deleted" => "false"}.to_json
152
- else
153
- scan = settings.db.find_scan_result(uuid)
154
- if scan.empty?
155
- return {"deleted" => "false"}.to_json
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
- settings.db.delete_scan(uuid)
158
- return {"deleted" => "true"}.to_json
178
+ return {"work" => false}.to_json
159
179
  end
160
180
  end
161
- end
162
181
 
163
- get '/scan/results/delete/all' do
164
- settings.db.delete_all
165
- end
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
- get '/work' do
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
- post '/work/results/:worker_id/:uuid' do
181
- worker_id = params['worker_id']
182
- uuid = params['uuid']
183
- result = JSON.parse(request.body.first).first
184
- socket = {}
185
- socket[:target] = result['ip']
186
- socket[:port] = result['port']
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
- if worker_id.empty? || uuid.empty?
189
- return {"accepted" => "false"}.to_json
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
- get '/stats' do
196
- settings.stats.get_stats(settings.job_queue.size)
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
- get '/__lbheartbeat__' do
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
- def self.run!(options = {}, &block)
208
- set options
209
-
210
- configure do
211
- enable :logging
212
- set :bind, options["bind"] || '127.0.0.1'
213
- set :server, "thin"
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
- super do |server|
226
- # No SSL on app, SSL termination happens in nginx for a prod deployment
227
- server.ssl = false
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