nayutaya-webhook-dispatcher 0.0.1 → 0.0.2

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/Rakefile CHANGED
@@ -5,10 +5,11 @@ task :default => [:test]
5
5
 
6
6
  Rake::TestTask.new do |test|
7
7
  test.libs << "test"
8
- test.test_files = Dir.glob("test/*_test.rb")
8
+ test.test_files = Dir.glob("test/**/*_test.rb")
9
9
  test.verbose = true
10
10
  end
11
11
 
12
+ desc "Generate gemspec file from template"
12
13
  task :gemspec do
13
14
  require "erb"
14
15
  require "lib/webhook-dispatcher/version"
@@ -19,8 +20,14 @@ task :gemspec do
19
20
  version = WebHookDispatcher::VERSION
20
21
  date = Time.now.strftime("%Y-%m-%d")
21
22
 
22
- files = Dir.glob("**/*").select { |s| File.file?(s) }
23
- test_files = Dir.glob("test/**").select { |s| File.file?(s) }
23
+ files = Dir.glob("**/*").
24
+ select { |path| File.file?(path) }.
25
+ reject { |path| /^nbproject\// =~ path }.
26
+ sort
27
+
28
+ test_files = Dir.glob("test/**.rb").
29
+ select { |path| File.file?(path) }.
30
+ sort
24
31
 
25
32
  File.open("webhook-dispatcher.gemspec", "wb") { |file|
26
33
  file.write(erb.result(binding))
data/example.rb CHANGED
@@ -1,47 +1,17 @@
1
1
 
2
2
  # このスクリプトはイメージであり、動作しません
3
3
 
4
- WebHookPublisher.open_timeout = 5 # sec
5
- WebHookPublisher.read_timeout = 5 # sec
6
- WebHookPublisher.user_agent = "hoge"
7
- WebHookPublisher.acl = x
8
- WebHookPublisher.acl_with {
9
- }
4
+ require "webhook-dispatcher"
10
5
 
11
- wp = WebHookPublisher.new
12
- wp.open_timeout = 5 # sec
13
- wp.read_timeout = 5 # sec
14
- wp.user_agent = "hoge"
15
- wp.acl = WebHookPublisher::Acl.with {
16
- allow :all
17
- allow "*", :all
18
- allow "*", 1024..3000
19
- allow "*", 0..1024
20
- allow "*", [1,2,3,4]
21
- deny IPAdd.new("0.0.0.0/0")
22
- allow "127.0.0.0/8"
23
- allow "localhost"
24
- }
6
+ p dispatcher = WebHookDispatcher.new
7
+ p request = WebHookDispatcher::Request::Get.new(URI.parse("http://www.google.co.jp"))
25
8
 
26
- acl.clear
27
- acl.add_deny(...)
28
- acl.add_allow(...)
29
- acl.allow?(ipaddr)
30
- acl.deny?(ipaddr)
31
- acl.with { ... }
32
-
33
-
34
- request_obj = WebHookPublisher::Request.new(:get, URI.new(..))
35
- request_obj.http_method = :get
36
- request_obj.uri = uri
9
+ p response = dispatcher.request(request)
37
10
 
11
+ =begin
38
12
  res = wp.request(request_obj)
39
13
  res = wp.get(url)
40
14
  res = wp.head(url)
41
15
  res = wp.post(url, data)
42
16
  #=> WebHookPublisher::Response
43
- res.success? #=> true/false
44
- res.status #=> :timeout
45
- res.status_code #=> 200
46
- res.status_message #=> OK
47
- res.inner_exception #=> #<RuntimeError>
17
+ =end
@@ -0,0 +1,12 @@
1
+
2
+ require "webhook-dispatcher/acl/entry_base"
3
+
4
+ class WebHookDispatcher
5
+ class Acl
6
+ class AllowEntry < EntryBase
7
+ def value
8
+ return true
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+
2
+ require "webhook-dispatcher/acl/entry_base"
3
+
4
+ class WebHookDispatcher
5
+ class Acl
6
+ class DenyEntry < EntryBase
7
+ def value
8
+ return false
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,94 @@
1
+
2
+ require "ipaddr"
3
+
4
+ class WebHookDispatcher
5
+ class Acl
6
+ class EntryBase
7
+ end
8
+ end
9
+ end
10
+
11
+ class WebHookDispatcher::Acl::EntryBase
12
+ def initialize(options = nil)
13
+ case options
14
+ when nil, :all
15
+ @addr = nil
16
+ @name = nil
17
+ @port = nil
18
+ when Hash
19
+ options = options.dup
20
+ @addr = normalize_addr(options.delete(:addr))
21
+ @name = normalize_name(options.delete(:name))
22
+ @port = normalize_port(options.delete(:port))
23
+ raise(ArgumentError) unless options.empty?
24
+ else raise(ArgumentError)
25
+ end
26
+ end
27
+
28
+ attr_reader :addr, :name, :port
29
+
30
+ def ==(other)
31
+ return false unless other.instance_of?(self.class)
32
+ return (self.to_a == other.to_a)
33
+ end
34
+
35
+ def match?(addr, name, port)
36
+ return match_addr?(addr) && match_name?(name) && match_port?(port)
37
+ end
38
+
39
+ def value
40
+ raise(NotImplementedError)
41
+ end
42
+
43
+ def to_a
44
+ return [@addr, @name, @port]
45
+ end
46
+
47
+ private
48
+
49
+ def normalize_addr(addr)
50
+ case addr
51
+ when nil then return nil
52
+ when :all then return nil
53
+ when String then return IPAddr.new(addr)
54
+ when IPAddr then return addr
55
+ else raise(ArgumentError)
56
+ end
57
+ end
58
+
59
+ def normalize_name(name)
60
+ case name
61
+ when nil then return nil
62
+ when :all then return nil
63
+ when String then return name.downcase
64
+ when Regexp then return name
65
+ else raise(ArgumentError)
66
+ end
67
+ end
68
+
69
+ def normalize_port(port)
70
+ case port
71
+ when nil then return nil
72
+ when :all then return nil
73
+ when Integer then return [port]
74
+ when Array then return port.sort
75
+ when Range then return port
76
+ else raise(ArgumentError)
77
+ end
78
+ end
79
+
80
+ def match_addr?(addr)
81
+ return true if self.addr.nil?
82
+ return (!addr.nil? && self.addr.include?(addr))
83
+ end
84
+
85
+ def match_name?(name)
86
+ return true if self.name.nil?
87
+ return (!name.nil? && (self.name === name.downcase))
88
+ end
89
+
90
+ def match_port?(port)
91
+ return true if self.port.nil?
92
+ return (!port.nil? && self.port.include?(port))
93
+ end
94
+ end
@@ -1,26 +1,62 @@
1
1
 
2
2
  require "ipaddr"
3
+ require "webhook-dispatcher/acl/allow_entry"
4
+ require "webhook-dispatcher/acl/deny_entry"
3
5
 
4
6
  class WebHookDispatcher::Acl
5
7
  def initialize
6
- @records = []
8
+ @entries = []
7
9
  end
8
10
 
9
11
  def self.with(&block)
10
12
  return self.new.with(&block)
11
13
  end
12
14
 
15
+ def self.allow_all
16
+ return self.with { allow :all }
17
+ end
18
+
19
+ def self.deny_all
20
+ return self.with { deny :all }
21
+ end
22
+
23
+ def self.ipaddr?(value)
24
+ return true if value.instance_of?(IPAddr)
25
+ begin
26
+ IPAddr.new(value)
27
+ return true
28
+ rescue ArgumentError
29
+ return false
30
+ end
31
+ end
32
+
33
+ def self.create_matching_targets(addr_or_name, port)
34
+ if self.ipaddr?(addr_or_name)
35
+ addr = addr_or_name
36
+ return [[IPAddr.new(addr), nil, port]]
37
+ else
38
+ name = addr_or_name
39
+ _name, _aliases, _type, *addresses = TCPSocket.gethostbyname(name)
40
+ return addresses.map { |addr| [IPAddr.new(addr), name, port] }
41
+ end
42
+ end
43
+
44
+ def ==(other)
45
+ return false unless other.instance_of?(self.class)
46
+ return (@entries == other.instance_eval { @entries })
47
+ end
48
+
13
49
  def size
14
- return @records.size
50
+ return @entries.size
15
51
  end
16
52
 
17
- def add_allow(ipaddr)
18
- @records << AllowRecord.new(ipaddr)
53
+ def add_allow(options)
54
+ @entries << AllowEntry.new(options)
19
55
  return self
20
56
  end
21
57
 
22
- def add_deny(ipaddr)
23
- @records << DenyRecord.new(ipaddr)
58
+ def add_deny(options)
59
+ @entries << DenyEntry.new(options)
24
60
  return self
25
61
  end
26
62
 
@@ -31,8 +67,8 @@ class WebHookDispatcher::Acl
31
67
 
32
68
  this = self
33
69
  (class << obj; self; end).class_eval {
34
- define_method(:allow) { |ipaddr| this.add_allow(ipaddr) }
35
- define_method(:deny) { |ipaddr| this.add_deny(ipaddr) }
70
+ define_method(:allow) { |options| this.add_allow(options) }
71
+ define_method(:deny) { |options| this.add_deny(options) }
36
72
  private :allow, :deny
37
73
  }
38
74
 
@@ -41,44 +77,18 @@ class WebHookDispatcher::Acl
41
77
  return self
42
78
  end
43
79
 
44
- def allow?(ipaddr)
45
- return @records.inject(true) { |result, record|
46
- result = record.value if record.include?(ipaddr)
47
- result
48
- }
49
- end
50
-
51
- def deny?(ipaddr)
52
- return !self.allow?(ipaddr)
53
- end
54
-
55
- class RecordBase
56
- def initialize(ipaddr)
57
- @ipaddr =
58
- case ipaddr
59
- when :all then IPAddr.new("0.0.0.0/0")
60
- when String then IPAddr.new(ipaddr)
61
- when IPAddr then ipaddr
62
- else raise(ArgumentError, "invalid IP address")
63
- end
64
- end
65
-
66
- attr_reader :ipaddr
67
-
68
- def include?(ipaddr)
69
- return @ipaddr.include?(ipaddr)
70
- end
71
- end
80
+ def allow?(addr_or_name, port = nil)
81
+ targets = self.class.create_matching_targets(addr_or_name, port)
72
82
 
73
- class AllowRecord < RecordBase
74
- def value
75
- return true
76
- end
83
+ return targets.all? { |taddr, tname, tport|
84
+ @entries.inject(true) { |result, entry|
85
+ result = entry.value if entry.match?(taddr, tname, tport)
86
+ result
87
+ }
88
+ }
77
89
  end
78
90
 
79
- class DenyRecord < RecordBase
80
- def value
81
- return false
82
- end
91
+ def deny?(addr_or_name, port = nil)
92
+ return !self.allow?(addr_or_name, port)
83
93
  end
84
94
  end
@@ -1,3 +1,110 @@
1
1
 
2
+ require "net/http"
3
+ require "webhook-dispatcher/version"
4
+ require "webhook-dispatcher/acl"
5
+ require "webhook-dispatcher/request/get"
6
+ require "webhook-dispatcher/request/head"
7
+ require "webhook-dispatcher/request/post"
8
+ require "webhook-dispatcher/response"
9
+
2
10
  class WebHookDispatcher
11
+ def initialize(options = {})
12
+ options = options.dup
13
+ @open_timeout = options.delete(:open_timeout) || self.class.open_timeout || self.class.default_open_timeout
14
+ @read_timeout = options.delete(:read_timeout) || self.class.read_timeout || self.class.default_read_timeout
15
+ @user_agent = options.delete(:user_agent) || self.class.user_agent || self.class.default_user_agent
16
+ @acl = options.delete(:acl) || self.class.acl || self.class.default_acl
17
+ raise(ArgumentError, "invalid parameter") unless options.empty?
18
+ end
19
+
20
+ class << self
21
+ @open_timeout = nil
22
+ @read_timeout = nil
23
+ @user_agent = nil
24
+ @acl = nil
25
+
26
+ attr_accessor :open_timeout, :read_timeout, :user_agent, :acl
27
+
28
+ define_method(:default_open_timeout) { 10 }
29
+ define_method(:default_read_timeout) { 10 }
30
+ define_method(:default_user_agent) { "webhook-dispatcher #{self::VERSION}" }
31
+ define_method(:default_acl) { Acl.new }
32
+
33
+ def acl_with(&block)
34
+ self.acl = Acl.with(&block)
35
+ end
36
+ end
37
+
38
+ attr_accessor :open_timeout, :read_timeout, :user_agent, :acl
39
+
40
+ def acl_with(&block)
41
+ self.acl = Acl.with(&block)
42
+ end
43
+
44
+ def request(request)
45
+ http_conn = request.create_http_connector
46
+ http_req = request.create_http_request
47
+ setup_http_connector(http_conn)
48
+ setup_http_request(http_req)
49
+
50
+ begin
51
+ if @acl.deny?(http_conn.address, http_conn.port)
52
+ return Response.new(
53
+ :status => :denied,
54
+ :message => "denied.")
55
+ end
56
+
57
+ http_res = http_conn.start { http_conn.request(http_req) }
58
+
59
+ return Response.new(
60
+ :status => (http_res.kind_of?(Net::HTTPSuccess) ? :success : :failure),
61
+ :http_code => http_res.code.to_i,
62
+ :message => http_res.message)
63
+ rescue TimeoutError => e
64
+ return Response.new(
65
+ :status => :timeout,
66
+ :message => "timeout.",
67
+ :exception => e)
68
+ rescue Errno::ECONNREFUSED => e
69
+ return Response.new(
70
+ :status => :refused,
71
+ :message => "connection refused.",
72
+ :exception => e)
73
+ rescue Errno::ECONNRESET => e
74
+ return Response.new(
75
+ :status => :reset,
76
+ :message => "connection reset by peer.",
77
+ :exception => e)
78
+ rescue => e
79
+ return Response.new(
80
+ :status => :error,
81
+ :message => "#{e.class}: #{e.message}",
82
+ :exception => e)
83
+ end
84
+ end
85
+
86
+ def get(uri)
87
+ return self.request(Request::Get.new(uri))
88
+ end
89
+
90
+ def head(uri)
91
+ return self.request(Request::Head.new(uri))
92
+ end
93
+
94
+ def post(uri, body = nil)
95
+ return self.request(Request::Post.new(uri, body))
96
+ end
97
+
98
+ private
99
+
100
+ def setup_http_connector(http_conn)
101
+ http_conn.open_timeout = self.open_timeout
102
+ http_conn.read_timeout = self.read_timeout
103
+ return http_conn
104
+ end
105
+
106
+ def setup_http_request(http_request)
107
+ http_request["User-Agent"] = self.user_agent
108
+ http_request
109
+ end
3
110
  end
@@ -1,5 +1,6 @@
1
1
 
2
2
  require "uri"
3
+ require "webhook-dispatcher/core"
3
4
 
4
5
  class WebHookDispatcher
5
6
  module Request
@@ -12,4 +13,12 @@ class WebHookDispatcher::Request::Base
12
13
  end
13
14
 
14
15
  attr_accessor :uri
16
+
17
+ def create_http_connector
18
+ return Net::HTTP.new(self.uri.host, self.uri.port)
19
+ end
20
+
21
+ def create_http_request
22
+ raise(NotImplementedError)
23
+ end
15
24
  end
@@ -5,4 +5,8 @@ class WebHookDispatcher::Request::Get < WebHookDispatcher::Request::Base
5
5
  def initialize(uri)
6
6
  super(uri)
7
7
  end
8
+
9
+ def create_http_request
10
+ return Net::HTTP::Get.new(self.uri.request_uri)
11
+ end
8
12
  end
@@ -0,0 +1,12 @@
1
+
2
+ require "webhook-dispatcher/request/base"
3
+
4
+ class WebHookDispatcher::Request::Head < WebHookDispatcher::Request::Base
5
+ def initialize(uri)
6
+ super(uri)
7
+ end
8
+
9
+ def create_http_request
10
+ return Net::HTTP::Head.new(self.uri.request_uri)
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+
2
+ require "webhook-dispatcher/request/base"
3
+
4
+ class WebHookDispatcher::Request::Post < WebHookDispatcher::Request::Base
5
+ def initialize(uri, body = nil)
6
+ super(uri)
7
+ @body = body
8
+ end
9
+
10
+ attr_accessor :body
11
+
12
+ def create_http_request
13
+ req = Net::HTTP::Post.new(self.uri.request_uri)
14
+ req.body = self.body
15
+ return req
16
+ end
17
+ end
@@ -2,7 +2,6 @@
2
2
  class WebHookDispatcher::Response
3
3
  def initialize(options = {})
4
4
  options = options.dup
5
- @success = (options.delete(:success) == true)
6
5
  @status = options.delete(:status) || :unknown
7
6
  @http_code = options.delete(:http_code) || nil
8
7
  @message = options.delete(:message) || nil
@@ -10,9 +9,9 @@ class WebHookDispatcher::Response
10
9
  raise(ArgumentError, "invalid parameter") unless options.empty?
11
10
  end
12
11
 
13
- attr_reader :success, :status, :http_code, :message, :exception
12
+ attr_reader :status, :http_code, :message, :exception
14
13
 
15
14
  def success?
16
- return self.success
15
+ return (self.status == :success)
17
16
  end
18
17
  end
@@ -1,4 +1,4 @@
1
1
 
2
2
  class WebHookDispatcher
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
@@ -0,0 +1,17 @@
1
+
2
+ require File.dirname(__FILE__) + "/../test_helper"
3
+ require "webhook-dispatcher/acl/allow_entry"
4
+
5
+ class AllowEntryTest < Test::Unit::TestCase
6
+ def setup
7
+ @klass = WebHookDispatcher::Acl::AllowEntry
8
+ end
9
+
10
+ #
11
+ # インスタンスメソッド
12
+ #
13
+
14
+ def test_value
15
+ assert_equal(true, @klass.new.value)
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+
2
+ require File.dirname(__FILE__) + "/../test_helper"
3
+ require "webhook-dispatcher/acl/deny_entry"
4
+
5
+ class DenyEntryTest < Test::Unit::TestCase
6
+ def setup
7
+ @klass = WebHookDispatcher::Acl::DenyEntry
8
+ end
9
+
10
+ def test_value
11
+ assert_equal(false, @klass.new.value)
12
+ end
13
+ end