josebuilder 0.0.5 → 0.0.6
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 +4 -4
- data/josebuilder-0.0.0.gem +0 -0
- data/josebuilder-0.0.1.gem +0 -0
- data/josebuilder-0.0.2.gem +0 -0
- data/josebuilder-0.0.3.gem +0 -0
- data/josebuilder-0.0.4.gem +0 -0
- data/josebuilder.gemspec +19 -0
- data/lib/jose/generators/josebuilder/USAGE +8 -0
- data/lib/jose/generators/josebuilder/josebuilder_generator.rb +63 -0
- data/lib/jose/generators/josebuilder/templates/index.json.jbuilder +7 -0
- data/lib/jose/generators/josebuilder/templates/show.json.jbuilder +3 -0
- data/lib/jose/json.rb +15 -0
- data/lib/josebuilder.rb +0 -0
- data/lib/jws.rb +127 -0
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 829439b805873f4fc7316f4cb4cff959f0d3a575
|
4
|
+
data.tar.gz: e38b3821283ce3f1d46fb318b32b6fbee46f3de6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14c50307fab5e8a189c8ac785453d8eedcba47f07018c6aad24522f0132adfc3c096e322ef2d249b1fbf11f3326cec1901a6f167b8e26d0ad63294f8436c018c
|
7
|
+
data.tar.gz: 235e76fcfafc51970b4097409058e0ce1fe9db87f730d6a995569b12fb644b3c126d94170c2b6aea2960f4b60924b9ff1fe3d9ce3e2cce4915f20b3bd6e58fd4
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/josebuilder.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'josebuilder'
|
3
|
+
s.version = '0.0.6'
|
4
|
+
s.authors = ['Nguyen Ngo Dinh']
|
5
|
+
s.email = ['nguyenngodinh@outlook.com']
|
6
|
+
s.summary = 'Create JSON Signature and encryption structures'
|
7
|
+
s.description = "json signature and encryption builder"
|
8
|
+
s.homepage = 'https://github.com/nguyenngodinh/josebuilder'
|
9
|
+
s.license = 'MIT'
|
10
|
+
|
11
|
+
s.required_ruby_version = '>= 1.9.3'
|
12
|
+
|
13
|
+
s.add_dependency 'activesupport', '>= 3.0.0', '< 5'
|
14
|
+
s.add_dependency 'multi_json', '~> 1.2'
|
15
|
+
s.add_runtime_dependency 'jwt', '~> 1.4', '>= 1.4.1'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rails/generators/resource_helpers'
|
2
|
+
require 'rails/generators/named_base'
|
3
|
+
|
4
|
+
class JosebuilderGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
|
7
|
+
argument :resource_name, :type => :string, :default => "defaultResourceName"
|
8
|
+
argument :secret, :type => :string, :default => "secret"
|
9
|
+
argument :algorithm, :type => :string, :default => "HS256"
|
10
|
+
|
11
|
+
class_option :signature, :type => :boolean, :default => true,
|
12
|
+
:description => "include signature"
|
13
|
+
class_option :encryption, :type => :boolean, :default => false,
|
14
|
+
:description => "include encryption"
|
15
|
+
class_option :combination, :type => :boolean, :default => false,
|
16
|
+
:description => "combine digital signature and encryption"
|
17
|
+
|
18
|
+
def generate_json_web_signature_file
|
19
|
+
["index", "show"].each do |view|
|
20
|
+
file = filename_with_directory(view)
|
21
|
+
template filename_with_extensions(view), file
|
22
|
+
end if options.signature?
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def get_secret
|
29
|
+
secret
|
30
|
+
end
|
31
|
+
def file_name
|
32
|
+
resource_name.underscore
|
33
|
+
end
|
34
|
+
|
35
|
+
def filename_with_extensions(name)
|
36
|
+
[name, :json, :jbuilder] * '.'
|
37
|
+
end
|
38
|
+
|
39
|
+
def pluralize(count, singular, plural = nil)
|
40
|
+
word = if (count == 1 || count =~ /^1(\.0+)?$/)
|
41
|
+
singular
|
42
|
+
else
|
43
|
+
plural || singular.pluralize
|
44
|
+
end
|
45
|
+
|
46
|
+
"#{count || 0} #{word}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def filename_with_directory(file_name)
|
50
|
+
file_name = filename_with_extensions(file_name)
|
51
|
+
File.join('app/views', controller_file_path, file_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def controller_file_path
|
55
|
+
pluralize_without_count(2, resource_name)
|
56
|
+
end
|
57
|
+
def pluralize_without_count(count, noun, text=nil)
|
58
|
+
if count!=0
|
59
|
+
count == 1? "#{noun}#{text}": "#{noun.pluralize}#{text}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
json.header = {alg: "<%= algorithm %>", typ: "JWS"}
|
2
|
+
json.payload do
|
3
|
+
json.array!(@<%= controller_file_path %>) do |<%= file_name %>|
|
4
|
+
json.<%= file_name %> = <%= file_name %>.as_json
|
5
|
+
end
|
6
|
+
end
|
7
|
+
json.signature = JWS.encode(@<%= controller_file_path %>.to_a.as_json, "<%= secret %>", "<%= algorithm %>")
|
data/lib/jose/json.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module JWS
|
2
|
+
module Json
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
def decode_json(encoded_json)
|
6
|
+
JSON.parse(encoded_json)
|
7
|
+
rescue JSON::ParseError
|
8
|
+
raise JOSE::DecodeError.new("Invalid encoding")
|
9
|
+
end
|
10
|
+
|
11
|
+
def encode_json(raw)
|
12
|
+
JSON.generate(raw)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/josebuilder.rb
ADDED
File without changes
|
data/lib/jws.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
require 'jose/json'
|
4
|
+
|
5
|
+
module JWS
|
6
|
+
class DecodeError < StandardError; end
|
7
|
+
class VerificationError < DecodeError; end
|
8
|
+
extend JWS::Json
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def sign(algorithm, msg, key)
|
13
|
+
if ['HS256', 'HS384', 'HS512'].include?(algorithm)
|
14
|
+
sign_hmac(algorithm, msg, key)
|
15
|
+
else
|
16
|
+
raise NotImplementedError.new("Unsupported signing mehtod")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def sign_hmac(algorithm, msg, key)
|
21
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'Sha')), key, msg)
|
22
|
+
end
|
23
|
+
|
24
|
+
def base64url_decode(str)
|
25
|
+
str += '=' *(4 - str.length.modulo(4))
|
26
|
+
Base64.decode64(str.tr('-_', '+/'))
|
27
|
+
end
|
28
|
+
|
29
|
+
def base64url_encode(str)
|
30
|
+
Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '')
|
31
|
+
end
|
32
|
+
|
33
|
+
def encoded_header(algorithm='HS256', header_fields={})
|
34
|
+
header = {'typ' => 'JWS', 'alg' => algorithm}.merge(header_fields)
|
35
|
+
base64url_encode(encode_json(header))
|
36
|
+
end
|
37
|
+
|
38
|
+
def encoded_payload(payload)
|
39
|
+
base64url_encode(encode_json(payload))
|
40
|
+
end
|
41
|
+
|
42
|
+
def encoded_signature(signing_input, key, algorithm)
|
43
|
+
if algorithm == 'none'
|
44
|
+
''
|
45
|
+
else
|
46
|
+
signature = sign(algorithm, signing_input, key)
|
47
|
+
base64url_encode(signature)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def encode(payload, key, algorithm='HS256', header_fields={})
|
52
|
+
algorithm ||= 'none'
|
53
|
+
segments = []
|
54
|
+
segments << encoded_header(algorithm, header_fields)
|
55
|
+
segments << encoded_payload(payload)
|
56
|
+
segments << encoded_signature(segments.join('.'), key, algorithm)
|
57
|
+
segments.join('.')
|
58
|
+
end
|
59
|
+
|
60
|
+
def raw_segments(jws, verify=true)
|
61
|
+
segments = jws.split('.')
|
62
|
+
required_number_of_segments = verify ? [3] :[2,3]
|
63
|
+
raise JWS::DecodeError.new('Not enough or too many segments') unless required_number_of_segments.include? segments.length
|
64
|
+
segments
|
65
|
+
end
|
66
|
+
|
67
|
+
def decode_header_and_payload(header_segment, payload_segment)
|
68
|
+
header = decode_json(base64url_decode(header_segment))
|
69
|
+
payload = decode_json(base64url_decode(payload_segment))
|
70
|
+
[header, payload]
|
71
|
+
end
|
72
|
+
|
73
|
+
def decoded_segments(jws, verify=true)
|
74
|
+
header_segment, payload_segment, crypto_segment = raw_segments(jws, verify)
|
75
|
+
header, payload = decode_header_and_payload(header_segment, payload_segment)
|
76
|
+
signature = base64url_decode(crypto_segment.to_s) if verify
|
77
|
+
signing_input = [header_segment, payload_segment].join('.')
|
78
|
+
[header, payload, signature, signing_input]
|
79
|
+
end
|
80
|
+
|
81
|
+
def decode(jws, key=nil, verify=true, options={}, &keyfinder)
|
82
|
+
raise JWS::DecodeError.new('Nil JSON Web Signature') unless jws
|
83
|
+
header, payload, signature, signing_input = decoded_segments(jws, verify)
|
84
|
+
raise JWS::DecodeError.new('Not enough or too many segments') unless header && payload
|
85
|
+
|
86
|
+
if verify
|
87
|
+
algo, key = signature_algorithm_and_key(header, key, &keyfinder)
|
88
|
+
if options[:algorithm] && algo != options[:algorithm]
|
89
|
+
raise JWS::IncorrectAlgorithm.new('Expected a different algorithm')
|
90
|
+
end
|
91
|
+
verify_signature(algo, key, signing_input, signature)
|
92
|
+
end
|
93
|
+
|
94
|
+
return payload, header
|
95
|
+
end
|
96
|
+
|
97
|
+
def signature_algorithm_and_key(header, key, &keyfinder)
|
98
|
+
if keyfinder
|
99
|
+
key = keyfinder.call(header)
|
100
|
+
end
|
101
|
+
[header['alg'], key]
|
102
|
+
end
|
103
|
+
|
104
|
+
def verify_signature(algo, key, signing_input, signature)
|
105
|
+
begin
|
106
|
+
if ['HS256', 'HS384', 'HS512'].include?(algo)
|
107
|
+
raise JWS::VerificationError.new('Signature verification failed') unless secure_compare(signature, sign_hmac(algo, signing_input, key))
|
108
|
+
else
|
109
|
+
raise JWS::VerificationError.new('Algorithm not supported')
|
110
|
+
end
|
111
|
+
rescue OpenSSL::Pkey::PkeyError
|
112
|
+
raise JWS::VerificationError.new('Signature verification failed')
|
113
|
+
ensure
|
114
|
+
OpenSSL.errors.clear
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def secure_compare(a, b)
|
119
|
+
return false if a.nil? || b.nil? || a.empty? || b.empty? || a.bytesize != b.bytesize
|
120
|
+
l = a.unpack "C#{a.bytesize}"
|
121
|
+
|
122
|
+
res = 0
|
123
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
124
|
+
res == 0
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: josebuilder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nguyen Ngo Dinh
|
@@ -70,7 +70,20 @@ email:
|
|
70
70
|
executables: []
|
71
71
|
extensions: []
|
72
72
|
extra_rdoc_files: []
|
73
|
-
files:
|
73
|
+
files:
|
74
|
+
- josebuilder-0.0.0.gem
|
75
|
+
- josebuilder-0.0.1.gem
|
76
|
+
- josebuilder-0.0.2.gem
|
77
|
+
- josebuilder-0.0.3.gem
|
78
|
+
- josebuilder-0.0.4.gem
|
79
|
+
- josebuilder.gemspec
|
80
|
+
- lib/jose/generators/josebuilder/USAGE
|
81
|
+
- lib/jose/generators/josebuilder/josebuilder_generator.rb
|
82
|
+
- lib/jose/generators/josebuilder/templates/index.json.jbuilder
|
83
|
+
- lib/jose/generators/josebuilder/templates/show.json.jbuilder
|
84
|
+
- lib/jose/json.rb
|
85
|
+
- lib/josebuilder.rb
|
86
|
+
- lib/jws.rb
|
74
87
|
homepage: https://github.com/nguyenngodinh/josebuilder
|
75
88
|
licenses:
|
76
89
|
- MIT
|