epics 2.10.0 → 3.0.0.rc1

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.
Files changed (245) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.semaphore/semaphore.yml +17 -8
  4. data/CHANGELOG.md +97 -0
  5. data/EBICS_REFERENCES.md +169 -0
  6. data/README.md +219 -50
  7. data/lib/epics/azv.rb +3 -10
  8. data/lib/epics/b2b.rb +3 -10
  9. data/lib/epics/bka.rb +3 -14
  10. data/lib/epics/builders/body_builder/base.rb +26 -0
  11. data/lib/epics/builders/body_builder/v2.rb +9 -0
  12. data/lib/epics/builders/body_builder/v3.rb +9 -0
  13. data/lib/epics/builders/body_builder.rb +6 -0
  14. data/lib/epics/builders/data_encryption_info_builder.rb +29 -0
  15. data/lib/epics/builders/data_transfer_builder/base.rb +52 -0
  16. data/lib/epics/builders/data_transfer_builder/v2.rb +9 -0
  17. data/lib/epics/builders/data_transfer_builder/v3.rb +12 -0
  18. data/lib/epics/builders/data_transfer_builder.rb +6 -0
  19. data/lib/epics/builders/header_builder/base.rb +26 -0
  20. data/lib/epics/builders/header_builder/v2.rb +9 -0
  21. data/lib/epics/builders/header_builder/v3.rb +9 -0
  22. data/lib/epics/builders/header_builder.rb +6 -0
  23. data/lib/epics/builders/mutable_builder.rb +28 -0
  24. data/lib/epics/builders/order_details_builder/base.rb +100 -0
  25. data/lib/epics/builders/order_details_builder/v2.rb +21 -0
  26. data/lib/epics/builders/order_details_builder/v3.rb +51 -0
  27. data/lib/epics/builders/order_details_builder.rb +10 -0
  28. data/lib/epics/builders/request_builder.rb +25 -0
  29. data/lib/epics/builders/static_builder/base.rb +75 -0
  30. data/lib/epics/builders/static_builder/v2.rb +9 -0
  31. data/lib/epics/builders/static_builder/v3.rb +9 -0
  32. data/lib/epics/builders/static_builder.rb +9 -0
  33. data/lib/epics/builders/transfer_receipt_builder.rb +19 -0
  34. data/lib/epics/builders/xml_builder/base.rb +92 -0
  35. data/lib/epics/builders/xml_builder/v24.rb +31 -0
  36. data/lib/epics/builders/xml_builder/v25.rb +31 -0
  37. data/lib/epics/builders/xml_builder/v3.rb +31 -0
  38. data/lib/epics/builders/xml_builder.rb +7 -0
  39. data/lib/epics/builders.rb +13 -0
  40. data/lib/epics/c2s.rb +3 -10
  41. data/lib/epics/c52.rb +2 -14
  42. data/lib/epics/c53.rb +2 -14
  43. data/lib/epics/c54.rb +2 -14
  44. data/lib/epics/c5n.rb +3 -14
  45. data/lib/epics/ccs.rb +3 -10
  46. data/lib/epics/cct.rb +3 -10
  47. data/lib/epics/cd1.rb +3 -10
  48. data/lib/epics/cdb.rb +3 -10
  49. data/lib/epics/cdd.rb +3 -10
  50. data/lib/epics/cds.rb +3 -10
  51. data/lib/epics/cdz.rb +3 -14
  52. data/lib/epics/cip.rb +3 -10
  53. data/lib/epics/client.rb +491 -123
  54. data/lib/epics/crypt/aes.rb +56 -0
  55. data/lib/epics/crypt/x_509.rb +52 -0
  56. data/lib/epics/crypt.rb +5 -0
  57. data/lib/epics/crz.rb +3 -14
  58. data/lib/epics/factories/crypt/aes_factory.rb +5 -0
  59. data/lib/epics/factories/crypt.rb +4 -0
  60. data/lib/epics/factories/request_factory/base.rb +236 -0
  61. data/lib/epics/factories/request_factory/v2.rb +194 -0
  62. data/lib/epics/factories/request_factory/v24.rb +32 -0
  63. data/lib/epics/factories/request_factory/v25.rb +31 -0
  64. data/lib/epics/factories/request_factory/v3.rb +305 -0
  65. data/lib/epics/factories/request_factory.rb +8 -0
  66. data/lib/epics/factories.rb +5 -0
  67. data/lib/epics/fdl.rb +3 -18
  68. data/lib/epics/ful.rb +6 -0
  69. data/lib/epics/generic_request.rb +31 -92
  70. data/lib/epics/generic_upload_request.rb +14 -67
  71. data/lib/epics/haa.rb +3 -9
  72. data/lib/epics/hac.rb +3 -14
  73. data/lib/epics/handlers/auth_signature_handler.rb +102 -0
  74. data/lib/epics/handlers/order_data_handler/base.rb +98 -0
  75. data/lib/epics/handlers/order_data_handler/v2.rb +39 -0
  76. data/lib/epics/handlers/order_data_handler/v24.rb +11 -0
  77. data/lib/epics/handlers/order_data_handler/v25.rb +11 -0
  78. data/lib/epics/handlers/order_data_handler/v3.rb +41 -0
  79. data/lib/epics/handlers/order_data_handler.rb +8 -0
  80. data/lib/epics/handlers/user_signature_handler/base.rb +10 -0
  81. data/lib/epics/handlers/user_signature_handler/v2.rb +17 -0
  82. data/lib/epics/handlers/user_signature_handler/v3.rb +17 -0
  83. data/lib/epics/handlers/user_signature_handler.rb +6 -0
  84. data/lib/epics/handlers.rb +6 -0
  85. data/lib/epics/hev.rb +2 -15
  86. data/lib/epics/hia.rb +4 -55
  87. data/lib/epics/hkd.rb +3 -9
  88. data/lib/epics/hpb.rb +3 -13
  89. data/lib/epics/hpd.rb +3 -9
  90. data/lib/epics/htd.rb +3 -9
  91. data/lib/epics/ini.rb +4 -46
  92. data/lib/epics/keyring.rb +17 -0
  93. data/lib/epics/letter_renderer.rb +17 -22
  94. data/lib/epics/ptk.rb +3 -14
  95. data/lib/epics/response.rb +34 -29
  96. data/lib/epics/services/crypt_service.rb +62 -0
  97. data/lib/epics/services/digest_resolver/base.rb +30 -0
  98. data/lib/epics/services/digest_resolver/v2.rb +13 -0
  99. data/lib/epics/services/digest_resolver/v3.rb +19 -0
  100. data/lib/epics/services/digest_resolver.rb +6 -0
  101. data/lib/epics/services.rb +5 -0
  102. data/lib/epics/signature.rb +50 -0
  103. data/lib/epics/{key.rb → signature_algorithm/base.rb} +14 -21
  104. data/lib/epics/signature_algorithm/rsa.rb +50 -0
  105. data/lib/epics/signature_algorithm/rsapkcs1.rb +16 -0
  106. data/lib/epics/signature_algorithm/rsapss.rb +20 -0
  107. data/lib/epics/signature_algorithm.rb +2 -0
  108. data/lib/epics/sta.rb +3 -14
  109. data/lib/epics/version.rb +1 -1
  110. data/lib/epics/vmk.rb +3 -14
  111. data/lib/epics/wss.rb +3 -9
  112. data/lib/epics/xct.rb +3 -10
  113. data/lib/epics/xds.rb +3 -10
  114. data/lib/epics/xe2.rb +3 -10
  115. data/lib/epics/xe3.rb +3 -10
  116. data/lib/epics/xek.rb +5 -0
  117. data/lib/epics/yct.rb +6 -0
  118. data/lib/epics/z01.rb +2 -14
  119. data/lib/epics/z52.rb +2 -14
  120. data/lib/epics/z53.rb +2 -14
  121. data/lib/epics/z54.rb +2 -14
  122. data/lib/epics/zsr.rb +5 -0
  123. data/lib/epics.rb +69 -5
  124. data/lib/letter/ini.erb +27 -6
  125. data/spec/aes_spec.rb +46 -0
  126. data/spec/auth_signature_handler_spec.rb +58 -0
  127. data/spec/builders_spec.rb +616 -0
  128. data/spec/certificate_handling_spec.rb +189 -0
  129. data/spec/client_setup_block_spec.rb +41 -0
  130. data/spec/client_spec.rb +143 -91
  131. data/spec/crypt_service_spec.rb +132 -0
  132. data/spec/date_range_spec.rb +46 -0
  133. data/spec/digest_resolver_spec.rb +164 -0
  134. data/spec/fixtures/bank_x509.pem +3 -0
  135. data/spec/fixtures/xml/haa.xml +40 -1
  136. data/spec/fixtures/xml/haa_receipt.xml +33 -30
  137. data/spec/fixtures/xml/haa_response_h004.xml +4 -0
  138. data/spec/fixtures/xml/haa_response_h005.xml +38 -0
  139. data/spec/fixtures/xml/hia_request_order_data.xml +24 -1
  140. data/spec/fixtures/xml/hpb_request.xml +1 -1
  141. data/spec/fixtures/xml/hpb_response_x509.xml +16 -0
  142. data/spec/fixtures/xml/htd_order_data_h005.xml +55 -0
  143. data/spec/fixtures/xml/jruby/hia.xml +20 -22
  144. data/spec/fixtures/xml/jruby/ini.xml +1 -3
  145. data/spec/fixtures/xml/ruby/hia.xml +21 -1
  146. data/spec/fixtures/xml/ruby/ini.xml +21 -1
  147. data/spec/handlers_spec.rb +267 -0
  148. data/spec/hpb_malformed_certificate_spec.rb +36 -0
  149. data/spec/key_file_decryption_spec.rb +27 -0
  150. data/spec/key_file_preservation_spec.rb +78 -0
  151. data/spec/keyring_spec.rb +349 -0
  152. data/spec/middleware/parse_ebics_spec.rb +2 -1
  153. data/spec/order_id_spec.rb +65 -0
  154. data/spec/orders/azv_spec.rb +63 -7
  155. data/spec/orders/b2b_spec.rb +68 -3
  156. data/spec/orders/bka_spec.rb +34 -4
  157. data/spec/orders/c2s_spec.rb +62 -9
  158. data/spec/orders/c52_spec.rb +34 -4
  159. data/spec/orders/c53_spec.rb +34 -4
  160. data/spec/orders/c54_spec.rb +36 -4
  161. data/spec/orders/c5n_spec.rb +36 -4
  162. data/spec/orders/camt_parity_spec.rb +80 -0
  163. data/spec/orders/ccs_spec.rb +62 -9
  164. data/spec/orders/cct_spec.rb +83 -9
  165. data/spec/orders/cd1_spec.rb +50 -7
  166. data/spec/orders/cdb_spec.rb +64 -7
  167. data/spec/orders/cdd_spec.rb +64 -7
  168. data/spec/orders/cds_spec.rb +74 -0
  169. data/spec/orders/cdz_spec.rb +67 -4
  170. data/spec/orders/cip_spec.rb +61 -9
  171. data/spec/orders/crz_spec.rb +67 -4
  172. data/spec/orders/fdl_spec.rb +143 -13
  173. data/spec/orders/ful_spec.rb +63 -0
  174. data/spec/orders/haa_spec.rb +115 -9
  175. data/spec/orders/hac_spec.rb +89 -10
  176. data/spec/orders/hev_spec.rb +1 -6
  177. data/spec/orders/hia_spec.rb +25 -22
  178. data/spec/orders/hkd_spec.rb +23 -4
  179. data/spec/orders/hpb_spec.rb +7 -4
  180. data/spec/orders/hpd_spec.rb +23 -4
  181. data/spec/orders/htd_spec.rb +23 -4
  182. data/spec/orders/ini_spec.rb +23 -18
  183. data/spec/orders/ptk_spec.rb +27 -4
  184. data/spec/orders/sta_spec.rb +129 -11
  185. data/spec/orders/vmk_spec.rb +36 -4
  186. data/spec/orders/wss_spec.rb +29 -3
  187. data/spec/orders/x_509_certificate_spec.rb +9 -1
  188. data/spec/orders/xct_spec.rb +63 -0
  189. data/spec/orders/xds_spec.rb +13 -6
  190. data/spec/orders/xe2_spec.rb +64 -7
  191. data/spec/orders/xe3_spec.rb +64 -7
  192. data/spec/orders/xek_spec.rb +31 -0
  193. data/spec/orders/yct_spec.rb +43 -0
  194. data/spec/orders/z01_spec.rb +34 -4
  195. data/spec/orders/z52_spec.rb +34 -4
  196. data/spec/orders/z53_spec.rb +34 -4
  197. data/spec/orders/z54_spec.rb +36 -4
  198. data/spec/orders/zsr_spec.rb +31 -0
  199. data/spec/request_factory_spec.rb +444 -0
  200. data/spec/response_business_error_spec.rb +45 -0
  201. data/spec/response_validation_spec.rb +23 -0
  202. data/spec/{key_spec.rb → signature_algorithm/rsa_pss_spec.rb} +4 -13
  203. data/spec/support/ebics_matcher.rb +17 -9
  204. data/spec/support/ebics_shared_examples.rb +642 -0
  205. data/spec/support/h005_client_helper.rb +23 -0
  206. data/spec/upload_digest_spec.rb +69 -0
  207. data/spec/user_signature_handler_spec.rb +25 -0
  208. data/spec/version_support_error_spec.rb +76 -0
  209. data/spec/xsd/{ebics_hev.xsd → H000/ebics_hev.xsd} +0 -0
  210. data/spec/xsd/H003/ebics.xsd +11 -0
  211. data/spec/xsd/H003/ebics_keymgmt_request.xsd +555 -0
  212. data/spec/xsd/H003/ebics_keymgmt_response.xsd +131 -0
  213. data/spec/xsd/H003/ebics_orders.xsd +1811 -0
  214. data/spec/xsd/H003/ebics_request.xsd +354 -0
  215. data/spec/xsd/H003/ebics_response.xsd +161 -0
  216. data/spec/xsd/{ebics_signature.xsd → H003/ebics_signature.xsd} +0 -0
  217. data/spec/xsd/H003/ebics_types.xsd +2361 -0
  218. data/spec/xsd/H003/xmldsig-core-schema.xsd +318 -0
  219. data/spec/xsd/H004/ebics_signature.xsd +217 -0
  220. data/spec/xsd/H005/ebics_H005.xsd +11 -0
  221. data/spec/xsd/H005/ebics_keymgmt_request_H005.xsd +523 -0
  222. data/spec/xsd/H005/ebics_keymgmt_response_H005.xsd +137 -0
  223. data/spec/xsd/H005/ebics_orders_H005.xsd +2094 -0
  224. data/spec/xsd/H005/ebics_request_H005.xsd +349 -0
  225. data/spec/xsd/H005/ebics_response_H005.xsd +167 -0
  226. data/spec/xsd/H005/ebics_signature_S002.xsd +177 -0
  227. data/spec/xsd/H005/ebics_types_H005.xsd +1885 -0
  228. data/spec/xsd/H005/xmldsig-core-schema.xsd +318 -0
  229. metadata +200 -36
  230. data/lib/epics/header_request.rb +0 -58
  231. data/lib/epics/middleware/xmlsig.rb +0 -16
  232. data/lib/epics/signer.rb +0 -40
  233. data/lib/epics/x_509_certificate.rb +0 -15
  234. data/lib/letter/ini_with_certs.erb +0 -335
  235. data/spec/generic_upload_spec.rb +0 -58
  236. data/spec/hpb_spec.rb +0 -15
  237. data/spec/signer_spec.rb +0 -34
  238. /data/spec/xsd/{ebics_H004.xsd → H004/ebics_H004.xsd} +0 -0
  239. /data/spec/xsd/{ebics_keymgmt_request_H004.xsd → H004/ebics_keymgmt_request_H004.xsd} +0 -0
  240. /data/spec/xsd/{ebics_keymgmt_response_H004.xsd → H004/ebics_keymgmt_response_H004.xsd} +0 -0
  241. /data/spec/xsd/{ebics_orders_H004.xsd → H004/ebics_orders_H004.xsd} +0 -0
  242. /data/spec/xsd/{ebics_request_H004.xsd → H004/ebics_request_H004.xsd} +0 -0
  243. /data/spec/xsd/{ebics_response_H004.xsd → H004/ebics_response_H004.xsd} +0 -0
  244. /data/spec/xsd/{ebics_types_H004.xsd → H004/ebics_types_H004.xsd} +0 -0
  245. /data/spec/xsd/{xmldsig-core-schema.xsd → H004/xmldsig-core-schema.xsd} +0 -0
@@ -0,0 +1,102 @@
1
+ class Epics::Handlers::AuthSignatureHandler
2
+ def initialize(keyring)
3
+ @keyring = keyring
4
+ @crypt_service = Epics::Services::CryptService.new
5
+ end
6
+
7
+ def handle(xml_builder)
8
+ signature_path = "//*[@authenticate='true']"
9
+ signature_method_algorithm = 'sha256'
10
+ digest_method_algorithm = 'sha256'
11
+ canonicalization_method_algorithm = 'REC-xml-c14n-20010315'
12
+ digest_transform_algorithm = 'REC-xml-c14n-20010315'
13
+
14
+ canonicalized_header = calculate_c14n(xml_builder.xml, signature_path, digest_transform_algorithm)
15
+ canonicalized_header_hash = @crypt_service.hash(canonicalized_header, digest_method_algorithm)
16
+
17
+ # Step 1: Build AuthSignature with SignedInfo and a placeholder SignatureValue
18
+ Nokogiri::XML::Builder.new do |xml|
19
+ @xml = xml
20
+ xml.AuthSignature do
21
+ xml.send('ds:SignedInfo') do
22
+ xml.send('ds:CanonicalizationMethod', Algorithm: urn_algorithm(canonicalization_method_algorithm))
23
+ xml.send('ds:SignatureMethod', Algorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-#{signature_method_algorithm}")
24
+ xml.send('ds:Reference', URI: "#xpointer(#{signature_path})") do
25
+ xml.send('ds:Transforms') do
26
+ xml.send('ds:Transform', Algorithm: urn_algorithm(digest_transform_algorithm))
27
+ end
28
+ xml.send('ds:DigestMethod', Algorithm: "http://www.w3.org/2001/04/xmlenc##{digest_method_algorithm}")
29
+ xml.send('ds:DigestValue', Base64.strict_encode64(canonicalized_header_hash))
30
+ end
31
+ end
32
+ xml.send('ds:SignatureValue', 'PLACEHOLDER')
33
+ end
34
+ end
35
+
36
+ # Step 2: Insert AuthSignature into the actual main document (before <body>)
37
+ xml_builder.xml.parent.children.last.add_previous_sibling @xml.parent.root
38
+
39
+ # Step 3: Canonicalize ds:SignedInfo from the main document context
40
+ # This ensures namespace inheritance matches what the bank will compute
41
+ signed_info_node = xml_builder.xml.doc.at_xpath(
42
+ '//ds:SignedInfo',
43
+ 'ds' => 'http://www.w3.org/2000/09/xmldsig#'
44
+ )
45
+ c14n_mode = Nokogiri::XML::XML_C14N_1_0
46
+ canonicalized_signed_info = signed_info_node.canonicalize(c14n_mode)
47
+
48
+ # Step 4: Sign and replace placeholder with actual SignatureValue
49
+ canonicalized_signed_info_hash_encrypted = @crypt_service.encrypt(@keyring.user_authentication,
50
+ canonicalized_signed_info)
51
+ signature_value_node = xml_builder.xml.doc.at_xpath(
52
+ '//ds:SignatureValue',
53
+ 'ds' => 'http://www.w3.org/2000/09/xmldsig#'
54
+ )
55
+ signature_value_node.content = Base64.strict_encode64(canonicalized_signed_info_hash_encrypted)
56
+ end
57
+
58
+ def to_xml
59
+ @xml.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML, encoding: 'utf-8')
60
+ end
61
+
62
+ private
63
+
64
+ def urn_algorithm(algorithm, with_comments = false)
65
+ urn = case algorithm
66
+ when 'xml-exc-c14n'
67
+ 'http://www.w3.org/2001/10/'
68
+ when 'REC-xml-c14n-20010315'
69
+ 'http://www.w3.org/TR/2001/'
70
+ when 'REC-xml-c14n11-20080502'
71
+ 'http://www.w3.org/TR/2008/'
72
+ else
73
+ raise UnknownAlgorithmException, algorithm
74
+ end
75
+ urn += algorithm
76
+ urn += '#WithComments' if with_comments
77
+ urn
78
+ end
79
+
80
+ def calculate_c14n(xml, path, algorithm = 'REC-xml-c14n-20010315', with_comments = false)
81
+ mode = case algorithm
82
+ when 'xml-exc-c14n'
83
+ Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
84
+ when 'REC-xml-c14n-20010315'
85
+ Nokogiri::XML::XML_C14N_1_0
86
+ when 'REC-xml-c14n11-20080502'
87
+ Nokogiri::XML::XML_C14N_1_1
88
+ else
89
+ raise UnknownAlgorithmException, algorithm
90
+ end
91
+ xml.doc.xpath(path).map { |node| node.canonicalize(mode, nil, with_comments) }.join
92
+ end
93
+
94
+ class UnknownAlgorithmException < StandardError
95
+ attr_reader :algorithm
96
+
97
+ def initialize(algorithm)
98
+ @algorithm = algorithm
99
+ super("Unknown algorithm: #{algorithm}")
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,98 @@
1
+ class Epics::Handlers::OrderDataHandler::Base
2
+ def initialize(client)
3
+ @client = client
4
+ end
5
+
6
+ def handle_ini(signature, timestamp = Time.now.utc)
7
+ create_signature_pubbey_order_data do
8
+ @xml.SignaturePubKeyInfo do
9
+ handle_x509_data(signature)
10
+ handle_ini_signature_pubkey(signature, timestamp)
11
+ @xml.SignatureVersion signature.version
12
+ end
13
+ handle_partner_id
14
+ handle_user_id
15
+ end
16
+ end
17
+
18
+ def handle_hia(authentication, encryption, timestamp = Time.now.utc)
19
+ create_hia_request_order_data do
20
+ @xml.AuthenticationPubKeyInfo do
21
+ handle_x509_data(authentication)
22
+ handle_hia_authentication_pubkey(authentication, timestamp)
23
+ @xml.AuthenticationVersion authentication.version
24
+ end
25
+ @xml.EncryptionPubKeyInfo do
26
+ handle_x509_data(encryption)
27
+ handle_hia_encryption_pubkey(encryption, timestamp)
28
+ @xml.EncryptionVersion encryption.version
29
+ end
30
+ handle_partner_id
31
+ handle_user_id
32
+ end
33
+ end
34
+
35
+ def to_xml
36
+ @xml.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML, encoding: 'utf-8')
37
+ end
38
+
39
+ protected
40
+
41
+ def create_signature_pubbey_order_data
42
+ Nokogiri::XML::Builder.new do |xml|
43
+ @xml = xml
44
+ yield
45
+ end
46
+ end
47
+
48
+ def create_hia_request_order_data(&block)
49
+ Nokogiri::XML::Builder.new do |xml|
50
+ @xml = xml
51
+ namespaces = { xmlns: h00x_namespace }
52
+ namespaces['xmlns:ds'] = 'http://www.w3.org/2000/09/xmldsig#'
53
+ @xml.HIARequestOrderData(**namespaces, &block)
54
+ end
55
+ end
56
+
57
+ def handle_ini_signature_pubkey(signature, timestamp)
58
+ raise NotImplementedError
59
+ end
60
+
61
+ def handle_hia_authentication_pubkey(authentication, timestamp)
62
+ raise NotImplementedError
63
+ end
64
+
65
+ def handle_hia_encryption_pubkey(encryption, timestamp)
66
+ raise NotImplementedError
67
+ end
68
+
69
+ def h00x_version
70
+ raise NotImplementedError
71
+ end
72
+
73
+ def h00x_namespace
74
+ raise NotImplementedError
75
+ end
76
+
77
+ private
78
+
79
+ def handle_x509_data(signature)
80
+ return unless signature.certificate
81
+
82
+ @xml.send('ds:X509Data') do
83
+ @xml.send('ds:X509IssuerSerial') do
84
+ @xml.send('ds:X509IssuerName', signature.certificate.issuer.to_s(OpenSSL::X509::Name::RFC2253))
85
+ @xml.send('ds:X509SerialNumber', signature.certificate.serial)
86
+ end
87
+ @xml.send('ds:X509Certificate', Base64.strict_encode64(signature.certificate.to_der))
88
+ end
89
+ end
90
+
91
+ def handle_partner_id
92
+ @xml.PartnerID @client.partner_id
93
+ end
94
+
95
+ def handle_user_id
96
+ @xml.UserID @client.user_id
97
+ end
98
+ end
@@ -0,0 +1,39 @@
1
+ class Epics::Handlers::OrderDataHandler::V2 < Epics::Handlers::OrderDataHandler::Base
2
+ protected
3
+
4
+ def create_signature_pubbey_order_data
5
+ super do
6
+ namespaces = { xmlns: 'http://www.ebics.org/S001' }
7
+ namespaces['xmlns:ds'] = 'http://www.w3.org/2000/09/xmldsig#'
8
+ @xml.SignaturePubKeyOrderData **namespaces do
9
+ yield
10
+ end
11
+ end
12
+ end
13
+
14
+ def handle_ini_signature_pubkey(signature, timestamp)
15
+ handle_pubkey_value(signature, timestamp)
16
+ end
17
+
18
+ def handle_hia_authentication_pubkey(authentication, timestamp)
19
+ handle_pubkey_value(authentication, timestamp)
20
+ end
21
+
22
+ def handle_hia_encryption_pubkey(encryption, timestamp)
23
+ handle_pubkey_value(encryption, timestamp)
24
+ end
25
+
26
+ private
27
+
28
+ def handle_pubkey_value(signature, timestamp)
29
+ modulus = [signature.key.modulus.to_s(16)].pack('H*')
30
+ exponent = signature.key.exponent.to_s(2)
31
+ @xml.PubKeyValue do
32
+ @xml.send('ds:RSAKeyValue') do
33
+ @xml.send('ds:Modulus', Base64.strict_encode64(modulus))
34
+ @xml.send('ds:Exponent', Base64.strict_encode64(exponent))
35
+ end
36
+ @xml.TimeStamp timestamp.iso8601
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,11 @@
1
+ class Epics::Handlers::OrderDataHandler::V24 < Epics::Handlers::OrderDataHandler::V2
2
+ protected
3
+
4
+ def h00x_version
5
+ 'H003'
6
+ end
7
+
8
+ def h00x_namespace
9
+ 'http://www.ebics.org/H003'
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class Epics::Handlers::OrderDataHandler::V25 < Epics::Handlers::OrderDataHandler::V2
2
+ protected
3
+
4
+ def h00x_version
5
+ 'H004'
6
+ end
7
+
8
+ def h00x_namespace
9
+ 'urn:org:ebics:H004'
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ class Epics::Handlers::OrderDataHandler::V3 < Epics::Handlers::OrderDataHandler::Base
2
+ protected
3
+
4
+ def h00x_version
5
+ 'H005'
6
+ end
7
+
8
+ def h00x_namespace
9
+ 'urn:org:ebics:H005'
10
+ end
11
+
12
+ def create_signature_pubbey_order_data(&block)
13
+ super do
14
+ namespaces = { xmlns: 'http://www.ebics.org/S002' }
15
+ namespaces['xmlns:ds'] = 'http://www.w3.org/2000/09/xmldsig#'
16
+ @xml.SignaturePubKeyOrderData(**namespaces, &block)
17
+ end
18
+ end
19
+
20
+ # H005 has no raw modulus/exponent form: the key travels inside the ds:X509Data that
21
+ # handle_x509_data emits. Without a certificate the element carries no key at all.
22
+ def handle_ini_signature_pubkey(signature, _timestamp)
23
+ require_certificate!(signature, Epics::Signature::TYPE_A)
24
+ end
25
+
26
+ def handle_hia_authentication_pubkey(authentication, _timestamp)
27
+ require_certificate!(authentication, Epics::Signature::TYPE_X)
28
+ end
29
+
30
+ def handle_hia_encryption_pubkey(encryption, _timestamp)
31
+ require_certificate!(encryption, Epics::Signature::TYPE_E)
32
+ end
33
+
34
+ private
35
+
36
+ def require_certificate!(signature, type)
37
+ return if signature.certificate
38
+
39
+ raise Epics::MissingCertificateError.new(signature.version, Epics::Client::CERTIFICATE_OPTIONS[type])
40
+ end
41
+ end
@@ -0,0 +1,8 @@
1
+ module Epics::Handlers::OrderDataHandler
2
+ end
3
+
4
+ require 'epics/handlers/order_data_handler/base'
5
+ require 'epics/handlers/order_data_handler/v2'
6
+ require 'epics/handlers/order_data_handler/v24'
7
+ require 'epics/handlers/order_data_handler/v25'
8
+ require 'epics/handlers/order_data_handler/v3'
@@ -0,0 +1,10 @@
1
+ class Epics::Handlers::UserSignatureHandler::Base
2
+ def initialize(client)
3
+ @client = client
4
+ @crypt_service = Epics::Services::CryptService.new
5
+ end
6
+
7
+ def handle(digest)
8
+ raise NotImplementedError
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ class Epics::Handlers::UserSignatureHandler::V2 < Epics::Handlers::UserSignatureHandler::Base
2
+ def handle(digest)
3
+ canonicalized_user_signature_data_hash_signed = @crypt_service.encrypt(@client.keyring.user_signature, digest)
4
+
5
+ Nokogiri::XML::Builder.new do |xml|
6
+ @xml = xml
7
+ xml.UserSignatureData('xmlns' => 'http://www.ebics.org/S001', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation' => 'http://www.ebics.org/S001 http://www.ebics.org/S001/ebics_signature.xsd') do
8
+ xml.OrderSignatureData do
9
+ xml.SignatureVersion @client.keyring.user_signature.version
10
+ xml.SignatureValue Base64.strict_encode64(canonicalized_user_signature_data_hash_signed)
11
+ xml.PartnerID @client.partner_id
12
+ xml.UserID @client.user_id
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ class Epics::Handlers::UserSignatureHandler::V3 < Epics::Handlers::UserSignatureHandler::Base
2
+ def handle(digest)
3
+ canonicalized_user_signature_data_hash_signed = @crypt_service.encrypt(@client.keyring.user_signature, digest)
4
+
5
+ Nokogiri::XML::Builder.new do |xml|
6
+ @xml = xml
7
+ xml.UserSignatureData('xmlns' => 'http://www.ebics.org/S002', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation' => 'http://www.ebics.org/S002 http://www.ebics.org/S002/ebics_signature.xsd') do
8
+ xml.OrderSignatureData do
9
+ xml.SignatureVersion @client.keyring.user_signature.version
10
+ xml.SignatureValue Base64.strict_encode64(canonicalized_user_signature_data_hash_signed)
11
+ xml.PartnerID @client.partner_id
12
+ xml.UserID @client.user_id
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ module Epics::Handlers::UserSignatureHandler
2
+ end
3
+
4
+ require 'epics/handlers/user_signature_handler/base'
5
+ require 'epics/handlers/user_signature_handler/v2'
6
+ require 'epics/handlers/user_signature_handler/v3'
@@ -0,0 +1,6 @@
1
+ module Epics::Handlers
2
+ end
3
+
4
+ require 'epics/handlers/auth_signature_handler'
5
+ require 'epics/handlers/order_data_handler'
6
+ require 'epics/handlers/user_signature_handler'
data/lib/epics/hev.rb CHANGED
@@ -1,19 +1,6 @@
1
1
  class Epics::HEV < Epics::GenericRequest
2
- def root
3
- "ebicsHEVRequest"
4
- end
5
-
6
- def body
7
- Nokogiri::XML::Builder.new do |xml|
8
- xml.HostID host_id
9
- end.doc.root
10
- end
11
-
12
2
  def to_xml
13
- Nokogiri::XML::Builder.new do |xml|
14
- xml.send(root, 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation' => 'http://www.ebics.org/H000 http://www.ebics.org/H000/ebics_hev.xsd', 'xmlns' => 'http://www.ebics.org/H000') {
15
- xml.parent.add_child(body)
16
- }
17
- end.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML, encoding: 'utf-8')
3
+ builder = request_factory.create_hev
4
+ builder.to_xml
18
5
  end
19
6
  end
data/lib/epics/hia.rb CHANGED
@@ -1,62 +1,11 @@
1
1
  class Epics::HIA < Epics::GenericRequest
2
- def root
3
- "ebicsUnsecuredRequest"
4
- end
5
-
6
- def header
7
- client.header_request.build(
8
- order_type: 'HIA',
9
- order_attribute: 'DZNNN',
10
- with_bank_pubkey_digests: false,
11
- mutable: {}
12
- )
13
- end
14
-
15
- def body
16
- Nokogiri::XML::Builder.new do |xml|
17
- xml.body{
18
- xml.DataTransfer {
19
- xml.OrderData Base64.strict_encode64(Zlib::Deflate.deflate(order_data))
20
- }
21
- }
22
- end.doc.root
23
- end
24
-
25
2
  def order_data
26
- Nokogiri::XML::Builder.new do |xml|
27
- xml.HIARequestOrderData('xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', 'xmlns' => 'urn:org:ebics:H004') {
28
- xml.AuthenticationPubKeyInfo {
29
- x509_data_xml(xml, client.x_509_certificate(:x))
30
- xml.PubKeyValue {
31
- xml.send('ds:RSAKeyValue') {
32
- xml.send('ds:Modulus', Base64.strict_encode64([client.x.n].pack("H*")))
33
- xml.send('ds:Exponent', Base64.strict_encode64(client.x.key.e.to_s(2)))
34
- }
35
- }
36
- xml.AuthenticationVersion 'X002'
37
- }
38
- xml.EncryptionPubKeyInfo{
39
- x509_data_xml(xml, client.x_509_certificate(:e))
40
- xml.PubKeyValue {
41
- xml.send('ds:RSAKeyValue') {
42
- xml.send('ds:Modulus', Base64.strict_encode64([client.e.n].pack("H*")))
43
- xml.send('ds:Exponent', Base64.strict_encode64(client.e.key.e.to_s(2)))
44
- }
45
- }
46
- xml.EncryptionVersion 'E002'
47
- }
48
- xml.PartnerID partner_id
49
- xml.UserID user_id
50
- }
51
- end.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML, encoding: 'utf-8')
3
+ order_data = order_data_handle.handle_hia(client.keyring.user_authentication, client.keyring.user_encryption)
4
+ order_data.to_xml
52
5
  end
53
6
 
54
7
  def to_xml
55
- Nokogiri::XML::Builder.new do |xml|
56
- xml.send(root, 'xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', 'xmlns' => 'urn:org:ebics:H004', 'Version' => 'H004', 'Revision' => '1') {
57
- xml.parent.add_child(header)
58
- xml.parent.add_child(body)
59
- }
60
- end.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML, encoding: 'utf-8')
8
+ builder = request_factory.create_hia(order_data)
9
+ builder.to_xml
61
10
  end
62
11
  end
data/lib/epics/hkd.rb CHANGED
@@ -1,12 +1,6 @@
1
1
  class Epics::HKD < Epics::GenericRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'HKD',
7
- order_attribute: 'DZHNN',
8
- order_params: {},
9
- mutable: { TransactionPhase: 'Initialisation' }
10
- )
2
+ def to_xml
3
+ builder = request_factory.create_hkd
4
+ builder.to_xml
11
5
  end
12
6
  end
data/lib/epics/hpb.rb CHANGED
@@ -1,16 +1,6 @@
1
1
  class Epics::HPB < Epics::GenericRequest
2
- def root
3
- "ebicsNoPubKeyDigestsRequest"
4
- end
5
-
6
- def header
7
- client.header_request.build(
8
- nonce: nonce,
9
- timestamp: timestamp,
10
- order_type: 'HPB',
11
- order_attribute: 'DZHNN',
12
- with_bank_pubkey_digests: false,
13
- mutable: {}
14
- )
2
+ def to_xml
3
+ builder = request_factory.create_hpb
4
+ builder.to_xml
15
5
  end
16
6
  end
data/lib/epics/hpd.rb CHANGED
@@ -1,12 +1,6 @@
1
1
  class Epics::HPD < Epics::GenericRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'HPD',
7
- order_attribute: 'DZHNN',
8
- order_params: {},
9
- mutable: { TransactionPhase: 'Initialisation' }
10
- )
2
+ def to_xml
3
+ builder = request_factory.create_hpd
4
+ builder.to_xml
11
5
  end
12
6
  end
data/lib/epics/htd.rb CHANGED
@@ -1,12 +1,6 @@
1
1
  class Epics::HTD < Epics::GenericRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'HTD',
7
- order_attribute: 'DZHNN',
8
- order_params: {},
9
- mutable: { TransactionPhase: 'Initialisation' }
10
- )
2
+ def to_xml
3
+ builder = request_factory.create_htd
4
+ builder.to_xml
11
5
  end
12
6
  end
data/lib/epics/ini.rb CHANGED
@@ -1,53 +1,11 @@
1
1
  class Epics::INI < Epics::GenericRequest
2
- def root
3
- "ebicsUnsecuredRequest"
4
- end
5
-
6
- def header
7
- client.header_request.build(
8
- order_type: 'INI',
9
- order_attribute: 'DZNNN',
10
- with_bank_pubkey_digests: false,
11
- mutable: {},
12
- )
13
- end
14
-
15
- def body
16
- Nokogiri::XML::Builder.new do |xml|
17
- xml.body{
18
- xml.DataTransfer {
19
- xml.OrderData Base64.strict_encode64(Zlib::Deflate.deflate(key_signature))
20
- }
21
- }
22
- end.doc.root
23
- end
24
-
25
2
  def key_signature
26
- Nokogiri::XML::Builder.new do |xml|
27
- xml.SignaturePubKeyOrderData('xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', 'xmlns' => 'http://www.ebics.org/S001') {
28
- xml.SignaturePubKeyInfo {
29
- x509_data_xml(xml, client.x_509_certificate(:a))
30
- xml.PubKeyValue {
31
- xml.send('ds:RSAKeyValue') {
32
- xml.send('ds:Modulus', Base64.strict_encode64([client.a.n].pack("H*")))
33
- xml.send('ds:Exponent', Base64.strict_encode64(client.a.key.e.to_s(2)))
34
- }
35
- xml.TimeStamp timestamp
36
- }
37
- xml.SignatureVersion 'A006'
38
- }
39
- xml.PartnerID partner_id
40
- xml.UserID user_id
41
- }
42
- end.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML, encoding: 'utf-8')
3
+ order_data = order_data_handle.handle_ini(client.keyring.user_signature)
4
+ order_data.to_xml
43
5
  end
44
6
 
45
7
  def to_xml
46
- Nokogiri::XML::Builder.new do |xml|
47
- xml.send(root, 'xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', 'xmlns' => 'urn:org:ebics:H004', 'Version' => 'H004', 'Revision' => '1') {
48
- xml.parent.add_child(header)
49
- xml.parent.add_child(body)
50
- }
51
- end.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML, encoding: 'utf-8')
8
+ builder = request_factory.create_ini(key_signature)
9
+ builder.to_xml
52
10
  end
53
11
  end
@@ -0,0 +1,17 @@
1
+ class Epics::Keyring
2
+ VERSION_24 = 'H003'
3
+ VERSION_25 = 'H004'
4
+ VERSION_30 = 'H005'
5
+
6
+ VERSIONS = [VERSION_24, VERSION_25, VERSION_30]
7
+
8
+ attr_reader :version
9
+ attr_accessor :user_signature, :user_encryption, :user_authentication
10
+ attr_accessor :bank_encryption, :bank_authentication
11
+
12
+ def initialize(version)
13
+ raise ArgumentError, "Unsupported version: #{version}" unless VERSIONS.include?(version)
14
+
15
+ @version = version
16
+ end
17
+ end
@@ -5,6 +5,12 @@ class Epics::LetterRenderer
5
5
 
6
6
  def initialize(client)
7
7
  @client = client
8
+ @digest_resolver = case client.version
9
+ when Epics::Keyring::VERSION_24, Epics::Keyring::VERSION_25
10
+ Epics::Services::DigestResolver::V2.new
11
+ when Epics::Keyring::VERSION_30
12
+ Epics::Services::DigestResolver::V3.new
13
+ end
8
14
  end
9
15
 
10
16
  def translate(key, **options)
@@ -13,30 +19,19 @@ class Epics::LetterRenderer
13
19
 
14
20
  alias t translate
15
21
 
16
- def_delegators :@client, :host_id, :user_id, :partner_id, :a, :x, :e
22
+ def_delegators :@digest_resolver, :confirm_digest
23
+ def_delegators :@client, :keyring,
24
+ :host_id, :user_id, :partner_id,
25
+ :signature_version, :signature_key,
26
+ :encryption_version, :encryption_key,
27
+ :authentication_version, :authentication_key
28
+
29
+ alias_method :a, :signature_key
30
+ alias_method :e, :encryption_key
31
+ alias_method :x, :authentication_key
17
32
 
18
33
  def render(bankname)
19
- template_path = File.join(File.dirname(__FILE__), '../letter/', template_filename)
34
+ template_path = File.join(File.dirname(__FILE__), '../letter/ini.erb')
20
35
  ERB.new(File.read(template_path)).result(binding)
21
36
  end
22
-
23
- def template_filename
24
- use_x_509_certificate_template? ? 'ini_with_certs.erb' : 'ini.erb'
25
- end
26
-
27
- def use_x_509_certificate_template?
28
- x_509_certificate_a_hash && x_509_certificate_x_hash && x_509_certificate_e_hash
29
- end
30
-
31
- def x_509_certificate_a_hash
32
- @client.x_509_certificate_hash(:a)
33
- end
34
-
35
- def x_509_certificate_x_hash
36
- @client.x_509_certificate_hash(:x)
37
- end
38
-
39
- def x_509_certificate_e_hash
40
- @client.x_509_certificate_hash(:e)
41
- end
42
37
  end