urlscan 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e026187891feb001443e0380f839bd4ad5cb08d0601be2c73af45345d8a1f3d
4
- data.tar.gz: 8b027008ebdb5c6686c4f1b2cfd841cebe4e933949473163d36f9ac8e3527ba4
3
+ metadata.gz: 798702a904c93cd2895f683aae28dd0dc3d44dfea5b17d247168a6189bcb9c21
4
+ data.tar.gz: 3fbca0a7a6210fa2062ea02f84bb83492544bbb53aa5d7d5e0cad09077fa271e
5
5
  SHA512:
6
- metadata.gz: a8c269b3080f8ec2e8d0785eba8b5fa3531ae169bd2718f02011920d20907d4c19a7c2293e6a146e391c6e5f231bc353732ae7d3f83f7ece50c66a068d8cff56
7
- data.tar.gz: 251095794ae5577e33d887497caa82fccea882f89a322eb8b02cac86f8f31e27e975c156131e0bb29ccb966a96b32159bcb0297bee8644edbc3829a5e80c5167
6
+ metadata.gz: 4cfebe6cd4c4673e3afaa2575b4af09e5b46d357097ce3701c26200dc2ff565124a04b57a1bdccb652e3330a5886e1fbf2550b93f00e73f12f7000d52c61768c
7
+ data.tar.gz: 6239d851913a5b67fd54c4688106145f3ffe4faea8908faf928d92c6ed8263c8d78c4891719ba1dc0f799d233ea99b8af498773fef8221c016e9e625443921c9
data/README.md CHANGED
@@ -18,7 +18,7 @@ gem install urlscan
18
18
  ## API usage
19
19
 
20
20
  ```ruby
21
- require 'urlscan'
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,34 @@ 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
- ### Supported API endpoints
41
+ ## Supported API endpoints
48
42
 
49
- | HTTP Method | URI | API method |
50
- |-------------|-------------------------|----------------------------------------------------------------|
51
- | POST | /scan | `UrlScan::API#submit(url, is_public = true)` |
52
- | GET | /result/`uuid`/ | `UrlScan::API#result(uuid)` |
53
- | GET | /dom/`uuid`/ | `UrlScan::API#dom(uuid)` |
54
- | GET | /screenshots/`uuid`.png | `UrlScan::API#screenshot(uuid)` |
55
- | GET | /search | `UrlScan::API#search(q, size: 100, offset: 0, sort: "_score")` |
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, offset: 0, sort: "_score")` |
50
+
51
+ ### Pro
52
+
53
+ | HTTP Method | URI | API method |
54
+ |-------------|---------|-------------------------------------------------------------------|
55
+ | GET | /search | `UrlScan::Clients::Pro#search(query: nil, filter: nil, size: 50)` |
56
+ | GET | /brands | `UrlScan::Clients::Pro#brands` |
57
+ | GET | /kits | `UrlScan::Clients::Pro#kits` |
56
58
 
57
59
  ## CLI usage
58
60
 
@@ -70,3 +72,15 @@ Options:
70
72
  [--API-KEY=API_KEY]
71
73
 
72
74
  ```
75
+
76
+ ### Pro
77
+
78
+ ```bash
79
+ $ urlscan pro
80
+ Commands:
81
+ urlscan pro help [COMMAND] # Describe subcommands or one specific subcommand
82
+ urlscan pro search # search for scans
83
+
84
+ Options:
85
+ [--API-KEY=API_KEY]
86
+ ```
data/lib/urlscan.rb CHANGED
@@ -2,5 +2,14 @@
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
+ require "urlscan/commands/pro"
13
+
5
14
  require "urlscan/api"
6
15
  require "urlscan/cli"
data/lib/urlscan/api.rb CHANGED
@@ -1,104 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "net/https"
4
- require "json"
3
+ require "forwardable"
5
4
 
6
5
  module UrlScan
7
6
  class API
8
- VERSION = 1
9
- HOST = "urlscan.io"
10
- URL = "https://#{HOST}/api/v#{VERSION}"
7
+ extend Forwardable
11
8
 
12
- attr_reader :key
9
+ attr_reader :pro
13
10
 
14
11
  def initialize(key = ENV["URLSCAN_API_KEY"])
15
- @key = key
12
+ @community = Clients::Community.new(key)
13
+ @pro = Clients::Pro.new(key)
16
14
  end
17
15
 
18
- # @return [Hash]
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,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
- require "thor"
5
-
6
3
  module UrlScan
7
- class CLI < Thor
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
4
+ class CLI < Commands::Community
5
+ desc "pro", "PRO api commands"
6
+ subcommand "pro", Commands::Pro
67
7
  end
68
8
  end
@@ -0,0 +1,82 @@
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://#{self.class::HOST}/api/v#{self.class::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 auth_header
65
+ { "API-KEY": key }
66
+ end
67
+
68
+ def get(path, &block)
69
+ get = Net::HTTP::Get.new(url_for(path))
70
+ request(get, &block)
71
+ end
72
+
73
+ def post(path, json, &block)
74
+ post = Net::HTTP::Post.new(url_for(path), auth_header)
75
+ post.content_type = "application/json"
76
+ post.body = json.to_json
77
+
78
+ request(post, &block)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,36 @@
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
+ raise ArgumentError, "API key is required for this method." if key.nil?
9
+
10
+ params = { url: url, public: is_public ? "on" : "off" }
11
+ post("/scan/", params) { |json| json }
12
+ end
13
+
14
+ # @return [Hash]
15
+ def result(uuid)
16
+ get("/result/#{uuid}") { |json| json }
17
+ end
18
+
19
+ # @return [String]
20
+ def dom(uuid)
21
+ get("/dom/#{uuid}/") { |dom| dom }
22
+ end
23
+
24
+ def screenshot(uuid)
25
+ get("/screenshots/#{uuid}.png") { |png| png }
26
+ end
27
+
28
+ # @return [Hash]
29
+ def search(q, size: 100, offset: 0, sort: "_score")
30
+ params = { q: q, size: size, offset: offset, sort: sort }
31
+ query = URI.encode_www_form(params)
32
+ get("/search/?#{query}") { |json| json }
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UrlScan
4
+ module Clients
5
+ class Pro < Base
6
+ VERSION = 1
7
+ HOST = "pro.urlscan.com"
8
+
9
+ def initialize(key = ENV["URLSCAN_API_KEY"])
10
+ super key
11
+
12
+ raise ArgumentError, "API key is required for this class." if key.nil?
13
+ end
14
+
15
+ # @return [Hash]
16
+ def search(query: nil, filter: nil, size: 50)
17
+ filter = build_filter(filter)
18
+ params = { q: query, size: size }.compact
19
+ uri_query = URI.encode_www_form(params)
20
+ uri_query << "&filter=#{filter}" if filter
21
+
22
+ get("/search?#{uri_query}") { |json| json }
23
+ end
24
+
25
+ # @return [Hash]
26
+ def brands
27
+ get("/brands") { |json| json }
28
+ end
29
+
30
+ # @return [Hash]
31
+ def kits
32
+ get("/kits") { |json| json }
33
+ end
34
+
35
+ private
36
+
37
+ def build_filter(filter)
38
+ return nil unless filter
39
+
40
+ filter.start_with?("$") ? filter : "$#{filter}"
41
+ end
42
+
43
+ def url
44
+ @url ||= "https://#{self.class::HOST}/api/v#{self.class::VERSION}/pro"
45
+ end
46
+
47
+ def get(path, &block)
48
+ get = Net::HTTP::Get.new(url_for(path), auth_header)
49
+ request(get, &block)
50
+ end
51
+ end
52
+ end
53
+ 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,51 @@
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 :offset, type: :numeric, default: 0
26
+ method_option :sort, type: :string, default: "_score"
27
+ def search(query)
28
+ with_error_handling do
29
+ res = api.search(query, size: options["size"], offset: options["offset"], sort: options["sort"])
30
+ puts JSON.pretty_generate(res)
31
+ end
32
+ end
33
+
34
+ desc "dom [UUID]", "get the DOM of a scan using the scan id [UUID]"
35
+ def dom(uuid)
36
+ with_error_handling do
37
+ res = api.dom(uuid)
38
+ puts res
39
+ end
40
+ end
41
+
42
+ desc "screenshot [UUID]", "get the screenshot(image/png) of a scan using the scan id [UUID]"
43
+ def screenshot(uuid)
44
+ with_error_handling do
45
+ res = api.screenshot(uuid)
46
+ puts res
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UrlScan
4
+ module Commands
5
+ class Pro < Base
6
+ desc "search", "search for scans"
7
+ method_option :size, type: :numeric, default: 50
8
+ method_option :query, type: :string
9
+ method_option :filter, type: :string
10
+ def search
11
+ with_error_handling do
12
+ res = api.pro.search(query: options["query"], filter: options["filter"], size: options["size"])
13
+ puts JSON.pretty_generate(res)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UrlScan
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
data/urlscan.gemspec CHANGED
@@ -23,11 +23,10 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 2.0"
25
25
  spec.add_development_dependency "coveralls", "~> 0.8"
26
- spec.add_development_dependency "dotenv", "~> 2.5"
27
26
  spec.add_development_dependency "rake", "~> 12.3"
28
27
  spec.add_development_dependency "rspec", "~> 3.8"
29
28
  spec.add_development_dependency "vcr", "~> 5.0"
30
- spec.add_development_dependency "webmock", "~> 3.6"
29
+ spec.add_development_dependency "webmock", "~> 3.7"
31
30
 
32
31
  spec.add_runtime_dependency "thor", "~> 0.20"
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.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manabu Niseki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-18 00:00:00.000000000 Z
11
+ date: 2019-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,20 +38,6 @@ 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
@@ -100,14 +86,14 @@ dependencies:
100
86
  requirements:
101
87
  - - "~>"
102
88
  - !ruby/object:Gem::Version
103
- version: '3.6'
89
+ version: '3.7'
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.6'
96
+ version: '3.7'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: thor
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -143,6 +129,12 @@ 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
137
+ - lib/urlscan/commands/pro.rb
146
138
  - lib/urlscan/exceptions.rb
147
139
  - lib/urlscan/version.rb
148
140
  - urlscan.gemspec