urlscan 0.3.0 → 0.4.0

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
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