bixby_common 0.2.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.
- data/.document +5 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +45 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/bixby_common.gemspec +95 -0
- data/lib/bixby_common.rb +21 -0
- data/lib/bixby_common/api/base_module.rb +12 -0
- data/lib/bixby_common/api/bundle_repository.rb +12 -0
- data/lib/bixby_common/api/json_request.rb +25 -0
- data/lib/bixby_common/api/json_response.rb +69 -0
- data/lib/bixby_common/command_response.rb +31 -0
- data/lib/bixby_common/command_spec.rb +149 -0
- data/lib/bixby_common/exception/bundle_not_found.rb +5 -0
- data/lib/bixby_common/exception/command_not_found.rb +5 -0
- data/lib/bixby_common/util/crypto_util.rb +64 -0
- data/lib/bixby_common/util/hashify.rb +16 -0
- data/lib/bixby_common/util/http_client.rb +70 -0
- data/lib/bixby_common/util/jsonify.rb +27 -0
- data/test/helper.rb +74 -0
- data/test/support/test_bundle/bin/cat +2 -0
- data/test/support/test_bundle/bin/echo +2 -0
- data/test/support/test_bundle/digest +17 -0
- data/test/support/test_bundle/manifest.json +0 -0
- data/test/test_bixby_common.rb +18 -0
- data/test/test_command_spec.rb +92 -0
- data/test/test_jsonify.rb +36 -0
- data/test_guard.rb +179 -0
- metadata +267 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
require 'base64'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module Bixby
|
6
|
+
module CryptoUtil
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def encrypt(data, key_pem, iv_pem)
|
11
|
+
c = new_cipher()
|
12
|
+
c.encrypt
|
13
|
+
key = c.random_key
|
14
|
+
iv = c.random_iv
|
15
|
+
encrypted = c.update(data) + c.final
|
16
|
+
|
17
|
+
out = []
|
18
|
+
out << w( key_pem.public_encrypt(key) )
|
19
|
+
out << w( iv_pem.private_encrypt(iv) )
|
20
|
+
out << e64(encrypted)
|
21
|
+
|
22
|
+
return out.join("\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
def decrypt(data, key_pem, iv_pem)
|
26
|
+
data = StringIO.new(data, 'rb')
|
27
|
+
key = key_pem.private_decrypt(read_next(data))
|
28
|
+
iv = iv_pem.public_decrypt(read_next(data))
|
29
|
+
|
30
|
+
c = new_cipher()
|
31
|
+
c.decrypt
|
32
|
+
c.key = key
|
33
|
+
c.iv = iv
|
34
|
+
|
35
|
+
ret = c.update(d64(data.read)) + c.final
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def new_cipher
|
42
|
+
OpenSSL::Cipher.new("AES-256-CBC")
|
43
|
+
end
|
44
|
+
|
45
|
+
def w(s)
|
46
|
+
e64(s).gsub(/\n/, "\\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
def read_next(data)
|
50
|
+
d64(data.readline.gsub(/\\n/, "\n"))
|
51
|
+
end
|
52
|
+
|
53
|
+
def e64(s)
|
54
|
+
Base64.encode64(s)
|
55
|
+
end
|
56
|
+
|
57
|
+
def d64(s)
|
58
|
+
Base64.decode64(s)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end # CryptoUtil
|
64
|
+
end # Bixby
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module Bixby
|
3
|
+
|
4
|
+
# Adds to_hash method to an Object
|
5
|
+
module Hashify
|
6
|
+
|
7
|
+
# Creates a Hash representation of self
|
8
|
+
#
|
9
|
+
# @return [Hash]
|
10
|
+
def to_hash
|
11
|
+
self.instance_variables.inject({}) { |m,v| m[v[1,v.length].to_sym] = instance_variable_get(v); m }
|
12
|
+
end
|
13
|
+
|
14
|
+
end # Hashify
|
15
|
+
|
16
|
+
end # Bixby
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
require 'curb'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
module Bixby
|
6
|
+
|
7
|
+
# Utilities for creating HTTP Clients. Just a thin wrapper around curb and JSON
|
8
|
+
# for common cases.
|
9
|
+
module HttpClient
|
10
|
+
|
11
|
+
# Execute an HTTP GET request to the given URL
|
12
|
+
#
|
13
|
+
# @param [String] url
|
14
|
+
# @return [String] Contents of the response's body
|
15
|
+
def http_get(url)
|
16
|
+
Curl::Easy.http_get(url).body_str
|
17
|
+
end
|
18
|
+
|
19
|
+
# Execute an HTTP GET request (see #http_get) and parse the JSON response
|
20
|
+
#
|
21
|
+
# @param [String] url
|
22
|
+
# @return [Object] Result of calling JSON.parse() on the response body
|
23
|
+
def http_get_json(url)
|
24
|
+
MultiJson.load(http_get(url))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Convert a Hash into a Curl::Postfield Array
|
28
|
+
#
|
29
|
+
# @param [Hash] data
|
30
|
+
def create_post_data(data)
|
31
|
+
if data.kind_of? Hash then
|
32
|
+
data = data.map{ |k,v| Curl::PostField.content(k, v) }
|
33
|
+
end
|
34
|
+
data
|
35
|
+
end
|
36
|
+
|
37
|
+
# Execute an HTTP POST request to the given URL
|
38
|
+
#
|
39
|
+
# @param [String] url
|
40
|
+
# @param [Hash] data Key/Value pairs to POST
|
41
|
+
# @return [String] Contents of the response's body
|
42
|
+
def http_post(url, data)
|
43
|
+
return Curl::Easy.http_post(url, create_post_data(data)).body_str
|
44
|
+
end
|
45
|
+
|
46
|
+
# Execute an HTTP POST request (see #http_get) and parse the JSON response
|
47
|
+
#
|
48
|
+
# @param [String] url
|
49
|
+
# @param [Hash] data Key/Value pairs to POST
|
50
|
+
# @return [Object] Result of calling JSON.parse() on the response body
|
51
|
+
def http_post_json(url, data)
|
52
|
+
MultiJson.load(http_post(url, data))
|
53
|
+
end
|
54
|
+
|
55
|
+
# Execute an HTTP post request and save the response body
|
56
|
+
#
|
57
|
+
# @param [String] url
|
58
|
+
# @param [Hash] data Key/Value pairs to POST
|
59
|
+
# @return [void]
|
60
|
+
def http_post_download(url, data, dest)
|
61
|
+
File.open(dest, "w") do |io|
|
62
|
+
c = Curl::Easy.new(url)
|
63
|
+
c.on_body { |d| io << d; d.length }
|
64
|
+
c.http_post(data)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end # HttpClient
|
69
|
+
|
70
|
+
end # Bixby
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module Bixby
|
5
|
+
module Jsonify
|
6
|
+
|
7
|
+
include Hashify
|
8
|
+
|
9
|
+
def to_json
|
10
|
+
MultiJson.dump(self.to_hash)
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def from_json(json)
|
15
|
+
json = MultiJson.load(json) if json.kind_of? String
|
16
|
+
obj = self.allocate
|
17
|
+
json.each{ |k,v| obj.send("#{k}=".to_sym, v) }
|
18
|
+
obj
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(receiver)
|
23
|
+
receiver.extend(ClassMethods)
|
24
|
+
end
|
25
|
+
|
26
|
+
end # Jsonify
|
27
|
+
end # Bixby
|
data/test/helper.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'minitest/unit'
|
11
|
+
require 'turn'
|
12
|
+
require 'turn/reporter'
|
13
|
+
require 'turn/reporters/outline_reporter'
|
14
|
+
|
15
|
+
Turn.config.framework = :minitest
|
16
|
+
Turn.config.format = :outline
|
17
|
+
|
18
|
+
module Turn
|
19
|
+
class OutlineReporter < Reporter
|
20
|
+
def start_test(test)
|
21
|
+
@stdout = StringIO.new
|
22
|
+
@stderr = StringIO.new
|
23
|
+
|
24
|
+
name = naturalized_name(test)
|
25
|
+
|
26
|
+
io.print " %-57s" % name
|
27
|
+
|
28
|
+
@stdout.rewind
|
29
|
+
@stderr.rewind
|
30
|
+
|
31
|
+
$stdout = @stdout
|
32
|
+
$stderr = @stderr unless $DEBUG
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
require 'simplecov'
|
39
|
+
SimpleCov.start do
|
40
|
+
add_filter "/test/"
|
41
|
+
end
|
42
|
+
rescue Exception => ex
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
47
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
48
|
+
require 'bixby_common'
|
49
|
+
|
50
|
+
class MiniTest::Unit::TestCase
|
51
|
+
|
52
|
+
# minitest assert_throws doesn't seem to work properly
|
53
|
+
def assert_throws(clazz, msg = nil, &block)
|
54
|
+
begin
|
55
|
+
yield
|
56
|
+
rescue Exception => ex
|
57
|
+
puts "#{ex.class}: #{ex.message}"
|
58
|
+
puts ex.backtrace.join("\n")
|
59
|
+
if clazz.to_s == ex.class.name then
|
60
|
+
if msg.nil?
|
61
|
+
return
|
62
|
+
elsif msg == ex.message then
|
63
|
+
return
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
flunk("Expected #{mu_pp(clazz)} to have been thrown")
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
Dir.glob(File.dirname(__FILE__) + "/../lib/**/*.rb").each{ |f| require f }
|
73
|
+
|
74
|
+
MiniTest::Unit.autorun
|
@@ -0,0 +1,17 @@
|
|
1
|
+
{
|
2
|
+
"digest": "2429629015110c29f8fae8ca97e0e494410a28b981653c0e094cfe4a7567f1b7",
|
3
|
+
"files": [
|
4
|
+
{
|
5
|
+
"file": "bin/cat",
|
6
|
+
"digest": "6d14ab63802f3ef51bdc16db1cfeb6df93167fe7a2aa09a6c737293d42c118b2"
|
7
|
+
},
|
8
|
+
{
|
9
|
+
"file": "bin/echo",
|
10
|
+
"digest": "299001868fb8c02fd431c336c6d058f5558c5dff5b5af5e6fe04b870a6a9cbba"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"file": "manifest.json",
|
14
|
+
"digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Bixby
|
4
|
+
module Test
|
5
|
+
|
6
|
+
class TestBixbyCommon < MiniTest::Unit::TestCase
|
7
|
+
|
8
|
+
def test_autoloading
|
9
|
+
assert_equal(JsonRequest, JsonRequest.new(nil, nil).class)
|
10
|
+
assert_equal(BundleNotFound, BundleNotFound.new.class)
|
11
|
+
assert_equal(CommandNotFound, CommandNotFound.new.class)
|
12
|
+
assert_equal(CommandSpec, CommandSpec.new.class)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end # Test
|
18
|
+
end # Bixby
|
@@ -0,0 +1,92 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
module Bixby
|
6
|
+
module Test
|
7
|
+
|
8
|
+
class TestCommandSpec < MiniTest::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
BundleRepository.path = File.expand_path(File.dirname(__FILE__))
|
12
|
+
h = { :repo => "support", :bundle => "test_bundle", 'command' => "echo", :foobar => "baz" }
|
13
|
+
@c = CommandSpec.new(h)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def test_init_with_hash
|
18
|
+
|
19
|
+
assert(@c)
|
20
|
+
assert_equal("support", @c.repo)
|
21
|
+
assert_equal("test_bundle", @c.bundle)
|
22
|
+
assert_equal("echo", @c.command)
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_to_hash
|
27
|
+
|
28
|
+
assert_equal("support", @c.to_hash[:repo])
|
29
|
+
assert_equal("test_bundle", @c.to_hash[:bundle])
|
30
|
+
assert_equal("echo", @c.to_hash[:command])
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_validate
|
35
|
+
@c.validate
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_validate_failures
|
39
|
+
assert_throws(BundleNotFound) do
|
40
|
+
CommandSpec.new(:repo => "support", :bundle => "foobar").validate
|
41
|
+
end
|
42
|
+
assert_throws(CommandNotFound) do
|
43
|
+
CommandSpec.new(:repo => "support", :bundle => "test_bundle", :command => "foobar").validate
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_execute
|
48
|
+
(status, stdout, stderr) = @c.execute
|
49
|
+
assert(status.success?)
|
50
|
+
assert_equal("hi\n", stdout)
|
51
|
+
assert_equal("", stderr)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_execute_stdin
|
55
|
+
@c.command = "cat"
|
56
|
+
@c.stdin = "hi"
|
57
|
+
(status, stdout, stderr) = @c.execute
|
58
|
+
assert(status.success?)
|
59
|
+
assert_equal("hi", stdout)
|
60
|
+
assert_equal("", stderr)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_digest
|
64
|
+
assert_equal "2429629015110c29f8fae8ca97e0e494410a28b981653c0e094cfe4a7567f1b7", @c.digest
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_digest_no_err
|
68
|
+
c = CommandSpec.new({ :repo => "support", :bundle => "test_bundle", 'command' => "echofoo" })
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_update_digest
|
72
|
+
expected = MultiJson.load(File.read(BundleRepository.path + "/support/test_bundle/digest"))
|
73
|
+
|
74
|
+
t = "/tmp/foobar_test_repo"
|
75
|
+
d = "#{t}/support/test_bundle/digest"
|
76
|
+
`mkdir -p #{t}`
|
77
|
+
`cp -a #{BundleRepository.path}/support #{t}/`
|
78
|
+
`rm #{d}`
|
79
|
+
BundleRepository.path = t
|
80
|
+
|
81
|
+
refute File.exist? d
|
82
|
+
@c.update_digest
|
83
|
+
assert File.exist? d
|
84
|
+
|
85
|
+
assert_equal MultiJson.dump(expected), MultiJson.dump(MultiJson.load(File.read(d)))
|
86
|
+
`rm -rf #{t}`
|
87
|
+
end
|
88
|
+
|
89
|
+
end # TestCommandSpec
|
90
|
+
|
91
|
+
end # Test
|
92
|
+
end # Bixby
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
module Bixby
|
5
|
+
module Test
|
6
|
+
|
7
|
+
class TestJsonify < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
def test_to_json
|
10
|
+
j = JFoo.new
|
11
|
+
j.bar = "baz"
|
12
|
+
json = j.to_json
|
13
|
+
assert json
|
14
|
+
assert_equal '{"bar":"baz"}', json
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_from_json
|
18
|
+
j1 = JFoo.new
|
19
|
+
j1.bar = "baz"
|
20
|
+
|
21
|
+
j2 = JFoo.from_json(j1.to_json)
|
22
|
+
assert_equal "baz", j2.bar
|
23
|
+
|
24
|
+
j3 = JFoo.from_json('{"bar":"baz"}')
|
25
|
+
assert_equal "baz", j3.bar
|
26
|
+
end
|
27
|
+
|
28
|
+
end # Jsonify
|
29
|
+
|
30
|
+
class JFoo
|
31
|
+
include Jsonify
|
32
|
+
attr_accessor :bar
|
33
|
+
end
|
34
|
+
|
35
|
+
end # Test
|
36
|
+
end # Bixby
|