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 +7 -0
- data/lib/coder_decorator.rb +3 -0
- data/lib/coder_decorator/coders/base64.rb +22 -0
- data/lib/coder_decorator/coders/cipher.rb +42 -0
- data/lib/coder_decorator/coders/coder.rb +62 -0
- data/lib/coder_decorator/coders/hmac.rb +49 -0
- data/lib/coder_decorator/coders/identity.rb +15 -0
- data/lib/coder_decorator/coders/json.rb +18 -0
- data/lib/coder_decorator/coders/marshal.rb +17 -0
- data/lib/coder_decorator/coders/rescue.rb +18 -0
- data/lib/coder_decorator/coders/zip.rb +18 -0
- data/lib/coder_decorator/errors.rb +5 -0
- metadata +96 -0
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,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
|
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: []
|