diff --git a/README.md b/README.md index cec6c99..5ba3f00 100644 --- a/README.md +++ b/README.md @@ -16,32 +16,28 @@ $ gem install syruppay_jose ### JWE ```ruby -require syruppay_jose - -include SyrupPay::JWE +require 'syruppay_jose' # SyrupPay가 발급하는 secret -key = '1234567890123456' +key = '12345678901234561234567890123456' # JWE header 규격 # alg : key wrap encryption algorithm. 아래 Supported JOSE encryption algorithms 참조 # enc : content encryption algorithm. 아래 Supported JOSE encryption algorithms 참조 # kid : SyrupPay가 발급하는 iss -header = {:alg=>'A128KW', :enc=>'A128CBC-HS256', :kid=>'syruppay_sample'} +header = {:alg=>'A256KW', :enc=>'A128CBC-HS256', :kid=>'syruppay_sample'} # 암호화 할 데이터 payload = '{"iss":"syruppap_sample", "exp":1300819380, "isSample":true}' # encryption and serialize -jwe_value = compact_serialization(key, header, payload} +jwe_token = SyrupPay::JsonEncryptionCompactSerialization.serialization(key, header, payload) # decryption and deserialize -actual = compact_deserialization(key, jwe_value) +actual = SyrupPay::CompactDeserialization.deserialization(key, jwe_token) ``` ### JWS ```ruby -require syruppay_jose - -include SyrupPay::JWS +require 'syruppay_jose' # SyrupPay가 발급하는 secret key = '12345678901234561234567890123456' @@ -53,10 +49,10 @@ header = {:alg=>'HS256', :kid=>'syruppay_sample'} claims = '{"iss":"syruppap_sample", "exp":1300819380, "isSample":true}' # # sign and serialize -jws_value = compact_serialization(key, header, claims} +jws_value = SyrupPay::JsonSignatureCompactSerialization.serialization(key, header, claims) # verify and deserialize -actual = compact_deserialization(key, jws_value) +actual = SyrupPay::CompactDeserialization.deserialization(key, jws_value) ``` ## Supported JOSE encryption algorithms diff --git a/lib/jose/version.rb b/lib/jose/version.rb index 948ded9..e4a6270 100644 --- a/lib/jose/version.rb +++ b/lib/jose/version.rb @@ -1,5 +1,5 @@ module SyrupPay module Jose - VERSION = "0.1.0" + VERSION = "1.0.0" end end diff --git a/lib/syruppay_jose.rb b/lib/syruppay_jose.rb index 3af5639..e33fa3b 100644 --- a/lib/syruppay_jose.rb +++ b/lib/syruppay_jose.rb @@ -1,36 +1,55 @@ require 'jose/version' require 'jose/jwe/jwe' require 'jose/jws/jws' +require 'active_support/all' module SyrupPay - module JWE - def compact_serialization_for_test(key, cek, iv, header = {}, payload) - jwe_serializer = SyrupPay::JweSerializer.new(key) - jwe_serializer.cek = cek - jwe_serializer.iv = iv - jwe_serializer.compactSerialize(header, payload) + class JsonSignatureCompactSerialization + def self.serialization(key, header = {}, claims) + jws_serializer = SyrupPay::JwsSerializer.new(key) + jws_serializer.compactSerialize(header, claims) end + end + + class JsonEncryptionCompactSerialization + def self.serialization(key, header = {}, payload) + payload = payload - def compact_serialization(key, header = {}, payload) jwe_serializer = SyrupPay::JweSerializer.new(key) jwe_serializer.compactSerialize(header, payload) end + end - def compact_deserialization(key, serialization_input) - jwe_serializer = SyrupPay::JweSerializer.new(key) - jwe_serializer.compactDeserialize serialization_input + class CompactDeserialization + class UnSupportAlgorithmError < StandardError; end + + def self.deserialization(key, serialized_src) + header_json = UrlSafeBase64.decode64(serialized_src.split('.').first) + + header = json_to_hash(header_json) + + if (jwe_algorithm?(header[:alg].try(:to_sym))) + jwe_serializer = SyrupPay::JweSerializer.new(key) + jwe_serializer.compactDeserialize serialized_src + elsif (jws_algorithm?(header[:alg].try(:to_sym))) + jws_serializer = SyrupPay::JwsSerializer.new(key) + jws_serializer.compactDeserialize serialized_src + else + raise UnSupportAlgorithmError, (header[:alg].presence||'alg(nil)')+' is not supported' + end end - end - module JWS - def compact_serialization(key, header = {}, claims) - jws_serializer = SyrupPay::JwsSerializer.new(key) - jws_serializer.compactSerialize(header, claims) + private + def self.jwe_algorithm?(alg) + SyrupPay::JweSupportAlgorithm::ALG.include? alg end - def compact_deserialization(key, serialization_input) - jws_serializer = SyrupPay::JwsSerializer.new(key) - jws_serializer.compactDeserialize serialization_input + def self.jws_algorithm?(alg) + SyrupPay::JwsSupportAlgorithm::ALG.include? alg + end + + def self.json_to_hash(json) + ActiveSupport::JSON.decode(json).with_indifferent_access end end end diff --git a/spec/syruppay_jose_spec.rb b/spec/syruppay_jose_spec.rb index a2d32d2..48482c6 100644 --- a/spec/syruppay_jose_spec.rb +++ b/spec/syruppay_jose_spec.rb @@ -1,70 +1,56 @@ require 'rspec' require 'syruppay_jose' -describe 'JWE' do - include SyrupPay::JWE - - context '#compact_serialization' do +describe 'JsonEncryptionCompactSerialization' do + context '#serialization' do it 'matches expected result' do - cek = [4, 211, 31, 197, 84, 157, 252, 254, 11, 100, - 157, 250, 63, 170, 106, 206, 107, 124, 212, 45, - 111, 107, 9, 219, 200, 177, 0, 240, 143, 156, - 44, 207].pack('C*') - - iv = [3, 22, 60, 12, 43, 67, 104, 105, 108, 108, - 105, 99, 111, 116, 104, 101].pack('C*') - payload = [76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32, 112, 114, 111, 115, 112, 101, 114, 46].pack('C*') + expected = 'Live long and prosper.' key = UrlSafeBase64.decode64('GawgguFyGrWKav7AX4VKUg'); - expected = 'eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.U0m_YmjN04DJvceFICbCVQ' + jwe_token = SyrupPay::JsonEncryptionCompactSerialization.serialization(key, {:alg => 'A128KW', :enc => 'A128CBC-HS256'}, payload) + actual = SyrupPay::CompactDeserialization.deserialization(key, jwe_token) - actual = compact_serialization_for_test(key, cek, iv, {:alg => 'A128KW', :enc => 'A128CBC-HS256'}, payload) expect(actual).to eq expected end end - context '#compact_deserialization' do + context '#deserialization' do it 'matches expected result' do - key = UrlSafeBase64.decode64('GawgguFyGrWKav7AX4VKUg'); - jwe_result = 'eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.U0m_YmjN04DJvceFICbCVQ' - + serialize_input = 'eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.InI3AtAH0bTq3uR-CZLOvqDyHt0WKBk9KPauauXysRmRWYqIorgT3Q.NmIzMWFlM2YyODAyYjMwZA.U9vntb16e_EfmPVO7SCrvx1TX4TXNzGMg5Nsw3-stuw.AOZxq-cpYQTASGYxXaogTw' expected = 'Live long and prosper.' + key = UrlSafeBase64.decode64('GawgguFyGrWKav7AX4VKUg'); - actual = compact_deserialization(key, jwe_result) + actual = SyrupPay::CompactDeserialization.deserialization(key, serialize_input) expect(actual).to eq expected end end end -describe 'JWS' do - include SyrupPay::JWS - - context '#compact_serialization' do +describe 'JsonSignatureCompactSerialization' do + context '#serialization' do it 'matches expected result' do claims = "{\"iss\":\"joe\",\n" + " \"exp\":1300819380,\n" + " \"http://example.com/is_root\":true}" + expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLAogICAiZXhwIjoxMzAwODE5MzgwLAogICAiaHR0cDovL2V4YW1wbGUuY29tL2lzX3Jvb3QiOnRydWV9.NnnMCS7jsU-kBIm3oJIc5xEHLGzzXLX6O2wVxlslAgo'; key = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" - expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLAogICAiZXhwIjoxMzAwODE5MzgwLAogICAiaHR0cDovL2V4YW1wbGUuY29tL2lzX3Jvb3QiOnRydWV9.NnnMCS7jsU-kBIm3oJIc5xEHLGzzXLX6O2wVxlslAgo" - - actual = compact_serialization(key, {:typ => 'JWT', :alg => 'HS256'}, claims) + actual = SyrupPay::JsonSignatureCompactSerialization.serialization(key, {:typ => 'JWT', :alg => 'HS256'}, claims) expect(actual).to eq expected end end - context '#compact_deserialization' do + context '#deserialization' do it 'matches expected result' do - signing = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLAogICAiZXhwIjoxMzAwODE5MzgwLAogICAiaHR0cDovL2V4YW1wbGUuY29tL2lzX3Jvb3QiOnRydWV9.NnnMCS7jsU-kBIm3oJIc5xEHLGzzXLX6O2wVxlslAgo" - key = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" - + serialized_input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLAogICAiZXhwIjoxMzAwODE5MzgwLAogICAiaHR0cDovL2V4YW1wbGUuY29tL2lzX3Jvb3QiOnRydWV9.NnnMCS7jsU-kBIm3oJIc5xEHLGzzXLX6O2wVxlslAgo'; expected = "{\"iss\":\"joe\",\n" + " \"exp\":1300819380,\n" + " \"http://example.com/is_root\":true}" + key = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" - actual = compact_deserialization(key, signing) + actual = SyrupPay::CompactDeserialization.deserialization(key, serialized_input) expect(actual).to eq expected end diff --git a/syruppay_jose.gemspec b/syruppay_jose.gemspec index e7959e7..07a4119 100644 --- a/syruppay_jose.gemspec +++ b/syruppay_jose.gemspec @@ -6,8 +6,8 @@ require 'jose/version' Gem::Specification.new do |spec| spec.name = "syruppay_jose" spec.version = SyrupPay::Jose::VERSION - spec.authors = ["byeongchan"] - spec.email = ["byeongchan.park@sk.com"] + spec.authors = ["placia"] + spec.email = ["parkgun78@gmail.com"] spec.summary = %q{JOSE for SyrupPay service's merchant} spec.description = %q{Library for SyrupPay service's merchant. @@ -18,11 +18,11 @@ Gem::Specification.new do |spec| # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or # delete this section to allow pushing this gem to any host. - if spec.respond_to?(:metadata) - spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" - else - raise "RubyGems 2.0 or newer is required to protect against public gem pushes." - end + # if spec.respond_to?(:metadata) + # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" + # else + # raise "RubyGems 2.0 or newer is required to protect against public gem pushes." + # end spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } spec.bindir = "exe"