Skip to content

Commit

Permalink
Merge pull request #1 from ninoseki/dev
Browse files Browse the repository at this point in the history
First commit
  • Loading branch information
ninoseki committed Aug 15, 2020
2 parents 433ee16 + cf4eb40 commit d8a3c03
Show file tree
Hide file tree
Showing 39 changed files with 1,738 additions and 4 deletions.
8 changes: 5 additions & 3 deletions .gitignore
Expand Up @@ -45,12 +45,14 @@ build-iPhoneSimulator/

# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
# .ruby-version
# .ruby-gemset
Gemfile.lock
.ruby-version
.ruby-gemset

# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc

# Used by RuboCop. Remote config files pulled in from inherit_from directive.
# .rubocop-https?--*

.rspec_status
3 changes: 3 additions & 0 deletions .rspec
@@ -0,0 +1,3 @@
--format documentation
--color
--require spec_helper
6 changes: 6 additions & 0 deletions .travis.yml
@@ -0,0 +1,6 @@
---
language: ruby
cache: bundler
rvm:
- 2.7
before_install: gem install bundler -v 2.1
4 changes: 4 additions & 0 deletions Gemfile
@@ -0,0 +1,4 @@
source "https://rubygems.org"

# Specify your gem's dependencies in spysex.gemspec
gemspec
37 changes: 36 additions & 1 deletion README.md
@@ -1 +1,36 @@
# spysex
# spysex

[![Build Status](https://travis-ci.com/ninoseki/spysex.svg?branch=master)](https://travis-ci.com/ninoseki/spysex)
[![Coverage Status](https://coveralls.io/repos/github/ninoseki/spysex/badge.svg?branch=master)](https://coveralls.io/github/ninoseki/spysex?branch=master)
[![CodeFactor](https://www.codefactor.io/repository/github/ninoseki/spysex/badge)](https://www.codefactor.io/repository/github/ninoseki/spysex)

A dead simple [Spyse](https://spyse.com) API wrapper for Ruby.

Note: this wrapper does not support all the API endpoints.

## Installation

```bash
gem install spysex
```

## Usage

```ruby
require "spysex"

# when given nothing, it tries to load your usernamem & API key via ENV["SPYSE_API_KEY"]
api = Spyse::API.new
# or you can set them manually
api = Spyse::API.new("foo bar")

api.domain.get("example.com")
api.domain.search(search_params)

api.ip.get("1.1.1.1")
api.ip.search(search_params)
```

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
6 changes: 6 additions & 0 deletions Rakefile
@@ -0,0 +1,6 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task default: :spec
14 changes: 14 additions & 0 deletions bin/console
@@ -0,0 +1,14 @@
#!/usr/bin/env ruby

require "bundler/setup"
require "spysex"

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.

# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start

require "irb"
IRB.start(__FILE__)
8 changes: 8 additions & 0 deletions bin/setup
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle install

# Do any other automated setup that you need to do here
15 changes: 15 additions & 0 deletions lib/spyse.rb
@@ -0,0 +1,15 @@
require "spyse/version"

require "spyse/clients/base"

require "spyse/clients/as"
require "spyse/clients/cert"
require "spyse/clients/cve"
require "spyse/clients/domain"
require "spyse/clients/ip"

require "spyse/api"

module Spyse
class Error < StandardError; end
end
30 changes: 30 additions & 0 deletions lib/spyse/api.rb
@@ -0,0 +1,30 @@
# frozen_string_literal: true

module Spyse
class API
def initialize(api_key = ENV["SPYSE_API_KEY"])
@api_key = api_key
raise ArgumentError, "No api key has been found or provided!" unless @api_key
end

def as
@as ||= Client::AS.new(@api_key)
end

def cert
@cert ||= Client::Cert.new(@api_key)
end

def cve
@cve ||= Client::CVE.new(@api_key)
end

def domain
@domain ||= Client::Domain.new(@api_key)
end

def ip
@ip ||= Client::IP.new(@api_key)
end
end
end
35 changes: 35 additions & 0 deletions lib/spyse/clients/as.rb
@@ -0,0 +1,35 @@
# frozen_string_literal: true

module Spyse
module Client
class AS < Base
#
# Lists AS
#
# @see https://spyse.com/api#/as/as
#
# @return [Hash]
#
def get(asn, limit: nil, offset: nil)
params = {
asn: asn, limit: limit, offset: offset,
}.compact
_get("/as", params) { |json| json }
end

#
# Lists ASs
#
# @see https://spyse.com/api#/as/as_search
#
# @return [Hash]
#
def search(search_params, limit: nil, offset: nil)
params = {
search_params: search_params, limit: limit, offset: offset,
}.compact
_post("/as/search", params) { |json| json }
end
end
end
end
75 changes: 75 additions & 0 deletions lib/spyse/clients/base.rb
@@ -0,0 +1,75 @@
# frozen_string_literal: true

require "json"
require "net/https"
require "uri"

module Spyse
module Client
class Base
HOST = "api.spyse.com"
VERSION = "v3"
BASE_URL = "https://#{HOST}/#{VERSION}/data"

def initialize(api_key)
@api_key = api_key
end

private

def url_for(path)
URI(BASE_URL + path)
end

def https_options
if proxy = ENV["HTTPS_PROXY"] || ENV["https_proxy"]
uri = URI(proxy)
{
proxy_address: uri.hostname,
proxy_port: uri.port,
proxy_from_env: false,
use_ssl: true
}
else
{ use_ssl: true }
end
end

def request(req)
Net::HTTP.start(HOST, 443, https_options) do |http|
req["Authorization"] = "Bearer #{@api_key}"

response = http.request(req)

code = response.code.to_i
body = response.body
json = JSON.parse(body)

case code
when 200
yield json
else
error = json.dig("error", "message") || body
raise Error, "Unsupported response code returned: #{code} - #{error}"
end
end
end

def _get(path, params = {}, &block)
uri = url_for(path)
uri.query = URI.encode_www_form(params)
get = Net::HTTP::Get.new(uri)

request(get, &block)
end

def _post(path, params = {}, &block)
post = Net::HTTP::Post.new(url_for(path))
post.body = JSON.generate(params)
post["Content-Type"] = "application/json"

request(post, &block)
end
end
end
end
35 changes: 35 additions & 0 deletions lib/spyse/clients/cert.rb
@@ -0,0 +1,35 @@
# frozen_string_literal: true

module Spyse
module Client
class Cert < Base
#
# Lists Certificate
#
# @see https://spyse.com/api#/certificate/certificate
#
# @return [Hash]
#
def get(hash, limit: nil, offset: nil)
params = {
hash: hash, limit: limit, offset: offset,
}.compact
_get("/cert", params) { |json| json }
end

#
# Lists certificates
#
# @see https://spyse.com/api#/certificate/cert_search
#
# @return [Hash]
#
def search(search_params, limit: nil, offset: nil)
params = {
search_params: search_params, limit: limit, offset: offset,
}.compact
_post("/cert/search", params) { |json| json }
end
end
end
end
49 changes: 49 additions & 0 deletions lib/spyse/clients/cve.rb
@@ -0,0 +1,49 @@
# frozen_string_literal: true

module Spyse
module Client
class CVE < Base
#
# Lists CVE
#
# @see https://spyse.com/api#/cve/cve
#
# @return [Hash]
#
def get(cve_id, limit: nil, offset: nil)
params = {
cve_id: cve_id, limit: limit, offset: offset,
}.compact
_get("/cve", params) { |json| json }
end

#
# Lists IPs, that vulnerable by provided CVE
#
# @see https://spyse.com/api#/cve/vulnerable_ip_by_cve
#
# @return [Hash]
#
def vulnerable_ip(cve, limit: nil, offset: nil)
params = {
cve: cve, limit: limit, offset: offset,
}.compact
_get("/cve/vulnerable-ip", params) { |json| json }
end

#
# Lists CVEs
#
# @see https://spyse.com/api#/cve/cve_search
#
# @return [Hash]
#
def search(search_params, limit: nil, offset: nil)
params = {
search_params: search_params, limit: limit, offset: offset,
}.compact
_post("/cve/search", params) { |json| json }
end
end
end
end

0 comments on commit d8a3c03

Please sign in to comment.