urlscan 0.3.0 → 0.7.0
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/.github/workflows/test.yml +25 -0
- data/README.md +20 -17
- data/lib/urlscan.rb +8 -0
- data/lib/urlscan/api.rb +6 -92
- data/lib/urlscan/cli.rb +1 -64
- data/lib/urlscan/clients/base.rb +85 -0
- data/lib/urlscan/clients/community.rb +33 -0
- data/lib/urlscan/clients/pro.rb +43 -0
- data/lib/urlscan/commands/base.rb +26 -0
- data/lib/urlscan/commands/community.rb +50 -0
- data/lib/urlscan/version.rb +1 -1
- data/renovate.json +5 -0
- data/urlscan.gemspec +6 -7
- metadata +26 -34
- data/.travis.yml +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0d83b308d78e0bd41123a1a6d37a4cec0d947dcb97dc9a79176a44b142c1c00d
|
|
4
|
+
data.tar.gz: 6912d1c6cbdc4099d1cd391b364c6e19ee98b9976ce0a6928c22ec333f43d33a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 447e4250c9f685716e981caccde9020c1c3f1f7cf6c00d89db553e541b174046cc3458800962e6fa8c1bcd407d6b5106cd20031864a5fcc63bde4aee30e29a8e
|
|
7
|
+
data.tar.gz: 910c24d8f9457e0736b6b11604150af4fb644c396d7da9f285e63e6006ec492ae0fb24155c705169bb1e97afd5f6e1df143404cd8eee2783cbf0c7b5a445e1c0
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Ruby CI
|
|
2
|
+
|
|
3
|
+
on: [pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
|
|
9
|
+
strategy:
|
|
10
|
+
fail-fast: false
|
|
11
|
+
matrix:
|
|
12
|
+
ruby: [2.7, "3.0"]
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v2
|
|
16
|
+
- name: Set up Ruby
|
|
17
|
+
uses: ruby/setup-ruby@v1
|
|
18
|
+
with:
|
|
19
|
+
ruby-version: ${{ matrix.ruby }}
|
|
20
|
+
bundler-cache: true
|
|
21
|
+
- name: Build and test with Rake
|
|
22
|
+
run: |
|
|
23
|
+
gem install bundler
|
|
24
|
+
bundle install
|
|
25
|
+
bundle exec rake
|
data/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# urlscan
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/urlscan)
|
|
4
|
-
[](https://github.com/ninoseki/urlscan/actions/workflows/test.yml)
|
|
5
5
|
[](https://codeclimate.com/github/ninoseki/urlscan/maintainability)
|
|
6
6
|
[](https://coveralls.io/github/ninoseki/urlscan?branch=master)
|
|
7
7
|
|
|
8
8
|
## Description
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
[urlscan.io](https://urlscan.io/) API wrapper for Ruby.
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -18,7 +18,7 @@ gem install urlscan
|
|
|
18
18
|
## API usage
|
|
19
19
|
|
|
20
20
|
```ruby
|
|
21
|
-
require
|
|
21
|
+
require "urlscan"
|
|
22
22
|
|
|
23
23
|
# when given nothing, it tries to load your API key from ENV["URLSCAN_API_KEY"]
|
|
24
24
|
api = UrlScan::API.new
|
|
@@ -27,32 +27,35 @@ api = UrlScan::API.new(api_key)
|
|
|
27
27
|
|
|
28
28
|
# Submit a URL to scan
|
|
29
29
|
res = api.submit("https://wikipedia.org")
|
|
30
|
-
puts res["result"] # => "https://urlscan.io/result/ac04bc14-4efe-439d-b356-8384843daf75/"
|
|
31
30
|
|
|
32
31
|
# Get a scan result
|
|
33
32
|
res = api.result("ac04bc14-4efe-439d-b356-8384843daf75")
|
|
34
|
-
p res # => See the following URL as an example of the response.
|
|
35
|
-
# https://gist.github.com/ninoseki/a974d7e95629813615b380c30e737825#file-result-json
|
|
36
33
|
|
|
37
34
|
# Get a DOM
|
|
38
35
|
res = api.dom("ac04bc14-4efe-439d-b356-8384843daf75")
|
|
39
|
-
p res
|
|
40
36
|
|
|
41
37
|
# Search
|
|
42
38
|
res = api.search("wikipedia.org")
|
|
43
|
-
p res # => See the following URL as an example of the reponse.
|
|
44
|
-
# https://gist.github.com/ninoseki/a974d7e95629813615b380c30e737825#file-search-json
|
|
45
39
|
```
|
|
46
40
|
|
|
47
|
-
|
|
41
|
+
## Supported API endpoints
|
|
48
42
|
|
|
49
|
-
| HTTP Method | URI | API method
|
|
50
|
-
|
|
51
|
-
| POST | /scan | `UrlScan::
|
|
52
|
-
| GET | /result/`uuid`/ | `UrlScan::
|
|
53
|
-
| GET | /dom/`uuid`/ | `UrlScan::
|
|
54
|
-
| GET | /screenshots/`uuid`.png | `UrlScan::
|
|
55
|
-
| GET | /search | `UrlScan::
|
|
43
|
+
| HTTP Method | URI | API method |
|
|
44
|
+
|-------------|-------------------------|-----------------------------------------------------------------------|
|
|
45
|
+
| POST | /scan | `UrlScan::Clients::Community#submit(url, is_public = true)` |
|
|
46
|
+
| GET | /result/`uuid`/ | `UrlScan::Clients::Community#result(uuid)` |
|
|
47
|
+
| GET | /dom/`uuid`/ | `UrlScan::Clients::Community#dom(uuid)` |
|
|
48
|
+
| GET | /screenshots/`uuid`.png | `UrlScan::Clients::Community#screenshot(uuid)` |
|
|
49
|
+
| GET | /search | `UrlScan::Clients::Community#search(q, size: 100, search_after: nil)` |
|
|
50
|
+
|
|
51
|
+
### Pro
|
|
52
|
+
|
|
53
|
+
| HTTP Method | URI | API method |
|
|
54
|
+
|-------------|-------------------------|---------------------------------------|
|
|
55
|
+
| GET | /brands | `UrlScan::Clients::Pro#brands` |
|
|
56
|
+
| GET | /kits | `UrlScan::Clients::Pro#kits` |
|
|
57
|
+
| GET | /phishfeed | `UrlScan::Clients::Pro#phishfeed` |
|
|
58
|
+
| GET | /result/`uuid`/similar/ | `UrlScan::Clients::Pro#similar(uuid)` |
|
|
56
59
|
|
|
57
60
|
## CLI usage
|
|
58
61
|
|
data/lib/urlscan.rb
CHANGED
|
@@ -2,5 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
require "urlscan/version"
|
|
4
4
|
require "urlscan/exceptions"
|
|
5
|
+
|
|
6
|
+
require "urlscan/clients/base"
|
|
7
|
+
require "urlscan/clients/community"
|
|
8
|
+
require "urlscan/clients/pro"
|
|
9
|
+
|
|
10
|
+
require "urlscan/commands/base"
|
|
11
|
+
require "urlscan/commands/community"
|
|
12
|
+
|
|
5
13
|
require "urlscan/api"
|
|
6
14
|
require "urlscan/cli"
|
data/lib/urlscan/api.rb
CHANGED
|
@@ -1,104 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
4
|
-
require "json"
|
|
3
|
+
require "forwardable"
|
|
5
4
|
|
|
6
5
|
module UrlScan
|
|
7
6
|
class API
|
|
8
|
-
|
|
9
|
-
HOST = "urlscan.io"
|
|
10
|
-
URL = "https://#{HOST}/api/v#{VERSION}"
|
|
7
|
+
extend Forwardable
|
|
11
8
|
|
|
12
|
-
attr_reader :
|
|
9
|
+
attr_reader :pro
|
|
13
10
|
|
|
14
11
|
def initialize(key = ENV["URLSCAN_API_KEY"])
|
|
15
|
-
@
|
|
12
|
+
@community = Clients::Community.new(key)
|
|
13
|
+
@pro = Clients::Pro.new(key)
|
|
16
14
|
end
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
def submit(url, is_public = true)
|
|
20
|
-
raise ArgumentError, "API key is required for this method." if key.nil?
|
|
21
|
-
|
|
22
|
-
params = { url: url, public: is_public ? "on" : "off" }
|
|
23
|
-
post("/scan/", params) { |json| json }
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# @return [Hash]
|
|
27
|
-
def result(uuid)
|
|
28
|
-
get("/result/#{uuid}") { |json| json }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# @return [String]
|
|
32
|
-
def dom(uuid)
|
|
33
|
-
get("/dom/#{uuid}/") { |dom| dom }
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def screenshot(uuid)
|
|
37
|
-
get("/screenshots/#{uuid}.png") { |png| png }
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# @return [Hash]
|
|
41
|
-
def search(q, size: 100, offset: 0, sort: "_score")
|
|
42
|
-
params = { q: q, size: size, offset: offset, sort: sort }
|
|
43
|
-
query = URI.encode_www_form(params)
|
|
44
|
-
get("/search/?#{query}") { |json| json }
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def url_for(path)
|
|
48
|
-
URI(URL + path)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def https_options
|
|
52
|
-
if proxy = ENV["HTTPS_PROXY"]
|
|
53
|
-
uri = URI(proxy)
|
|
54
|
-
{
|
|
55
|
-
proxy_address: uri.hostname,
|
|
56
|
-
proxy_port: uri.port,
|
|
57
|
-
proxy_from_env: false,
|
|
58
|
-
use_ssl: true
|
|
59
|
-
}
|
|
60
|
-
else
|
|
61
|
-
{ use_ssl: true }
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def request(req)
|
|
66
|
-
Net::HTTP.start(HOST, 443, https_options) do |http|
|
|
67
|
-
response = http.request(req)
|
|
68
|
-
|
|
69
|
-
case response.code
|
|
70
|
-
when "200"
|
|
71
|
-
if response["Content-Type"].to_s.include? "application/json"
|
|
72
|
-
yield JSON.parse(response.body)
|
|
73
|
-
else
|
|
74
|
-
yield response.body
|
|
75
|
-
end
|
|
76
|
-
when "400" then raise ProcessingError, response.body
|
|
77
|
-
when "401" then raise AuthenticationError, response.body
|
|
78
|
-
when "404" then raise NotFound, response.body
|
|
79
|
-
when "429" then raise RateLimited, response.body
|
|
80
|
-
when "500" then raise InternalServerError, response.body
|
|
81
|
-
else
|
|
82
|
-
raise ResponseError, response.body
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def auth_header
|
|
88
|
-
{ "API-KEY": key }
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def get(path, &block)
|
|
92
|
-
get = Net::HTTP::Get.new(url_for(path))
|
|
93
|
-
request(get, &block)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def post(path, json, &block)
|
|
97
|
-
post = Net::HTTP::Post.new(url_for(path), auth_header)
|
|
98
|
-
post.content_type = "application/json"
|
|
99
|
-
post.body = json.to_json
|
|
100
|
-
|
|
101
|
-
request(post, &block)
|
|
102
|
-
end
|
|
16
|
+
def_delegators :@community, :submit, :result, :dom, :screenshot, :search
|
|
103
17
|
end
|
|
104
18
|
end
|
data/lib/urlscan/cli.rb
CHANGED
|
@@ -1,68 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "json"
|
|
4
|
-
require "thor"
|
|
5
|
-
|
|
6
3
|
module UrlScan
|
|
7
|
-
class CLI <
|
|
8
|
-
class_option :API_KEY, type: :string
|
|
9
|
-
|
|
10
|
-
desc "submit [URL]", "submit a scan to [URL]"
|
|
11
|
-
method_option :public, type: :boolean, default: true
|
|
12
|
-
def submit(url)
|
|
13
|
-
with_error_handling do
|
|
14
|
-
res = api.submit(url, options[:public])
|
|
15
|
-
puts JSON.pretty_generate(res)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
desc "result [UUID]", "get the result of a scan using the scan id [UUID]"
|
|
20
|
-
def result(uuid)
|
|
21
|
-
with_error_handling do
|
|
22
|
-
res = api.result(uuid)
|
|
23
|
-
puts JSON.pretty_generate(res)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
desc "search [QUERY]", "search for scans by [QUERY]"
|
|
28
|
-
method_option :size, type: :numeric, default: 100
|
|
29
|
-
method_option :offset, type: :numeric, default: 0
|
|
30
|
-
method_option :sort, type: :string, default: "_score"
|
|
31
|
-
def search(query)
|
|
32
|
-
with_error_handling do
|
|
33
|
-
res = api.search(query, size: options["size"], offset: options["offset"], sort: options["sort"])
|
|
34
|
-
puts JSON.pretty_generate(res)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
desc "dom [UUID]", "get the DOM of a scan using the scan id [UUID]"
|
|
39
|
-
def dom(uuid)
|
|
40
|
-
with_error_handling do
|
|
41
|
-
res = api.dom(uuid)
|
|
42
|
-
puts res
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
desc "screenshot [UUID]", "get the screenshot(image/png) of a scan using the scan id [UUID]"
|
|
47
|
-
def screenshot(uuid)
|
|
48
|
-
with_error_handling do
|
|
49
|
-
res = api.screenshot(uuid)
|
|
50
|
-
puts res
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
no_commands do
|
|
55
|
-
def api
|
|
56
|
-
options["API_KEY"] ? API.new(options["API_KEY"]) : API.new
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def with_error_handling
|
|
60
|
-
yield
|
|
61
|
-
rescue ArgumentError => _e
|
|
62
|
-
puts "Warning: please specify your urlscan.io API key via ENV['URLSCAN_API_KEY'] or --API-KEY"
|
|
63
|
-
rescue ResponseError => e
|
|
64
|
-
puts "Warning: #{e}"
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
4
|
+
class CLI < Commands::Community; end
|
|
68
5
|
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/https"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module UrlScan
|
|
7
|
+
module Clients
|
|
8
|
+
class Base
|
|
9
|
+
VERSION = 1
|
|
10
|
+
HOST = "urlscan.io"
|
|
11
|
+
|
|
12
|
+
attr_reader :key
|
|
13
|
+
|
|
14
|
+
def initialize(key = ENV["URLSCAN_API_KEY"])
|
|
15
|
+
@key = key
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def url
|
|
21
|
+
@url ||= "https://#{HOST}/api/v#{VERSION}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def url_for(path)
|
|
25
|
+
URI(url + path)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def https_options
|
|
29
|
+
if proxy = ENV["HTTPS_PROXY"]
|
|
30
|
+
uri = URI(proxy)
|
|
31
|
+
{
|
|
32
|
+
proxy_address: uri.hostname,
|
|
33
|
+
proxy_port: uri.port,
|
|
34
|
+
proxy_from_env: false,
|
|
35
|
+
use_ssl: true
|
|
36
|
+
}
|
|
37
|
+
else
|
|
38
|
+
{ use_ssl: true }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def request(req)
|
|
43
|
+
Net::HTTP.start(HOST, 443, https_options) do |http|
|
|
44
|
+
response = http.request(req)
|
|
45
|
+
|
|
46
|
+
case response.code
|
|
47
|
+
when "200"
|
|
48
|
+
if response["Content-Type"].to_s.include? "application/json"
|
|
49
|
+
yield JSON.parse(response.body)
|
|
50
|
+
else
|
|
51
|
+
yield response.body
|
|
52
|
+
end
|
|
53
|
+
when "400" then raise ProcessingError, response.body
|
|
54
|
+
when "401" then raise AuthenticationError, response.body
|
|
55
|
+
when "404" then raise NotFound, response.body
|
|
56
|
+
when "429" then raise RateLimited, response.body
|
|
57
|
+
when "500" then raise InternalServerError, response.body
|
|
58
|
+
else
|
|
59
|
+
raise ResponseError, response.body
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def default_headers
|
|
65
|
+
@default_headers ||= { "API-KEY": key }.compact
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def get(path, params = {}, &block)
|
|
69
|
+
uri = url_for(path)
|
|
70
|
+
uri.query = URI.encode_www_form(params)
|
|
71
|
+
|
|
72
|
+
get = Net::HTTP::Get.new(uri, default_headers)
|
|
73
|
+
request(get, &block)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def post(path, json, &block)
|
|
77
|
+
post = Net::HTTP::Post.new(url_for(path), default_headers)
|
|
78
|
+
post.content_type = "application/json"
|
|
79
|
+
post.body = json.to_json
|
|
80
|
+
|
|
81
|
+
request(post, &block)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UrlScan
|
|
4
|
+
module Clients
|
|
5
|
+
class Community < Base
|
|
6
|
+
# @return [Hash]
|
|
7
|
+
def submit(url, is_public = true)
|
|
8
|
+
params = { url: url, public: is_public ? "on" : "off" }
|
|
9
|
+
post("/scan/", params) { |json| json }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @return [Hash]
|
|
13
|
+
def result(uuid)
|
|
14
|
+
get("/result/#{uuid}") { |json| json }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [String]
|
|
18
|
+
def dom(uuid)
|
|
19
|
+
get("/dom/#{uuid}/") { |dom| dom }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def screenshot(uuid)
|
|
23
|
+
get("/screenshots/#{uuid}.png") { |png| png }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [Hash]
|
|
27
|
+
def search(q, size: 100, search_after: nil)
|
|
28
|
+
params = { q: q, size: size, search_after: search_after }.compact
|
|
29
|
+
get("/search/", params) { |json| json }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UrlScan
|
|
4
|
+
module Clients
|
|
5
|
+
class Pro < Base
|
|
6
|
+
VERSION = 1
|
|
7
|
+
HOST = "urlscan.io"
|
|
8
|
+
|
|
9
|
+
# @return [Hash]
|
|
10
|
+
def brands
|
|
11
|
+
get("/brands") { |json| json }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return [Hash]
|
|
15
|
+
def kits
|
|
16
|
+
get("/kits") { |json| json }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Hash]
|
|
20
|
+
def phishfeed(q: "result.task.time:>now-24h", format: "json")
|
|
21
|
+
params = { q: q, format: format }
|
|
22
|
+
get("/phishfeed", params) { |json| json }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Hash]
|
|
26
|
+
def similar(uuid)
|
|
27
|
+
get("/result/#{uuid}/similar/") { |json| json }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def build_filter(filter)
|
|
33
|
+
return nil unless filter
|
|
34
|
+
|
|
35
|
+
filter.start_with?("$") ? filter : "$#{filter}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def url
|
|
39
|
+
@url ||= "https://#{HOST}/api/v#{VERSION}/pro"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "thor"
|
|
5
|
+
|
|
6
|
+
module UrlScan
|
|
7
|
+
module Commands
|
|
8
|
+
class Base < Thor
|
|
9
|
+
class_option :API_KEY, type: :string
|
|
10
|
+
|
|
11
|
+
no_commands do
|
|
12
|
+
def api
|
|
13
|
+
options.key?("API_KEY") ? API.new(options["API_KEY"]) : API.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def with_error_handling
|
|
17
|
+
yield
|
|
18
|
+
rescue ArgumentError => _e
|
|
19
|
+
puts "Warning: please specify your urlscan.io API key via ENV['URLSCAN_API_KEY'] or --API-KEY"
|
|
20
|
+
rescue ResponseError => e
|
|
21
|
+
puts "Warning: #{e}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module UrlScan
|
|
4
|
+
module Commands
|
|
5
|
+
class Community < Base
|
|
6
|
+
desc "submit [URL]", "submit a scan to [URL]"
|
|
7
|
+
method_option :public, type: :boolean, default: true
|
|
8
|
+
def submit(url)
|
|
9
|
+
with_error_handling do
|
|
10
|
+
res = api.submit(url, options[:public])
|
|
11
|
+
puts JSON.pretty_generate(res)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc "result [UUID]", "get the result of a scan using the scan id [UUID]"
|
|
16
|
+
def result(uuid)
|
|
17
|
+
with_error_handling do
|
|
18
|
+
res = api.result(uuid)
|
|
19
|
+
puts JSON.pretty_generate(res)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc "search [QUERY]", "search for scans by [QUERY]"
|
|
24
|
+
method_option :size, type: :numeric, default: 100
|
|
25
|
+
method_option :search_after, type: :string
|
|
26
|
+
def search(query)
|
|
27
|
+
with_error_handling do
|
|
28
|
+
res = api.search(query, size: options["size"], search_after: options["search_after"])
|
|
29
|
+
puts JSON.pretty_generate(res)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc "dom [UUID]", "get the DOM of a scan using the scan id [UUID]"
|
|
34
|
+
def dom(uuid)
|
|
35
|
+
with_error_handling do
|
|
36
|
+
res = api.dom(uuid)
|
|
37
|
+
puts res
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
desc "screenshot [UUID]", "get the screenshot(image/png) of a scan using the scan id [UUID]"
|
|
42
|
+
def screenshot(uuid)
|
|
43
|
+
with_error_handling do
|
|
44
|
+
res = api.screenshot(uuid)
|
|
45
|
+
puts res
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/urlscan/version.rb
CHANGED
data/urlscan.gemspec
CHANGED
|
@@ -21,13 +21,12 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
22
|
spec.require_paths = ["lib"]
|
|
23
23
|
|
|
24
|
-
spec.add_development_dependency "bundler", "~> 2.
|
|
24
|
+
spec.add_development_dependency "bundler", "~> 2.2"
|
|
25
25
|
spec.add_development_dependency "coveralls", "~> 0.8"
|
|
26
|
-
spec.add_development_dependency "
|
|
27
|
-
spec.add_development_dependency "
|
|
28
|
-
spec.add_development_dependency "
|
|
29
|
-
spec.add_development_dependency "
|
|
30
|
-
spec.add_development_dependency "webmock", "~> 3.6"
|
|
26
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.10"
|
|
28
|
+
spec.add_development_dependency "vcr", "~> 6.0"
|
|
29
|
+
spec.add_development_dependency "webmock", "~> 3.12"
|
|
31
30
|
|
|
32
|
-
spec.add_runtime_dependency "thor", "~>
|
|
31
|
+
spec.add_runtime_dependency "thor", "~> 1.1"
|
|
33
32
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: urlscan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Manabu Niseki
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-04-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '2.
|
|
19
|
+
version: '2.2'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '2.
|
|
26
|
+
version: '2.2'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: coveralls
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -38,91 +38,77 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0.8'
|
|
41
|
-
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: dotenv
|
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - "~>"
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '2.5'
|
|
48
|
-
type: :development
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - "~>"
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '2.5'
|
|
55
41
|
- !ruby/object:Gem::Dependency
|
|
56
42
|
name: rake
|
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
|
58
44
|
requirements:
|
|
59
45
|
- - "~>"
|
|
60
46
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
47
|
+
version: '13.0'
|
|
62
48
|
type: :development
|
|
63
49
|
prerelease: false
|
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
51
|
requirements:
|
|
66
52
|
- - "~>"
|
|
67
53
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
54
|
+
version: '13.0'
|
|
69
55
|
- !ruby/object:Gem::Dependency
|
|
70
56
|
name: rspec
|
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
|
72
58
|
requirements:
|
|
73
59
|
- - "~>"
|
|
74
60
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '3.
|
|
61
|
+
version: '3.10'
|
|
76
62
|
type: :development
|
|
77
63
|
prerelease: false
|
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
65
|
requirements:
|
|
80
66
|
- - "~>"
|
|
81
67
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '3.
|
|
68
|
+
version: '3.10'
|
|
83
69
|
- !ruby/object:Gem::Dependency
|
|
84
70
|
name: vcr
|
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
|
86
72
|
requirements:
|
|
87
73
|
- - "~>"
|
|
88
74
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '
|
|
75
|
+
version: '6.0'
|
|
90
76
|
type: :development
|
|
91
77
|
prerelease: false
|
|
92
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
79
|
requirements:
|
|
94
80
|
- - "~>"
|
|
95
81
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '
|
|
82
|
+
version: '6.0'
|
|
97
83
|
- !ruby/object:Gem::Dependency
|
|
98
84
|
name: webmock
|
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
|
100
86
|
requirements:
|
|
101
87
|
- - "~>"
|
|
102
88
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '3.
|
|
89
|
+
version: '3.12'
|
|
104
90
|
type: :development
|
|
105
91
|
prerelease: false
|
|
106
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
93
|
requirements:
|
|
108
94
|
- - "~>"
|
|
109
95
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '3.
|
|
96
|
+
version: '3.12'
|
|
111
97
|
- !ruby/object:Gem::Dependency
|
|
112
98
|
name: thor
|
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
|
114
100
|
requirements:
|
|
115
101
|
- - "~>"
|
|
116
102
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: '
|
|
103
|
+
version: '1.1'
|
|
118
104
|
type: :runtime
|
|
119
105
|
prerelease: false
|
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
107
|
requirements:
|
|
122
108
|
- - "~>"
|
|
123
109
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: '
|
|
125
|
-
description:
|
|
110
|
+
version: '1.1'
|
|
111
|
+
description:
|
|
126
112
|
email:
|
|
127
113
|
- manabu.niseki@gmail.com
|
|
128
114
|
executables:
|
|
@@ -131,10 +117,10 @@ extensions: []
|
|
|
131
117
|
extra_rdoc_files: []
|
|
132
118
|
files:
|
|
133
119
|
- ".codeclimate.yml"
|
|
120
|
+
- ".github/workflows/test.yml"
|
|
134
121
|
- ".gitignore"
|
|
135
122
|
- ".rspec"
|
|
136
123
|
- ".rubocop.yml"
|
|
137
|
-
- ".travis.yml"
|
|
138
124
|
- Gemfile
|
|
139
125
|
- LICENSE
|
|
140
126
|
- README.md
|
|
@@ -143,14 +129,20 @@ files:
|
|
|
143
129
|
- lib/urlscan.rb
|
|
144
130
|
- lib/urlscan/api.rb
|
|
145
131
|
- lib/urlscan/cli.rb
|
|
132
|
+
- lib/urlscan/clients/base.rb
|
|
133
|
+
- lib/urlscan/clients/community.rb
|
|
134
|
+
- lib/urlscan/clients/pro.rb
|
|
135
|
+
- lib/urlscan/commands/base.rb
|
|
136
|
+
- lib/urlscan/commands/community.rb
|
|
146
137
|
- lib/urlscan/exceptions.rb
|
|
147
138
|
- lib/urlscan/version.rb
|
|
139
|
+
- renovate.json
|
|
148
140
|
- urlscan.gemspec
|
|
149
141
|
homepage: https://github.com/ninoseki/urlscan
|
|
150
142
|
licenses:
|
|
151
143
|
- MIT
|
|
152
144
|
metadata: {}
|
|
153
|
-
post_install_message:
|
|
145
|
+
post_install_message:
|
|
154
146
|
rdoc_options: []
|
|
155
147
|
require_paths:
|
|
156
148
|
- lib
|
|
@@ -165,8 +157,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
165
157
|
- !ruby/object:Gem::Version
|
|
166
158
|
version: '0'
|
|
167
159
|
requirements: []
|
|
168
|
-
rubygems_version: 3.
|
|
169
|
-
signing_key:
|
|
160
|
+
rubygems_version: 3.2.15
|
|
161
|
+
signing_key:
|
|
170
162
|
specification_version: 4
|
|
171
163
|
summary: Ruby API client for urlscan.io
|
|
172
164
|
test_files: []
|