passivetotalx 0.1.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 +7 -0
- data/.gitignore +52 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +46 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/passivetotal.rb +26 -0
- data/lib/passivetotal/api.rb +68 -0
- data/lib/passivetotal/clients/account.rb +121 -0
- data/lib/passivetotal/clients/action.rb +279 -0
- data/lib/passivetotal/clients/artifact.rb +141 -0
- data/lib/passivetotal/clients/base.rb +97 -0
- data/lib/passivetotal/clients/dns.rb +61 -0
- data/lib/passivetotal/clients/enrichment.rb +119 -0
- data/lib/passivetotal/clients/host.rb +69 -0
- data/lib/passivetotal/clients/monitor.rb +29 -0
- data/lib/passivetotal/clients/project.rb +153 -0
- data/lib/passivetotal/clients/ssl.rb +73 -0
- data/lib/passivetotal/clients/tag.rb +77 -0
- data/lib/passivetotal/clients/tracker.rb +25 -0
- data/lib/passivetotal/clients/whois.rb +61 -0
- data/lib/passivetotal/version.rb +5 -0
- data/lib/passivetotalx.rb +3 -0
- data/passivetotalx.gemspec +33 -0
- metadata +154 -0
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PassiveTotal
|
4
|
+
module Client
|
5
|
+
class Artifact < Base
|
6
|
+
#
|
7
|
+
# Create artifacts in bulk.
|
8
|
+
# http://api.passivetotal.org/api/docs/#api-Artifact-PutV2ArtifactBulk
|
9
|
+
#
|
10
|
+
# @param [Array<Hash>] artifacts a list of dictionaries that match the /v2/artifact interface (has query, type, tags, and project fields per dictionary)
|
11
|
+
#
|
12
|
+
# @return [Hash]
|
13
|
+
#
|
14
|
+
def bulk_create(artifacts)
|
15
|
+
params = {
|
16
|
+
artifacts: artifacts,
|
17
|
+
}.compact
|
18
|
+
|
19
|
+
_put("/artifact/bulk", params) { |json| json }
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Delete artifacts in bulk.
|
24
|
+
# http://api.passivetotal.org/api/docs/#api-Artifact-DeleteV2ArtifactBulk
|
25
|
+
#
|
26
|
+
# @param [Array<String>] artifacts the artifact ids to delete
|
27
|
+
#
|
28
|
+
# @return [Hash]
|
29
|
+
#
|
30
|
+
def bulk_delete(artifacts)
|
31
|
+
params = {
|
32
|
+
artifacts: artifacts,
|
33
|
+
}.compact
|
34
|
+
|
35
|
+
_delete("/artifact/bulk", params) { |json| json }
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Perform artifact updates in bulk.
|
40
|
+
# http://api.passivetotal.org/api/docs/#api-Artifact-PostV2ArtifactBulk
|
41
|
+
#
|
42
|
+
# @param [Array<Hash>] artifacts a list of dictionaries which match the fields for the /v2/artifact (artifact, monitor, tags)
|
43
|
+
#
|
44
|
+
# @return [Hash]
|
45
|
+
#
|
46
|
+
def bulk_update(artifacts)
|
47
|
+
params = {
|
48
|
+
artifacts: artifacts,
|
49
|
+
}.compact
|
50
|
+
|
51
|
+
_post("/artifact/bulk", params) { |json| json }
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Create an artifact.
|
56
|
+
# http://api.passivetotal.org/api/docs/#api-Artifact-PutV2Artifact
|
57
|
+
#
|
58
|
+
# @param [String] project the project id the artifact will live on
|
59
|
+
# @param [String] query the actual artifact query (passivetotal.org, 8.8.8.8, etc).
|
60
|
+
# @param [String, nil] type the type of the artifact (domain, ip, etc), or inferred by query string if domain or ip (optional).
|
61
|
+
# @param [String, nil] tags the tags the new artifact will have
|
62
|
+
#
|
63
|
+
# @return [Hash]
|
64
|
+
#
|
65
|
+
def create(project:, query:, type: nil, tags: nil)
|
66
|
+
params = {
|
67
|
+
project: project,
|
68
|
+
query: query,
|
69
|
+
type: type,
|
70
|
+
tags: tags,
|
71
|
+
}.compact
|
72
|
+
|
73
|
+
_put("/artifact", params) { |json| json }
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Delete an artifact with a UUID.
|
78
|
+
# http://api.passivetotal.org/api/docs/#api-Artifact-DeleteV2Artifact
|
79
|
+
#
|
80
|
+
# @param [String] artifact the artifact id
|
81
|
+
#
|
82
|
+
# @return [Hash]
|
83
|
+
#
|
84
|
+
def delete(artifact)
|
85
|
+
params = {
|
86
|
+
artifact: artifact,
|
87
|
+
}.compact
|
88
|
+
|
89
|
+
_delete("/artifact", params) { |json| json }
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Read existing artifacts. If no filters are passed, this returns all your personal artifacts created by you or your organization.
|
94
|
+
# http://api.passivetotal.org/api/docs/#api-Artifact-GetV2Artifact
|
95
|
+
#
|
96
|
+
# @param [String] artifact the artifact id
|
97
|
+
# @param [String] project filter by project id
|
98
|
+
# @param [String] owner filter by owner (an email or organization id)
|
99
|
+
# @param [String] creator filter by creator
|
100
|
+
# @param [String] organization filter by organization
|
101
|
+
# @param [String] query filter by query (passivetotal.org, etc)
|
102
|
+
# @param [String] type filter by artifact type (domain, ip, etc)
|
103
|
+
#
|
104
|
+
# @return [Hash]
|
105
|
+
#
|
106
|
+
def find(artifact: nil, project: nil, owner: nil, creator: nil, organization: nil, query: nil, type: nil)
|
107
|
+
params = {
|
108
|
+
artifact: artifact,
|
109
|
+
project: project,
|
110
|
+
owner: owner,
|
111
|
+
creator: creator,
|
112
|
+
organization: organization,
|
113
|
+
query: query,
|
114
|
+
type: type,
|
115
|
+
}.compact
|
116
|
+
|
117
|
+
_get("/artifact", params) { |json| json }
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Update artifact, or toggle monitoring status. If you want to change the query or artifact type, simply delete it and create a new one. Use /v2/artifact/tag to add or delete tags without setting everything at once.
|
122
|
+
# http://api.passivetotal.org/api/docs/#api-Artifact-PostV2Artifact
|
123
|
+
#
|
124
|
+
# @param [String] artifact the artifact id to update
|
125
|
+
# @param [String, nil] monitor whether to monitor the artifact
|
126
|
+
# @param [Array<String>, nil] tags sets the artifact's tags to this list
|
127
|
+
#
|
128
|
+
# @return [Hash]
|
129
|
+
#
|
130
|
+
def update(artifact, monitor: nil, tags: nil)
|
131
|
+
params = {
|
132
|
+
artifact: artifact,
|
133
|
+
monitor: monitor,
|
134
|
+
tags: tags,
|
135
|
+
}.compact
|
136
|
+
|
137
|
+
_post("/artifact", params) { |json| json }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PassiveTotal
|
4
|
+
module Client
|
5
|
+
class Base
|
6
|
+
HOST = "api.passivetotal.org"
|
7
|
+
VERSION = "v2"
|
8
|
+
BASE_URL = "https://#{HOST}/#{VERSION}"
|
9
|
+
|
10
|
+
def initialize(username:, api_key:)
|
11
|
+
@username = username
|
12
|
+
@api_key = api_key
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def url_for(path)
|
18
|
+
URI(BASE_URL + path)
|
19
|
+
end
|
20
|
+
|
21
|
+
def https_options
|
22
|
+
if proxy = ENV["HTTPS_PROXY"] || ENV["https_proxy"]
|
23
|
+
uri = URI(proxy)
|
24
|
+
{
|
25
|
+
proxy_address: uri.hostname,
|
26
|
+
proxy_port: uri.port,
|
27
|
+
proxy_from_env: false,
|
28
|
+
use_ssl: true
|
29
|
+
}
|
30
|
+
else
|
31
|
+
{ use_ssl: true }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def make_request(req)
|
36
|
+
Net::HTTP.start(HOST, 443, https_options) do |http|
|
37
|
+
response = http.request(req)
|
38
|
+
|
39
|
+
code = response.code.to_i
|
40
|
+
body = response.body
|
41
|
+
json = JSON.parse(body)
|
42
|
+
|
43
|
+
case code
|
44
|
+
when 200
|
45
|
+
yield json
|
46
|
+
else
|
47
|
+
error = json.dig("error") || body
|
48
|
+
raise Error, "Unsupported response code returned: #{code} - #{error}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_request(type: "GET", path:, params: {})
|
54
|
+
uri = url_for(path)
|
55
|
+
uri.query = URI.encode_www_form(params) if type == "GET"
|
56
|
+
|
57
|
+
request = case type
|
58
|
+
when "GET"
|
59
|
+
Net::HTTP::Get.new(uri)
|
60
|
+
when "POST"
|
61
|
+
Net::HTTP::Post.new(uri)
|
62
|
+
when "PUT"
|
63
|
+
Net::HTTP::Put.new(path)
|
64
|
+
when "DELETE"
|
65
|
+
Net::HTTP::Delete.new(path)
|
66
|
+
else
|
67
|
+
raise ArgumentError, "#{type} HTTP method is not supported"
|
68
|
+
end
|
69
|
+
|
70
|
+
request.body = JSON.generate(params) unless type == "GET"
|
71
|
+
request.basic_auth @username, @api_key
|
72
|
+
|
73
|
+
request
|
74
|
+
end
|
75
|
+
|
76
|
+
def _get(path, params = {}, &block)
|
77
|
+
request = build_request(type: "GET", path: path, params: params)
|
78
|
+
make_request(request, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
def _post(path, params = {}, &block)
|
82
|
+
request = build_request(type: "POST", path: path, params: params)
|
83
|
+
make_request(request, &block)
|
84
|
+
end
|
85
|
+
|
86
|
+
def _put(path, params = {}, &block)
|
87
|
+
request = build_request(type: "PUT", path: path, params: params)
|
88
|
+
make_request(request, &block)
|
89
|
+
end
|
90
|
+
|
91
|
+
def _delete(path, params = {}, &block)
|
92
|
+
request = build_request(type: "DELETE", path: path, params: params)
|
93
|
+
make_request(request, &block)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PassiveTotal
|
4
|
+
module Client
|
5
|
+
class DNS < Base
|
6
|
+
#
|
7
|
+
# Retrieves the passive DNS results from active account sources.
|
8
|
+
# http://api.passivetotal.org/api/docs/#api-Passive_DNS-GetV2DnsPassive
|
9
|
+
#
|
10
|
+
# @param [String] query the domain or IP being queried
|
11
|
+
# @param [String] start the start datetime
|
12
|
+
# @param [String] end the end datetime
|
13
|
+
# @param [String] timeout timeout to use for external resources
|
14
|
+
#
|
15
|
+
# @return [Hash]
|
16
|
+
#
|
17
|
+
def passive(query, start_at: nil, end_at: nil, timeout: 7)
|
18
|
+
params = {
|
19
|
+
query: query,
|
20
|
+
start: start_at,
|
21
|
+
end: end_at,
|
22
|
+
timeout: timeout,
|
23
|
+
}.compact
|
24
|
+
|
25
|
+
_get("/dns/passive", params) { |json| json }
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Retrieves the unique passive DNS results from active account sources.
|
30
|
+
# http://api.passivetotal.org/api/docs/#api-Passive_DNS-GetV2DnsPassiveUnique
|
31
|
+
#
|
32
|
+
# @param [String] query the domain or IP being queried
|
33
|
+
#
|
34
|
+
# @return [Hash]
|
35
|
+
#
|
36
|
+
def passive_unique(query)
|
37
|
+
params = {
|
38
|
+
query: query,
|
39
|
+
}.compact
|
40
|
+
|
41
|
+
_get("/dns/passive/unique", params) { |json| json }
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Searches the Passive DNS data for a keyword query.
|
46
|
+
# http://api.passivetotal.org/api/docs/#api-Passive_DNS-GetV2DnsSearchKeyword
|
47
|
+
#
|
48
|
+
# @param [String] query query
|
49
|
+
#
|
50
|
+
# @return [Hash]
|
51
|
+
#
|
52
|
+
def search(query)
|
53
|
+
params = {
|
54
|
+
query: query
|
55
|
+
}.compact
|
56
|
+
|
57
|
+
_get("/dns/search/keyword", params) { |json| json }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PassiveTotal
|
4
|
+
module Client
|
5
|
+
class Enrichment < Base
|
6
|
+
#
|
7
|
+
# Get enrichment data for a query
|
8
|
+
# http://api.passivetotal.org/api/docs/#api-Enrichment-GetV2Enrichment
|
9
|
+
#
|
10
|
+
# @param [String] query the domain or IP being queried
|
11
|
+
#
|
12
|
+
# @return [Hash]
|
13
|
+
#
|
14
|
+
def get(query)
|
15
|
+
params = {
|
16
|
+
query: query,
|
17
|
+
}.compact
|
18
|
+
|
19
|
+
_get("/enrichment", params) { |json| json }
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Get malware data for a query
|
24
|
+
# http://api.passivetotal.org/api/docs/#api-Enrichment-GetV2EnrichmentMalware
|
25
|
+
#
|
26
|
+
# @param [String] query the domain or IP being queried
|
27
|
+
#
|
28
|
+
# @return [Hash]
|
29
|
+
#
|
30
|
+
def malware(query)
|
31
|
+
params = {
|
32
|
+
query: query,
|
33
|
+
}.compact
|
34
|
+
|
35
|
+
_get("/enrichment/malware", params) { |json| json }
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Get osint data for a query
|
40
|
+
# http://api.passivetotal.org/api/docs/#api-Enrichment-GetV2EnrichmentOsint
|
41
|
+
#
|
42
|
+
# @param [String] query the domain or IP being queried
|
43
|
+
#
|
44
|
+
# @return [Hash]
|
45
|
+
#
|
46
|
+
def osint(query)
|
47
|
+
params = {
|
48
|
+
query: query,
|
49
|
+
}.compact
|
50
|
+
|
51
|
+
_get("/enrichment/osint", params) { |json| json }
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Get subdomains data for a query
|
56
|
+
# http://api.passivetotal.org/api/docs/#api-Enrichment-GetV2EnrichmentSubdomains
|
57
|
+
#
|
58
|
+
# @param [String] query the domain being queried
|
59
|
+
#
|
60
|
+
# @return [Hash]
|
61
|
+
#
|
62
|
+
def subdomains(query)
|
63
|
+
params = {
|
64
|
+
query: query,
|
65
|
+
}.compact
|
66
|
+
|
67
|
+
_get("/enrichment/subdomains", params) { |json| json }
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Get bulk enrichment data for many queries
|
72
|
+
# http://api.passivetotal.org/api/docs/#api-Bulk_Enrichment-GetV2EnrichmentBulk
|
73
|
+
#
|
74
|
+
# @param [Array<String>] query the domains and IPs being queried
|
75
|
+
#
|
76
|
+
# @return [Hash]
|
77
|
+
#
|
78
|
+
def bulk_data(*query)
|
79
|
+
params = {
|
80
|
+
query: query,
|
81
|
+
}.compact
|
82
|
+
|
83
|
+
_get("/enrichment/bulk", params) { |json| json }
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Get bulk malware data for many queries
|
88
|
+
# http://api.passivetotal.org/api/docs/#api-Bulk_Enrichment-GetV2EnrichmentBulkMalware
|
89
|
+
#
|
90
|
+
# @param [Array<String>] query the domains and IPs being queried
|
91
|
+
#
|
92
|
+
# @return [Hash]
|
93
|
+
#
|
94
|
+
def bulk_malware(*query)
|
95
|
+
params = {
|
96
|
+
query: query,
|
97
|
+
}.compact
|
98
|
+
|
99
|
+
_get("/enrichment/bulk/malware", params) { |json| json }
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Get bulk osint data for many queries
|
104
|
+
# http://api.passivetotal.org/api/docs/#api-Bulk_Enrichment-GetV2EnrichmentBulkOsint
|
105
|
+
#
|
106
|
+
# @param [Array<String>] query the domains and IPs being queried
|
107
|
+
#
|
108
|
+
# @return [Hash]
|
109
|
+
#
|
110
|
+
def bulk_osint(*query)
|
111
|
+
params = {
|
112
|
+
query: query,
|
113
|
+
}.compact
|
114
|
+
|
115
|
+
_get("/enrichment/bulk/osint", params) { |json| json }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PassiveTotal
|
4
|
+
module Client
|
5
|
+
class Host < Base
|
6
|
+
#
|
7
|
+
# Retrieves the host attribute components of a query.
|
8
|
+
# http://api.passivetotal.org/api/docs/#api-Host_Attributes-GetV2HostAttributesComponents
|
9
|
+
#
|
10
|
+
# @param [String] query
|
11
|
+
# @param [String, nil] start_at
|
12
|
+
# @param [String, nil] end_at
|
13
|
+
#
|
14
|
+
# @return [Hash]
|
15
|
+
#
|
16
|
+
def components(query, start_at: nil, end_at: nil)
|
17
|
+
params = {
|
18
|
+
query: query,
|
19
|
+
start: start_at,
|
20
|
+
end: end_at,
|
21
|
+
}.compact
|
22
|
+
|
23
|
+
_get("/host-attributes/components", params) { |json| json }
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Retrieves the host attribute pairs related to the query.
|
28
|
+
# https://api.passivetotal.org/api/docs/#api-Host_Attributes-GetV2HostAttributesComponents
|
29
|
+
#
|
30
|
+
# @param [String] query
|
31
|
+
# @param [String] direction
|
32
|
+
# @param [String] start_at
|
33
|
+
# @param [String] end_at
|
34
|
+
#
|
35
|
+
# @return [Hash]
|
36
|
+
#
|
37
|
+
def pairs(query, direction: "children", start_at: nil, end_at: nil)
|
38
|
+
params = {
|
39
|
+
query: query,
|
40
|
+
direction: direction,
|
41
|
+
start: start_at,
|
42
|
+
end: end_at,
|
43
|
+
}.compact
|
44
|
+
|
45
|
+
_get("/host-attributes/pairs", params) { |json| json }
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Retrieves the host attribute trackers
|
50
|
+
# https://api.passivetotal.org/api/docs/#api-Host_Attributes-GetV2HostAttributesTrackers
|
51
|
+
#
|
52
|
+
# @param [String] query
|
53
|
+
# @param [String, nil] start_at
|
54
|
+
# @param [String, nil] end_at
|
55
|
+
#
|
56
|
+
# @return [Hash]
|
57
|
+
#
|
58
|
+
def trackers(query, start_at: nil, end_at: nil)
|
59
|
+
params = {
|
60
|
+
query: query,
|
61
|
+
start: start_at,
|
62
|
+
end: end_at,
|
63
|
+
}.compact
|
64
|
+
|
65
|
+
_get("/host-attributes/trackers", params) { |json| json }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|