Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.1.0 #1

Merged
merged 1 commit into from Oct 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 5 additions & 3 deletions .gitignore
Expand Up @@ -42,9 +42,11 @@ 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

.rspec_status
3 changes: 3 additions & 0 deletions .rspec
@@ -0,0 +1,3 @@
--format documentation
--color
--require spec_helper
7 changes: 7 additions & 0 deletions .travis.yml
@@ -0,0 +1,7 @@
---
sudo: false
language: ruby
cache: bundler
rvm:
- 2.6.4
before_install: gem install bundler -v 2.0.2
6 changes: 6 additions & 0 deletions Gemfile
@@ -0,0 +1,6 @@
# frozen_string_literal: true

source "https://rubygems.org"

# Specify your gem's dependencies in zoomeye.gemspec
gemspec
45 changes: 44 additions & 1 deletion README.md
@@ -1 +1,44 @@
# zoomeye-rb
# zoomeye-rb

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

[ZoomEye](https://www.zoomeye.org/) API wrapper for Ruby.

## Installation

```bash
gem install zoomeye
```

## Usage

```ruby
require "zoomeye"

# when given nothing, it tries to load your usernamem & password via ENV["ZOOMEYE_USERNAME"] and ENV["ZOOMEYE_PASSWORD"]
api = ZoomEye::API.new

# or you can set them manually
api = ZoomEye::API.new(username: "USERNAME", password: "PASSWORD")

# Host search
api.host.search("port:80 nginx")
api.host.search("port:80 nginx", page: 7, facets: "app,device")

# Web search
api.web.search("wordpress")
api.web.search("wordpress", page: 1, facets: "app.os")

# Resource info
api.resource_info.get
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ninoseki/zoomeye-rb.

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
8 changes: 8 additions & 0 deletions Rakefile
@@ -0,0 +1,8 @@
# frozen_string_literal: true

require "bundler/gem_tasks"
require "rspec/core/rake_task"

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

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

require "bundler/setup"
require "zoomeye"

# 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/zoomeye.rb
@@ -0,0 +1,15 @@
# frozen_string_literal: true

require "zoomeye/version"

require "zoomeye/clients/base"

require "zoomeye/clients/host"
require "zoomeye/clients/resource_info"
require "zoomeye/clients/web"

require "zoomeye/api"

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

module ZoomEye
class API
attr_reader :host
attr_reader :web
attr_reader :resource_info

def initialize(username: ENV["ZOOMEYE_USERNAME"], password: ENV["ZOOMEYE_PASSWORD"])
@username = username
raise ArgumentError, "No usernamme has been found or provided!" unless @username

@password = password
raise ArgumentError, "No password has been found or provided!" unless @password

@web = Clients::Web.new(username: username, password: password)
@host = Clients::Host.new(username: username, password: password)
@resource_info = Clients::ResourceInfo.new(username: username, password: password)
end
end
end
97 changes: 97 additions & 0 deletions lib/zoomeye/clients/base.rb
@@ -0,0 +1,97 @@
# frozen_string_literal: true

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

module ZoomEye
module Clients
class Base
HOST = "api.zoomeye.org"
BASE_URL = "https://#{HOST}"

def initialize(username:, password:)
@username = username
@password = password
end

private

def access_token
@access_token ||= _post("/user/login", username: @username, password: @password) { |json| json.dig("access_token") }
end

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 make_request(req)
Net::HTTP.start(HOST, 443, https_options) do |http|
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("message") || body
raise Error, "Unsupported response code returned: #{code} - #{error}"
end
end
end

def token_headers
{
Authorization: "JWT #{access_token}"
}
end

def build_request(type: "GET", path:, params: {})
uri = url_for(path)
uri.query = URI.encode_www_form(params) if type == "GET"

headers = path == "/user/login" ? {} : token_headers

request = case type
when "GET"
Net::HTTP::Get.new(uri, headers)
when "POST"
Net::HTTP::Post.new(uri, headers)
else
raise ArgumentError, "#{type} HTTP method is not supported"
end

request.body = JSON.generate(params) unless type == "GET"

request
end

def _get(path, params = {}, &block)
request = build_request(type: "GET", path: path, params: params)
make_request(request, &block)
end

def _post(path, params = {}, &block)
request = build_request(type: "POST", path: path, params: params)
make_request(request, &block)
end
end
end
end
26 changes: 26 additions & 0 deletions lib/zoomeye/clients/host.rb
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module ZoomEye
module Clients
class Host < Base
#
# Search the Host devices
#
# @param [String] query Query string
# @param [Integer, nil] page The page number to paging(default:1)
# @param [String, nil] facets A comma-separated list of properties to get summary information on query
#
# @return [Hash]
#
def search(query, page: nil, facets: nil)
params = {
query: query,
page: page,
facets: facets
}.compact

_get("/host/search", params) { |json| json }
end
end
end
end
16 changes: 16 additions & 0 deletions lib/zoomeye/clients/resource_info.rb
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module ZoomEye
module Clients
class ResourceInfo < Base
#
# Resources info for account
#
# @return [Hash]
#
def get
_get("/resources-info") { |json| json }
end
end
end
end
26 changes: 26 additions & 0 deletions lib/zoomeye/clients/web.rb
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module ZoomEye
module Clients
class Web < Base
#
# Search the Web technologies
#
# @param [String] query Query string
# @param [Integer, nil] page The page number to paging(default:1)
# @param [String, nil] facets A comma-separated list of properties to get summary information on query
#
# @return [Hash]
#
def search(query, page: nil, facets: nil)
params = {
query: query,
page: page,
facets: facets
}.compact

_get("/web/search", params) { |json| json }
end
end
end
end
5 changes: 5 additions & 0 deletions lib/zoomeye/version.rb
@@ -0,0 +1,5 @@
# frozen_string_literal: true

module ZoomEye
VERSION = "0.1.0"
end
24 changes: 24 additions & 0 deletions spec/clients/host_spec.rb
@@ -0,0 +1,24 @@
# frozen_string_literal: true

RSpec.describe ZoomEye::Clients::Host, :vcr do
let(:api) { ZoomEye::API.new }

describe "#search" do
let(:query) { "port:80 nginx" }

it do
res = api.host.search(query)
expect(res).to be_a(Hash)
end

context "when given options" do
let(:page) { 7 }
let(:facets) { "app,device" }

it do
res = api.host.search(query, page: page, facets: facets)
expect(res).to be_a(Hash)
end
end
end
end
12 changes: 12 additions & 0 deletions spec/clients/resource_info_spec.rb
@@ -0,0 +1,12 @@
# frozen_string_literal: true

RSpec.describe ZoomEye::Clients::ResourceInfo, :vcr do
let(:api) { ZoomEye::API.new }

describe "#search" do
it do
res = api.resource_info.get
expect(res).to be_a(Hash)
end
end
end
24 changes: 24 additions & 0 deletions spec/clients/web_spec.rb
@@ -0,0 +1,24 @@
# frozen_string_literal: true

RSpec.describe ZoomEye::Clients::Web, :vcr do
let(:api) { ZoomEye::API.new }

describe "#search" do
let(:query) { "wordpress" }

it do
res = api.web.search(query)
expect(res).to be_a(Hash)
end

context "when given options" do
let(:page) { 1 }
let(:facets) { "app,os" }

it do
res = api.host.search(query, page: page, facets: facets)
expect(res).to be_a(Hash)
end
end
end
end