coder_decorator 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f29535d9096afdc19576192bc1f3c8417ab764f0
4
+ data.tar.gz: bcb43020e75dcc1d579ab24108b897d8b1f205bf
5
+ SHA512:
6
+ metadata.gz: 734f600c21637fb446c8188933581d405e955900b4bb75423ab0a9e882e48e846e04ea4b40daac85d73d76169e8ef4b02849ec446128b3a5330762db87a21df1
7
+ data.tar.gz: 54f858ea180c61ef4639926b08dcc86062f8c4734c1e55adb2fb0c558da7eb6bf1482e54fb95ed36c17a28d16fa5c2ea57d99f392ebcd343915de131493adb99
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+ module CoderDecorator; end # :nodoc:
3
+ Dir[File.join(__dir__, 'coder_decorator', '**', '*.rb')].each { |path| require path }
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/coders/coder'
3
+ module CoderDecorator
4
+ module Coders
5
+ class Base64 < Coder # :nodoc:
6
+ def initialize(coder = nil, strict: true)
7
+ super(coder)
8
+ @template_str = strict ? 'm0' : 'm'
9
+ end
10
+
11
+ def encode(obj)
12
+ [coder.encode(obj)].pack(@template_str)
13
+ end
14
+
15
+ def decode(str)
16
+ coder.decode(str.unpack(@template_str).first)
17
+ rescue ::ArgumentError
18
+ raise InvalidEncoding
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/coders/coder'
3
+ require 'coder_decorator/coders/base64'
4
+ require 'openssl'
5
+
6
+ module CoderDecorator
7
+ module Coders
8
+ # Encrypt the data into this format:
9
+ #
10
+ # "#{encrypted_data}--#{initial_vector}"
11
+ #
12
+ class Cipher < Coder
13
+ def initialize(coder = nil, secret:, cipher: 'AES-256-CBC')
14
+ super(coder)
15
+ @secret = secret
16
+ @cipher = ::OpenSSL::Cipher.new(cipher)
17
+ @base64 = Coders::Base64.new
18
+ end
19
+
20
+ def encode(obj)
21
+ @cipher.encrypt
22
+ @cipher.key = @secret
23
+ iv = @cipher.random_iv
24
+ encrypted_data = @cipher.update(coder.encode(obj)) << @cipher.final
25
+ blob = "#{@base64.encode(encrypted_data)}--#{@base64.encode(iv)}"
26
+ @base64.encode(blob)
27
+ end
28
+
29
+ def decode(str)
30
+ encrypted_data, iv = @base64.decode(str).split('--').map! { |v| @base64.decode(v) }
31
+ @cipher.decrypt
32
+ @cipher.key = @secret
33
+ @cipher.iv = iv
34
+ begin
35
+ coder.decode(@cipher.update(encrypted_data) << @cipher.final)
36
+ rescue ::OpenSSL::Cipher::CipherError
37
+ raise InvalidEncoding
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/errors'
3
+ module CoderDecorator
4
+ module Coders
5
+ # The abstract class of coder, must implement #encode and #decode.
6
+ # It's designed with decorator pattern, which makes it more flexible,
7
+ # and can be wrapped infinitely using Ruby instantiation.
8
+ #
9
+ # To implement a custom coder decorator, inherit from Coders::Coder, and use
10
+ # +coder.encode+, +coder.decode+ to get results from base coder:
11
+ #
12
+ # class Reverse < Coders::Coder
13
+ # def encode(str); coder.encode(str).reverse; end
14
+ # def decode(str); coder.decode(str.reverse); end
15
+ # end
16
+ # coder = Reverse.new(Coder::Base64.new)
17
+ #
18
+ # If you want to customize options, be sure to call super:
19
+ #
20
+ # class MyCoder < Coders::Coder
21
+ # def initialize(gueset_coder, options = {})
22
+ # super(guest_coder)
23
+ # @options = options
24
+ # end
25
+ # end
26
+ #
27
+ class Coder < BasicObject
28
+ # Can optionally pass a base coder which is going to be decorated.
29
+ def initialize(coder = nil)
30
+ @_coder = coder
31
+ end
32
+
33
+ def coder
34
+ @_coder ||= Null.new
35
+ end
36
+
37
+ def encode(_obj)
38
+ ::Kernel.raise ::NotImplementedError
39
+ end
40
+
41
+ # It decodes +_obj+, returning decoded data,
42
+ # or +nil+ if it can't decode.
43
+ def decode(_obj)
44
+ ::Kernel.raise ::NotImplementedError
45
+ end
46
+
47
+ def raise(*args)
48
+ ::Kernel.raise(*args)
49
+ end
50
+ end
51
+
52
+ class Null < BasicObject # :nodoc:
53
+ def encode(obj)
54
+ obj
55
+ end
56
+
57
+ def decode(obj)
58
+ obj
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/coders/coder'
3
+ require 'openssl'
4
+
5
+ module CoderDecorator
6
+ module Coders
7
+ # Actuall, it doesn't encode, instead, it appends a hex HMAC to the input data
8
+ # in this format:
9
+ #
10
+ # "#{data}--#{hmac}"
11
+ #
12
+ class HMAC < Coder
13
+ REGEXP = /\A(.*)--(.*)\z/
14
+
15
+ def initialize(coder = nil, secret:, digest: 'SHA1')
16
+ super(coder)
17
+ @secret = secret
18
+ @digest = ::OpenSSL::Digest.new(digest)
19
+ end
20
+
21
+ def encode(str)
22
+ data = coder.encode(str)
23
+ hmac = generate_hmac(data)
24
+ "#{data}--#{hmac}"
25
+ end
26
+
27
+ def decode(str)
28
+ data, hmac = REGEXP.match(str)&.captures
29
+ raise InvalidEncoding unless data && hmac && secure_compare(hmac, generate_hmac(data))
30
+ coder.decode(data)
31
+ end
32
+
33
+ private
34
+
35
+ def generate_hmac(str)
36
+ ::OpenSSL::HMAC.hexdigest(@digest.new, @secret, str)
37
+ end
38
+
39
+ def secure_compare(a, b)
40
+ return false unless a.bytesize == b.bytesize
41
+ l = a.unpack('C*')
42
+ r = 0
43
+ i = -1
44
+ b.each_byte { |v| r |= v ^ l[i += 1] }
45
+ r.zero?
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/coders/coder'
3
+ module CoderDecorator
4
+ module Coders
5
+ class Identity < Coder # :nodoc:
6
+ def encode(obj)
7
+ coder.encode(obj)
8
+ end
9
+
10
+ def decode(obj)
11
+ coder.decode(obj)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/coders/coder'
3
+ require 'json'
4
+ module CoderDecorator
5
+ module Coders
6
+ class JSON < Coder # :nodoc:
7
+ def encode(obj)
8
+ ::JSON.dump(coder.encode(obj))
9
+ end
10
+
11
+ def decode(str)
12
+ coder.decode(::JSON.parse(str))
13
+ rescue ::JSON::ParserError
14
+ raise InvalidEncoding
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/coders/coder'
3
+ module CoderDecorator
4
+ module Coders
5
+ class Marshal < Coder # :nodoc:
6
+ def encode(obj)
7
+ ::Marshal.dump(coder.encode(obj))
8
+ end
9
+
10
+ def decode(str)
11
+ coder.decode(::Marshal.load(str))
12
+ rescue ::TypeError
13
+ raise InvalidEncoding
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/coders/coder'
3
+ module CoderDecorator
4
+ module Coders
5
+ # When there's exception raised, it rescues and return +nil+.
6
+ class Rescue < Coder # :nodoc:
7
+ def encode(obj)
8
+ coder.encode(obj)
9
+ end
10
+
11
+ def decode(obj)
12
+ coder.decode(obj)
13
+ rescue
14
+ nil
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ require 'coder_decorator/coders/coder'
3
+ require 'zlib'
4
+ module CoderDecorator
5
+ module Coders
6
+ class Zip < Coder # :nodoc:
7
+ def encode(str)
8
+ ::Zlib::Deflate.deflate(coder.encode(str))
9
+ end
10
+
11
+ def decode(str)
12
+ coder.decode(::Zlib::Inflate.inflate(str))
13
+ rescue ::Zlib::DataError
14
+ raise InvalidEncoding
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ module CoderDecorator
3
+ class Error < RuntimeError; end
4
+ class InvalidEncoding < Error; end
5
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: coder_decorator
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jian Weihang
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: An encoding/decoding library with decorator pattern.
56
+ email: tonytonyjan@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/coder_decorator.rb
62
+ - lib/coder_decorator/coders/base64.rb
63
+ - lib/coder_decorator/coders/cipher.rb
64
+ - lib/coder_decorator/coders/coder.rb
65
+ - lib/coder_decorator/coders/hmac.rb
66
+ - lib/coder_decorator/coders/identity.rb
67
+ - lib/coder_decorator/coders/json.rb
68
+ - lib/coder_decorator/coders/marshal.rb
69
+ - lib/coder_decorator/coders/rescue.rb
70
+ - lib/coder_decorator/coders/zip.rb
71
+ - lib/coder_decorator/errors.rb
72
+ homepage:
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.6.8
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: An encoding/decoding library with decorator pattern.
96
+ test_files: []