epics 2.11.0 → 3.0.0.rc2

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.semaphore/semaphore.yml +17 -8
  4. data/CHANGELOG.md +103 -0
  5. data/EBICS_REFERENCES.md +169 -0
  6. data/README.md +223 -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 +511 -125
  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 +3 -15
  69. data/lib/epics/generic_request.rb +36 -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 +51 -31
  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 +3 -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 +94 -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 +51 -10
  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_spec.rb +31 -0
  202. data/spec/response_validation_spec.rb +23 -0
  203. data/spec/segmented_download_spec.rb +248 -0
  204. data/spec/{key_spec.rb → signature_algorithm/rsa_pss_spec.rb} +4 -13
  205. data/spec/support/ebics_matcher.rb +17 -9
  206. data/spec/support/ebics_shared_examples.rb +642 -0
  207. data/spec/support/h005_client_helper.rb +23 -0
  208. data/spec/upload_digest_spec.rb +69 -0
  209. data/spec/user_signature_handler_spec.rb +25 -0
  210. data/spec/version_support_error_spec.rb +76 -0
  211. data/spec/xsd/{ebics_hev.xsd → H000/ebics_hev.xsd} +0 -0
  212. data/spec/xsd/H003/ebics.xsd +11 -0
  213. data/spec/xsd/H003/ebics_keymgmt_request.xsd +555 -0
  214. data/spec/xsd/H003/ebics_keymgmt_response.xsd +131 -0
  215. data/spec/xsd/H003/ebics_orders.xsd +1811 -0
  216. data/spec/xsd/H003/ebics_request.xsd +354 -0
  217. data/spec/xsd/H003/ebics_response.xsd +161 -0
  218. data/spec/xsd/{ebics_signature.xsd → H003/ebics_signature.xsd} +0 -0
  219. data/spec/xsd/H003/ebics_types.xsd +2361 -0
  220. data/spec/xsd/H003/xmldsig-core-schema.xsd +318 -0
  221. data/spec/xsd/H004/ebics_signature.xsd +217 -0
  222. data/spec/xsd/H005/ebics_H005.xsd +11 -0
  223. data/spec/xsd/H005/ebics_keymgmt_request_H005.xsd +523 -0
  224. data/spec/xsd/H005/ebics_keymgmt_response_H005.xsd +137 -0
  225. data/spec/xsd/H005/ebics_orders_H005.xsd +2094 -0
  226. data/spec/xsd/H005/ebics_request_H005.xsd +349 -0
  227. data/spec/xsd/H005/ebics_response_H005.xsd +167 -0
  228. data/spec/xsd/H005/ebics_signature_S002.xsd +177 -0
  229. data/spec/xsd/H005/ebics_types_H005.xsd +1885 -0
  230. data/spec/xsd/H005/xmldsig-core-schema.xsd +318 -0
  231. metadata +199 -36
  232. data/lib/epics/header_request.rb +0 -58
  233. data/lib/epics/middleware/xmlsig.rb +0 -16
  234. data/lib/epics/signer.rb +0 -40
  235. data/lib/epics/x_509_certificate.rb +0 -15
  236. data/lib/letter/ini_with_certs.erb +0 -335
  237. data/spec/generic_upload_spec.rb +0 -58
  238. data/spec/hpb_spec.rb +0 -15
  239. data/spec/signer_spec.rb +0 -34
  240. /data/spec/xsd/{ebics_H004.xsd → H004/ebics_H004.xsd} +0 -0
  241. /data/spec/xsd/{ebics_keymgmt_request_H004.xsd → H004/ebics_keymgmt_request_H004.xsd} +0 -0
  242. /data/spec/xsd/{ebics_keymgmt_response_H004.xsd → H004/ebics_keymgmt_response_H004.xsd} +0 -0
  243. /data/spec/xsd/{ebics_orders_H004.xsd → H004/ebics_orders_H004.xsd} +0 -0
  244. /data/spec/xsd/{ebics_request_H004.xsd → H004/ebics_request_H004.xsd} +0 -0
  245. /data/spec/xsd/{ebics_response_H004.xsd → H004/ebics_response_H004.xsd} +0 -0
  246. /data/spec/xsd/{ebics_types_H004.xsd → H004/ebics_types_H004.xsd} +0 -0
  247. /data/spec/xsd/{xmldsig-core-schema.xsd → H004/xmldsig-core-schema.xsd} +0 -0
data/lib/epics/ptk.rb CHANGED
@@ -1,17 +1,6 @@
1
1
  class Epics::PTK < Epics::GenericRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'PTK',
7
- order_attribute: 'DZHNN',
8
- order_params: !!options[:from] && !!options[:to] ? {
9
- DateRange: {
10
- Start: options[:from],
11
- End: options[:to]
12
- }
13
- } : {},
14
- mutable: { TransactionPhase: 'Initialisation' }
15
- )
2
+ def to_xml
3
+ builder = request_factory.create_ptk(options[:from], options[:to])
4
+ builder.to_xml
16
5
  end
17
6
  end
@@ -1,6 +1,9 @@
1
1
  class Epics::Response
2
- attr_accessor :doc
3
- attr_accessor :client
2
+ # Informational body return codes. Every other 01xxxx code in Epics::Error is a
3
+ # failure -- 011001 is a negative acknowledgement, 011101 a segment underrun.
4
+ BUSINESS_OK_CODES = ['', '000000', '011000', '011301'].freeze
5
+
6
+ attr_accessor :doc, :client
4
7
 
5
8
  def initialize(client, xml)
6
9
  self.doc = Nokogiri::XML.parse(xml)
@@ -8,7 +11,7 @@ class Epics::Response
8
11
  end
9
12
 
10
13
  def technical_error?
11
- !["011000", "000000"].include?(technical_code)
14
+ !%w[011000 000000].include?(technical_code)
12
15
  end
13
16
 
14
17
  def technical_code
@@ -16,19 +19,19 @@ class Epics::Response
16
19
  end
17
20
 
18
21
  def mutable_return_code
19
- doc.xpath("//xmlns:header/xmlns:mutable/xmlns:ReturnCode", xmlns: "urn:org:ebics:H004").text
22
+ doc.xpath('//xmlns:header/xmlns:mutable/xmlns:ReturnCode', xmlns: client.urn_schema).text
20
23
  end
21
24
 
22
25
  def system_return_code
23
- doc.xpath("//xmlns:SystemReturnCode/xmlns:ReturnCode", xmlns: 'http://www.ebics.org/H000').text
26
+ doc.xpath('//xmlns:SystemReturnCode/xmlns:ReturnCode', xmlns: 'http://www.ebics.org/H000').text
24
27
  end
25
28
 
26
29
  def business_error?
27
- !["", "000000"].include?(business_code)
30
+ !BUSINESS_OK_CODES.include?(business_code)
28
31
  end
29
32
 
30
33
  def business_code
31
- doc.xpath("//xmlns:body/xmlns:ReturnCode", xmlns: "urn:org:ebics:H004").text
34
+ doc.xpath('//xmlns:body/xmlns:ReturnCode', xmlns: client.urn_schema).text
32
35
  end
33
36
 
34
37
  def ok?
@@ -36,63 +39,84 @@ class Epics::Response
36
39
  end
37
40
 
38
41
  def last_segment?
39
- !!doc.at_xpath("//xmlns:header/xmlns:mutable/*[@lastSegment='true']", xmlns: "urn:org:ebics:H004")
42
+ !!doc.at_xpath("//xmlns:header/xmlns:mutable/*[@lastSegment='true']", xmlns: client.urn_schema)
40
43
  end
41
44
 
42
45
  def segmented?
43
- !!doc.at_xpath("//xmlns:header/xmlns:mutable/xmlns:SegmentNumber", xmlns: "urn:org:ebics:H004")
46
+ !!doc.at_xpath('//xmlns:header/xmlns:mutable/xmlns:SegmentNumber', xmlns: client.urn_schema)
47
+ end
48
+
49
+ def num_segments
50
+ Integer(doc.xpath('//xmlns:header/xmlns:static/xmlns:NumSegments', xmlns: client.urn_schema).text, 10)
51
+ rescue ArgumentError => e
52
+ raise Epics::InvalidResponseError.new('NumSegments', e)
44
53
  end
45
54
 
46
55
  def return_code
47
- doc.xpath("//xmlns:ReturnCode", xmlns: "urn:org:ebics:H004").last.content
56
+ doc.xpath('//xmlns:ReturnCode', xmlns: client.urn_schema).last.content
48
57
  rescue NoMethodError
49
58
  nil
50
59
  end
51
60
 
52
61
  def report_text
53
- doc.xpath("//xmlns:ReportText", xmlns: "urn:org:ebics:H004").first.content
62
+ doc.xpath('//xmlns:ReportText', xmlns: client.urn_schema).first.content
54
63
  end
55
64
 
56
65
  def transaction_id
57
- doc.xpath("//xmlns:header/xmlns:static/xmlns:TransactionID", xmlns: 'urn:org:ebics:H004').text
66
+ doc.xpath('//xmlns:header/xmlns:static/xmlns:TransactionID', xmlns: client.urn_schema).text
58
67
  end
59
68
 
60
69
  def order_id
61
- doc.xpath("//xmlns:header/xmlns:mutable/xmlns:OrderID", xmlns: "urn:org:ebics:H004").text
70
+ doc.xpath('//xmlns:header/xmlns:mutable/xmlns:OrderID', xmlns: client.urn_schema).text
62
71
  end
63
72
 
64
73
  def digest_valid?
65
74
  authenticated = doc.xpath("//*[@authenticate='true']").map(&:canonicalize).join
66
- digest_value = doc.xpath("//ds:DigestValue", ds: "http://www.w3.org/2000/09/xmldsig#").first
75
+ digest_value = doc.xpath('//ds:DigestValue', ds: 'http://www.w3.org/2000/09/xmldsig#').first
67
76
 
68
- digest = Base64.encode64(digester.digest(authenticated)).strip
77
+ digest = Base64.encode64(OpenSSL::Digest.digest('sha256', authenticated)).strip
69
78
 
70
79
  digest == digest_value.content
71
80
  end
72
81
 
73
82
  def signature_valid?
74
- signature = doc.xpath("//ds:SignedInfo", ds: "http://www.w3.org/2000/09/xmldsig#").first.canonicalize
75
- signature_value = doc.xpath("//ds:SignatureValue", ds: "http://www.w3.org/2000/09/xmldsig#").first
83
+ key = client.bank_authentication_key
84
+ raise Epics::MissingKeyError, "The bank's authentication key" if !key
76
85
 
77
- client.bank_x.key.verify(digester, Base64.decode64(signature_value.content), signature)
86
+ signature = doc.xpath('//ds:SignedInfo', ds: 'http://www.w3.org/2000/09/xmldsig#').first.canonicalize
87
+ signature_value = doc.xpath('//ds:SignatureValue', ds: 'http://www.w3.org/2000/09/xmldsig#').first
88
+
89
+ key.verify(signature_value.content, signature)
78
90
  end
79
91
 
80
92
  def public_digest_valid?
81
- encryption_pub_key_digest = doc.xpath("//xmlns:EncryptionPubKeyDigest", xmlns: 'urn:org:ebics:H004').first
93
+ key = client.encryption_key
94
+ raise Epics::MissingKeyError, 'The encryption key' if !key
95
+
96
+ encryption_pub_key_digest = doc.xpath('//xmlns:EncryptionPubKeyDigest', xmlns: client.urn_schema).first
82
97
 
83
- client.e.public_digest == encryption_pub_key_digest.content
98
+ key.public_digest == encryption_pub_key_digest.content
84
99
  end
85
100
 
86
101
  def order_data
87
- order_data_encrypted = Base64.decode64(doc.xpath("//xmlns:OrderData", xmlns: 'urn:org:ebics:H004').first.content)
102
+ decrypt_order_data(order_data_encrypted)
103
+ end
88
104
 
89
- data = (cipher.update(order_data_encrypted) + cipher.final)
105
+ def order_data_encrypted
106
+ Base64.decode64(doc.xpath('//xmlns:OrderData', xmlns: client.urn_schema).first.content)
107
+ end
108
+
109
+ # Segments cannot be decrypted on their own, so pass all of them joined. Only the first
110
+ # response carries the transaction key.
111
+ def decrypt_order_data(order_data_encrypted)
112
+ decipher = cipher
113
+ data = decipher.update(order_data_encrypted) + decipher.final
90
114
 
91
- Zlib::Inflate.new.inflate(data)
115
+ Zlib::Inflate.inflate(data)
92
116
  end
93
117
 
94
118
  def cipher
95
- cipher = OpenSSL::Cipher.new("aes-128-cbc")
119
+ cipher = OpenSSL::Cipher.new('aes-128-cbc')
96
120
 
97
121
  cipher.decrypt
98
122
  cipher.padding = 0
@@ -101,13 +125,9 @@ class Epics::Response
101
125
  end
102
126
 
103
127
  def transaction_key
104
- transaction_key_encrypted = Base64.decode64(doc.xpath("//xmlns:TransactionKey", xmlns: 'urn:org:ebics:H004').first.content)
128
+ transaction_key_encrypted = Base64.decode64(doc.xpath('//xmlns:TransactionKey',
129
+ xmlns: client.urn_schema).first.content)
105
130
 
106
- @transaction_key ||= client.e.key.private_decrypt(transaction_key_encrypted)
131
+ @transaction_key ||= client.encryption_key.key.private_decrypt(transaction_key_encrypted)
107
132
  end
108
-
109
- def digester
110
- @digester ||= OpenSSL::Digest::SHA256.new
111
- end
112
-
113
133
  end
@@ -0,0 +1,62 @@
1
+ class Epics::Services::CryptService
2
+ def initialize
3
+ @aes_factory = Epics::Factories::Crypt::AesFactory.new
4
+ end
5
+
6
+ def encrypt(signature, data)
7
+ case signature.version
8
+ when Epics::Signature::A_VERSION_6, Epics::Signature::X_VERSION_2
9
+ signature.key.sign(data)
10
+ when Epics::Signature::A_VERSION_5
11
+ encrypt_by_rsa(signature.key, data)
12
+ end
13
+ end
14
+
15
+ def decrypt_by_key(key, encrypted)
16
+ aes = @aes_factory.create
17
+ aes.key_length = 128
18
+ aes.key = key
19
+ aes.decrypt(encrypted)
20
+ end
21
+
22
+ def encrypt_by_key(key, data)
23
+ aes = @aes_factory.create
24
+ aes.key_length = 128
25
+ aes.key = key
26
+ aes.encrypt(data)
27
+ end
28
+
29
+ def encrypt_transaction_key(key, transaction_key)
30
+ encrypt_by_rsa_public_key(key, transaction_key)
31
+ end
32
+
33
+ def hash(text, algorithm = 'sha256')
34
+ OpenSSL::Digest.digest(algorithm, text)
35
+ end
36
+
37
+ def calculate_digest(signature, algorithm = 'sha256')
38
+ exponent = signature.exponent.to_s(16)
39
+ modulus = signature.modulus.to_s(16)
40
+ key = calculate_key(exponent, modulus)
41
+
42
+ hash(key, algorithm)
43
+ end
44
+
45
+ def calculate_key(exponent, modulus)
46
+ [exponent.gsub(/^0*/,''), modulus.gsub(/^0*/,'')].map(&:downcase).join(' ')
47
+ end
48
+
49
+ def calculate_certificate_fingerprint(certificate, algorithm = 'sha256')
50
+ hash(certificate.to_der, algorithm)
51
+ end
52
+
53
+ private
54
+
55
+ def encrypt_by_rsa_public_key(key, data)
56
+ key.encrypt(data)
57
+ end
58
+
59
+ def encrypt_by_rsa(key, data)
60
+ key.private_encrypt(data)
61
+ end
62
+ end
@@ -0,0 +1,30 @@
1
+ class Epics::Services::DigestResolver::Base
2
+ def self.for_version(version)
3
+ case version
4
+ when Epics::Keyring::VERSION_24, Epics::Keyring::VERSION_25
5
+ Epics::Services::DigestResolver::V2.new
6
+ when Epics::Keyring::VERSION_30
7
+ Epics::Services::DigestResolver::V3.new
8
+ else
9
+ raise ArgumentError, "Unsupported EBICS version for DigestResolver: #{version}"
10
+ end
11
+ end
12
+
13
+ def initialize
14
+ @crypt_service = Epics::Services::CryptService.new
15
+ end
16
+
17
+ def sign_digest(signature, algorithm = 'sha256')
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def confirm_digest(signature, algorithm = 'sha256')
22
+ raise NotImplementedError
23
+ end
24
+
25
+ private
26
+
27
+ def bin2hex(date)
28
+ date.unpack1('H*')
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ class Epics::Services::DigestResolver::V2 < Epics::Services::DigestResolver::Base
2
+ def sign_digest(signature, algorithm = 'sha256')
3
+ @crypt_service.calculate_digest(signature.key, algorithm)
4
+ end
5
+
6
+ def confirm_digest(signature, algorithm = 'sha256')
7
+ bin2hex(if signature.certificate
8
+ @crypt_service.calculate_certificate_fingerprint(signature.certificate, algorithm)
9
+ else
10
+ @crypt_service.calculate_digest(signature.key, algorithm)
11
+ end)
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ class Epics::Services::DigestResolver::V3 < Epics::Services::DigestResolver::Base
2
+ def sign_digest(signature, algorithm = 'sha256')
3
+ if signature.certificate
4
+ @crypt_service.calculate_certificate_fingerprint(signature.certificate, algorithm)
5
+ else
6
+ warn '[epics] WARNING: EBICS 3.0 sign_digest falling back to key-based digest ' \
7
+ "for #{signature.version}. Bank certificate may be missing -- consider running HPB."
8
+ @crypt_service.calculate_digest(signature.key, algorithm)
9
+ end
10
+ end
11
+
12
+ def confirm_digest(signature, algorithm = 'sha256')
13
+ bin2hex(if signature.certificate
14
+ @crypt_service.calculate_certificate_fingerprint(signature.certificate, algorithm)
15
+ else
16
+ @crypt_service.calculate_digest(signature.key, algorithm)
17
+ end)
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ module Epics::Services::DigestResolver
2
+ end
3
+
4
+ require 'epics/services/digest_resolver/base'
5
+ require 'epics/services/digest_resolver/v2'
6
+ require 'epics/services/digest_resolver/v3'
@@ -0,0 +1,5 @@
1
+ module Epics::Services
2
+ end
3
+
4
+ require 'epics/services/crypt_service'
5
+ require 'epics/services/digest_resolver'
@@ -0,0 +1,50 @@
1
+ class Epics::Signature
2
+ A_VERSION_5 = 'A005'
3
+ A_VERSION_6 = 'A006'
4
+ E_VERSION_2 = 'E002'
5
+ X_VERSION_2 = 'X002'
6
+
7
+ A_VERSIONS = [A_VERSION_5, A_VERSION_6]
8
+ E_VERSIONS = [E_VERSION_2]
9
+ X_VERSIONS = [X_VERSION_2]
10
+
11
+ TYPE_A = 'A'
12
+ TYPE_X = 'X'
13
+ TYPE_E = 'E'
14
+
15
+ TYPES = [TYPE_A, TYPE_X, TYPE_E]
16
+
17
+ attr_reader :type, :version
18
+ attr_accessor :key, :certificate
19
+
20
+ def initialize(version, key)
21
+ self.key = key
22
+ self.version = version
23
+ end
24
+
25
+ def version=(value)
26
+ @type = value[0]
27
+ raise UnknownTypeError, type unless TYPES.include?(type)
28
+
29
+ @version = value
30
+ raise UnknownVersionError, version unless self.class.const_get("#{type}_VERSIONS").include?(version)
31
+ end
32
+
33
+ class UnknownVersionError < StandardError
34
+ attr_reader :version
35
+
36
+ def initialize(version)
37
+ @version = version
38
+ super("Unsupported version: #{version}")
39
+ end
40
+ end
41
+
42
+ class UnknownTypeError < StandardError
43
+ attr_reader :type
44
+
45
+ def initialize(type)
46
+ @type = type
47
+ super("Unsupported type: #{type}")
48
+ end
49
+ end
50
+ end
@@ -1,12 +1,8 @@
1
- class Epics::Key
1
+ class Epics::SignatureAlgorithm::Base
2
2
  attr_accessor :key
3
3
 
4
4
  def initialize(encoded_key, passphrase = nil)
5
- if encoded_key.kind_of?(OpenSSL::PKey::RSA)
6
- self.key = encoded_key
7
- else
8
- self.key = OpenSSL::PKey::RSA.new(encoded_key)
9
- end
5
+ self.key = encoded_key
10
6
  end
11
7
 
12
8
  ###
@@ -15,33 +11,30 @@ class Epics::Key
15
11
  # calculate digest (SHA256)
16
12
  # encode as Base64
17
13
  ####
14
+ # TODO: remove this method
18
15
  def public_digest
19
16
  c = [ e.gsub(/^0*/,''), n.gsub(/^0*/,'') ].map(&:downcase).join(" ")
20
17
 
21
18
  Base64.encode64(digester.digest(c)).strip
22
19
  end
23
20
 
24
- def n
25
- self.key.n.to_s(16)
21
+ def exponent
22
+ raise NotImplementedError
26
23
  end
27
24
 
28
- def e
29
- self.key.e.to_s(16)
25
+ def modulus
26
+ raise NotImplementedError
30
27
  end
31
28
 
32
- def sign(msg)
33
- Base64.encode64(
34
- key.sign_pss(
35
- 'SHA256',
36
- msg,
37
- salt_length: :digest,
38
- mgf1_hash: 'SHA256',
39
- ),
40
- ).gsub("\n", '')
29
+ def encrypt(data)
30
+ raise NotImplementedError
41
31
  end
42
32
 
43
- def digester
44
- @digester ||= OpenSSL::Digest::SHA256.new
33
+ def sign(msg)
34
+ raise NotImplementedError
45
35
  end
46
36
 
37
+ def verify(signature, msg)
38
+ raise NotImplementedError
39
+ end
47
40
  end
@@ -0,0 +1,50 @@
1
+ class Epics::SignatureAlgorithm::Rsa < Epics::SignatureAlgorithm::Base
2
+ HASH_ALGORITHM = 'sha256'
3
+
4
+ def initialize(encoded_key, passphrase = nil)
5
+ if encoded_key.kind_of?(OpenSSL::PKey::RSA)
6
+ self.key = encoded_key
7
+ else
8
+ self.key = OpenSSL::PKey::RSA.new(encoded_key)
9
+ end
10
+ end
11
+
12
+ def exponent
13
+ key.e
14
+ end
15
+
16
+ # TODO: remove this method
17
+ def e
18
+ exponent.to_s(16)
19
+ end
20
+
21
+ def modulus
22
+ key.n
23
+ end
24
+
25
+ # TODO: remove this method
26
+ def n
27
+ modulus.to_s(16)
28
+ end
29
+
30
+ def mgf1_hash_algorithm
31
+ OpenSSL::Digest.new(HASH_ALGORITHM)
32
+ end
33
+
34
+ def hash_algorithm
35
+ OpenSSL::Digest.new(HASH_ALGORITHM)
36
+ end
37
+
38
+ def encrypt(data)
39
+ key.public_encrypt(data)
40
+ end
41
+
42
+ def private_encrypt(data)
43
+ key.private_encrypt(data)
44
+ end
45
+
46
+ # TODO: remove this method
47
+ def digester
48
+ @digester ||= OpenSSL::Digest::SHA256.new
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ class Epics::SignatureAlgorithm::RsaPkcs1 < Epics::SignatureAlgorithm::Rsa
2
+ def sign(msg)
3
+ key.sign(
4
+ hash_algorithm,
5
+ msg
6
+ )
7
+ end
8
+
9
+ def verify(signature, msg)
10
+ key.verify(
11
+ hash_algorithm,
12
+ Base64.decode64(signature),
13
+ msg
14
+ )
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ class Epics::SignatureAlgorithm::RsaPss < Epics::SignatureAlgorithm::Rsa
2
+ def sign(msg)
3
+ key.sign_pss(
4
+ hash_algorithm,
5
+ msg,
6
+ salt_length: :digest,
7
+ mgf1_hash: mgf1_hash_algorithm,
8
+ )
9
+ end
10
+
11
+ def verify(signature, msg)
12
+ key.verify_pss(
13
+ hash_algorithm,
14
+ Base64.decode64(signature),
15
+ msg,
16
+ salt_length: :digest,
17
+ mgf1_hash: mgf1_hash_algorithm,
18
+ )
19
+ end
20
+ end
@@ -0,0 +1,2 @@
1
+ module Epics::SignatureAlgorithm
2
+ end
data/lib/epics/sta.rb CHANGED
@@ -1,17 +1,6 @@
1
1
  class Epics::STA < Epics::GenericRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'STA',
7
- order_attribute: 'DZHNN',
8
- order_params: !!options[:from] && !!options[:to] ? {
9
- DateRange: {
10
- Start: options[:from],
11
- End: options[:to]
12
- }
13
- } : {},
14
- mutable: { TransactionPhase: 'Initialisation' }
15
- )
2
+ def to_xml
3
+ builder = request_factory.create_sta(options[:from], options[:to])
4
+ builder.to_xml
16
5
  end
17
6
  end
data/lib/epics/version.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Epics
4
- VERSION = '2.11.0'
4
+
5
+ VERSION = '3.0.0.rc2'
6
+
5
7
  end
data/lib/epics/vmk.rb CHANGED
@@ -1,17 +1,6 @@
1
1
  class Epics::VMK < Epics::GenericRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'VMK',
7
- order_attribute: 'DZHNN',
8
- order_params: !!options[:from] && !!options[:to] ? {
9
- DateRange: {
10
- Start: options[:from],
11
- End: options[:to]
12
- }
13
- } : {},
14
- mutable: { TransactionPhase: 'Initialisation' }
15
- )
2
+ def to_xml
3
+ builder = request_factory.create_vmk(options[:from], options[:to])
4
+ builder.to_xml
16
5
  end
17
6
  end
data/lib/epics/wss.rb CHANGED
@@ -1,13 +1,7 @@
1
1
  class Epics::WSS < Epics::GenericRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'WSS',
7
- order_attribute: 'DZHNN',
8
- order_params: {},
9
- mutable: { TransactionPhase: 'Initialisation' }
10
- )
2
+ def to_xml
3
+ builder = request_factory.create_wss
4
+ builder.to_xml
11
5
  end
12
6
  end
13
7
 
data/lib/epics/xct.rb CHANGED
@@ -1,13 +1,6 @@
1
1
  class Epics::XCT < Epics::GenericUploadRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'XCT',
7
- order_attribute: 'OZHNN',
8
- order_params: {},
9
- num_segments: 1,
10
- mutable: { TransactionPhase: 'Initialisation' }
11
- )
2
+ def to_xml
3
+ builder = request_factory.create_xct(document_digest, transaction_key, **options)
4
+ builder.to_xml
12
5
  end
13
6
  end
data/lib/epics/xds.rb CHANGED
@@ -1,13 +1,6 @@
1
1
  class Epics::XDS < Epics::GenericUploadRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'XDS',
7
- order_attribute: 'OZHNN',
8
- order_params: {},
9
- num_segments: 1,
10
- mutable: { TransactionPhase: 'Initialisation' }
11
- )
2
+ def to_xml
3
+ builder = request_factory.create_xds(document_digest, transaction_key, **options)
4
+ builder.to_xml
12
5
  end
13
6
  end
data/lib/epics/xe2.rb CHANGED
@@ -1,13 +1,6 @@
1
1
  class Epics::XE2 < Epics::GenericUploadRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'XE2',
7
- order_attribute: 'OZHNN',
8
- order_params: {},
9
- num_segments: 1,
10
- mutable: { TransactionPhase: 'Initialisation' }
11
- )
2
+ def to_xml
3
+ builder = request_factory.create_xe2(document_digest, transaction_key, **options)
4
+ builder.to_xml
12
5
  end
13
6
  end
data/lib/epics/xe3.rb CHANGED
@@ -1,13 +1,6 @@
1
1
  class Epics::XE3 < Epics::GenericUploadRequest
2
- def header
3
- client.header_request.build(
4
- nonce: nonce,
5
- timestamp: timestamp,
6
- order_type: 'XE3',
7
- order_attribute: 'OZHNN',
8
- order_params: {},
9
- num_segments: 1,
10
- mutable: { TransactionPhase: 'Initialisation' }
11
- )
2
+ def to_xml
3
+ builder = request_factory.create_xe3(document_digest, transaction_key, **options)
4
+ builder.to_xml
12
5
  end
13
6
  end