ruby_fints 0.0.2

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.
@@ -0,0 +1,22 @@
1
+ module FinTS
2
+ module Segment
3
+ # HKIDN (Identifikation)
4
+ # Section C.3.1.2
5
+ class HKIDN < BaseSegment
6
+ def initialize(segment_number, blz, username, system_id=0, customerid=1)
7
+ data = ["#{country_code}:#{blz}", Helper.fints_escape(username), system_id, customerid]
8
+ super(segment_number, data)
9
+ end
10
+
11
+ protected
12
+
13
+ def type
14
+ 'HKIDN'
15
+ end
16
+
17
+ def version
18
+ 2
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ module FinTS
2
+ module Segment
3
+ # HKKAZ (Kontoumsätze)
4
+ # Refs: http://www.hbci-zka.de/dokumente/spezifikation_deutsch/fintsv3/FinTS_3.0_Messages_Geschaeftsvorfaelle_2015-08-07_final_version.pdf
5
+ # Section C.2.1.1.1.2
6
+ class HKKAZ < BaseSegment
7
+ def initialize(segno, version, account, date_start, date_end, touchdown)
8
+ @version = version
9
+ data = [
10
+ account,
11
+ 'N',
12
+ date_start.strftime('%Y%m%d'),
13
+ date_end.strftime('%Y%m%d'),
14
+ '',
15
+ touchdown ? Helper.fints_escape(touchdown) : ''
16
+ ]
17
+ super(segno, data)
18
+ end
19
+
20
+ protected
21
+
22
+ def type
23
+ 'HKKAZ'
24
+ end
25
+
26
+ def version
27
+ @version
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ module FinTS
2
+ module Segment
3
+ # HKSPA (SEPA-Kontoverbindung anfordern)
4
+ # Section C.10.1.3
5
+ class HKSPA < BaseSegment
6
+ def initialize(segno, accno, subaccfeature, blz)
7
+ data = if accno.nil?
8
+ ['']
9
+ else
10
+ [[accno, subaccfeature, country_code, blz].join(':')]
11
+ end
12
+ super(segno, data)
13
+ end
14
+
15
+ protected
16
+
17
+ def type
18
+ 'HKSPA'
19
+ end
20
+
21
+ def version
22
+ 1
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ module FinTS
2
+ module Segment
3
+ # HKSYN (Synchronisation)
4
+ # Section C.8.1.2
5
+ class HKSYN < BaseSegment
6
+ SYNC_MODE_NEW_CUSTOMER_ID = 0
7
+ SYNC_MODE_LAST_MSG_NUMBER = 1
8
+ SYNC_MODE_SIGNATURE_ID = 2
9
+
10
+ def initialize(segment_no, mode: SYNC_MODE_NEW_CUSTOMER_ID)
11
+ data = [mode]
12
+ super(segment_no, data)
13
+ end
14
+
15
+ protected
16
+
17
+ def type
18
+ 'HKSYN'
19
+ end
20
+
21
+ def version
22
+ 3
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ module FinTS
2
+ module Segment
3
+ # HKVVB (Verarbeitungsvorbereitung)
4
+ # Section C.3.1.3
5
+ class HKVVB < BaseSegment
6
+ LANG_DE = 1
7
+ LANG_EN = 2
8
+ LANG_FR = 3
9
+
10
+ def initialize(segment_no, lang: LANG_DE)
11
+ data = [0, 0, lang, Helper.fints_escape(FinTS::GEM_NAME), Helper.fints_escape(FinTS::VERSION)]
12
+ super(segment_no, data)
13
+ end
14
+
15
+ protected
16
+
17
+ def type
18
+ 'HKVVB'
19
+ end
20
+
21
+ def version
22
+ 3
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ module FinTS
2
+ module Segment
3
+ # HKWPD (Depotaufstellung anfordern)
4
+ # Section C.4.3.1
5
+ # Example: HKPWD:3:7+23456::280:10020030+USD+2'
6
+ class HKWPD < BaseSegment
7
+ def initialize(segno, version, account)
8
+ # The spec allows the specification of currency and
9
+ # quality of valuations, as shown in the docstring above.
10
+ # However, both 1822direkt and CortalConsors reject the
11
+ # call if these two are present, claiming an invalid input.
12
+ # 'EUR' # Währung der Depotaufstellung"
13
+ # 2 # Kursqualität
14
+ data = [account]
15
+ super(segno, data)
16
+ @version = version
17
+ end
18
+
19
+ protected
20
+
21
+ def type
22
+ 'HKPWD'
23
+ end
24
+
25
+ def version
26
+ @version
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module FinTS
2
+ module Segment
3
+ # HNHBK (Nachrichtenkopf)
4
+ # Section B.5.2
5
+ class HNHBK < BaseSegment
6
+ HEADER_LENGTH = 29
7
+
8
+ def initialize(msglen, dialog_id, msg_no)
9
+ if msglen.to_s.length != 12
10
+ msglen = (msglen.to_i + HEADER_LENGTH + dialog_id.to_s.length + msg_no.to_s.length).to_s.rjust(12, '0')
11
+ end
12
+ data = [msglen, 300, dialog_id, msg_no]
13
+ super(1, data)
14
+ end
15
+
16
+ protected
17
+
18
+ def type
19
+ 'HNHBK'
20
+ end
21
+
22
+ def version
23
+ 3
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ module FinTS
2
+ module Segment
3
+ # HNHBS (Nachrichtenabschluss)
4
+ # Section B.5.3
5
+ class HNHBS < BaseSegment
6
+ def initialize(segno, msgno)
7
+ data = [msgno.to_s]
8
+ super(segno, data)
9
+ end
10
+
11
+ protected
12
+
13
+ def type
14
+ 'HNHBS'
15
+ end
16
+
17
+ def version
18
+ 1
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ module FinTS
2
+ module Segment
3
+ # HNSHA (Signaturabschluss)
4
+ # Section B.5.2
5
+ class HNSHA < BaseSegment
6
+ SECURITY_FUNC = 999
7
+ SECURITY_BOUNDARY = 1 # SHM
8
+ SECURITY_SUPPLIER_ROLE = 1 # ISS
9
+ PINTAN_VERSION = 1 # 1-step
10
+
11
+ def initialize(segno, secref, pin)
12
+ data = [secref, '', Helper.fints_escape(pin)]
13
+ super(segno, data)
14
+ end
15
+
16
+ protected
17
+
18
+ def type
19
+ 'HNSHA'
20
+ end
21
+
22
+ def version
23
+ 2
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ module FinTS
2
+ module Segment
3
+ # HNSHK (Signaturkopf)
4
+ # Section B.5.1
5
+ class HNSHK < BaseSegment
6
+ SECURITY_FUNC = 999
7
+ SECURITY_BOUNDARY = 1 # SHM
8
+ SECURITY_SUPPLIER_ROLE = 1 # ISS
9
+
10
+ def initialize(segno, secref, blz, username, system_id, profile_version, security_function=SECURITY_FUNC)
11
+ data = [
12
+ ['PIN', profile_version.to_s].join(':'),
13
+ security_function,
14
+ secref,
15
+ SECURITY_BOUNDARY,
16
+ SECURITY_SUPPLIER_ROLE,
17
+ ['1', '', system_id.to_s].join(':'),
18
+ 1,
19
+ ['1', Time.now.strftime('%Y%m%d'), Time.now.strftime('%H%M%S')].join(':'),
20
+ ['1', '999', '1'].join(':'), # Negotiate hash algorithm
21
+ ['6', '10', '16'].join(':'), # RSA mode
22
+ [country_code.to_s, blz, Helper.fints_escape(username), 'S', '0', '0'].join(':')
23
+ ]
24
+ super(segno, data)
25
+ end
26
+
27
+ protected
28
+
29
+ def type
30
+ 'HNSHK'
31
+ end
32
+
33
+ def version
34
+ 4
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ module FinTS
2
+ module Segment
3
+ # HNVSD (Verschlüsselte Daten)
4
+ # Section B.5.4
5
+ class HNVSD < BaseSegment
6
+ attr_reader :encoded_data
7
+
8
+ def initialize(segno, encoded_data)
9
+ @encoded_data = encoded_data
10
+ data = ["@#{encoded_data.length}@#{encoded_data}"]
11
+ super(segno, data)
12
+ end
13
+
14
+ def set_data(encoded_data)
15
+ @encoded_data = encoded_data
16
+ @data = ["@#{encoded_data.length}@#{encoded_data}"]
17
+ end
18
+
19
+ protected
20
+
21
+ def type
22
+ 'HNVSD'
23
+ end
24
+
25
+ def version
26
+ 1
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ module FinTS
2
+ module Segment
3
+ # HNVSK (Verschlüsselungskopf)
4
+ # Section B.5.3
5
+ class HNVSK < BaseSegment
6
+ COMPRESSION_NONE = 0
7
+ SECURITY_SUPPLIER_ROLE = 1 # ISS
8
+
9
+ def initialize(segno, blz, username, system_id, profile_version)
10
+ data = [
11
+ ['PIN', profile_version.to_s].join(':'),
12
+ 998,
13
+ SECURITY_SUPPLIER_ROLE,
14
+ ['1', '', system_id.to_s].join(':'),
15
+ ['1', Time.now.strftime('%Y%m%d'), Time.now.strftime('%H%M%S')].join(':'),
16
+ ['2', '2', '13', '@8@00000000', '5', '1'].join(':'),
17
+ [country_code.to_s, blz, Helper.fints_escape(username), 'S', '0', '0'].join(':'),
18
+ COMPRESSION_NONE
19
+ ]
20
+ super(segno, data)
21
+ end
22
+
23
+ protected
24
+
25
+ def type
26
+ 'HNVSK'
27
+ end
28
+
29
+ def version
30
+ 3
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module FinTS
2
+ class SegmentNotFoundError < StandardError; end
3
+ end
@@ -0,0 +1,4 @@
1
+ module FinTS
2
+ GEM_NAME = 'ruby_fints'
3
+ VERSION = '0.0.2'
4
+ end
data/lib/ruby_fints.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'base64'
2
+ require 'httparty'
3
+ require 'cmxl'
4
+ require 'logger'
5
+ require_relative 'fints/client'
6
+ require_relative 'fints/connection_error'
7
+ require_relative 'fints/dialog'
8
+ require_relative 'fints/helper'
9
+ require_relative 'fints/https_connection'
10
+ require_relative 'fints/message'
11
+ require_relative 'fints/mt535_miniparser'
12
+ require_relative 'fints/pin_tan_client'
13
+ require_relative 'fints/response'
14
+ require_relative 'fints/segment_not_found_error'
15
+ require_relative 'fints/version'
16
+ require_relative 'fints/segment/base_segment'
17
+ require_relative 'fints/segment/hkend'
18
+ require_relative 'fints/segment/hkidn'
19
+ require_relative 'fints/segment/hkkaz'
20
+ require_relative 'fints/segment/hkspa'
21
+ require_relative 'fints/segment/hksyn'
22
+ require_relative 'fints/segment/hkvvb'
23
+ require_relative 'fints/segment/hkwpd'
24
+ require_relative 'fints/segment/hnhbk'
25
+ require_relative 'fints/segment/hnhbs'
26
+ require_relative 'fints/segment/hnsha'
27
+ require_relative 'fints/segment/hnshk'
28
+ require_relative 'fints/segment/hnvsd'
29
+ require_relative 'fints/segment/hnvsk'
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'fints/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'ruby_fints'
7
+ s.version = FinTS::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Marvin Killing']
10
+ s.email = ['marvin@playtestcloud.com']
11
+ s.homepage = ''
12
+ s.summary = %q{Basic FinTS 3.0 implementation in Ruby}
13
+ s.description = %q{FinTS (formerly known as HBCI) is a protocol to programmatically interface with German banks. This gem is a translation of https://github.com/raphaelm/python-fints into Ruby.}
14
+
15
+ s.add_runtime_dependency 'cmxl', '~> 0.2'
16
+ s.add_runtime_dependency 'httparty', '~> 0.10'
17
+ s.add_development_dependency 'rake'
18
+ s.add_development_dependency 'minitest'
19
+ s.add_development_dependency 'webmock'
20
+ s.add_development_dependency 'simplecov'
21
+ s.add_development_dependency 'delorean'
22
+ s.add_development_dependency 'mocha'
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
26
+ s.require_paths = ['lib']
27
+ end
@@ -0,0 +1 @@
1
+ HNHBK:1:3+000000001881+220+1653639025+1+1653639025:1'HNSHK:2:3+900+2+1+1+2::1241978588+0+1:20120316:210842+1:999:1+6:10:16+280::1:S:0:0'HIRMG:3:2+0010::Nachricht entgegengenommen'HIRMS:4:2:4+3920::Auftraege werden nur gemaess Zwei-Schritt-Verfahren (ITAN) angenommen.:900'HIBPA:5:2:4+1+280:33020000+akf Bank Wuppertal+23+1+220'HISHV:6:2:4+N+RDH:1'HIKAZS:7:5:4+1+1+60:N:N'HIUEBS:8:4:4+1+1+14:51:53:54:67:69'HISUBS:9:5:4+1+1+9999:14:51:53:54'HISLAS:10:5:4+1+1+9999:14:04:05'HISALS:11:5:4+1+1'HIAOMS:12:1:4+1+1+J:756;24;23;24;64;15000,;EUR:208;24;23;24;64;15000,;EUR:246;24;23;24;64;15000,;EUR:440;24;23;24;64;15000,;EUR:616;24;23;24;64;15000,;EUR:752;24;23;24;64;15000,;EUR:705;24;23;24;64;15000,;EUR:203;24;23;24;64;15000,;EUR:348;24;23;24;64;15000,;EUR:056;24;23;24;64;15000,;EUR:372;24;23;24;64;15000,;EUR:380;24;23;24;64;15000,;EUR:442;24;23;24;64;15000,;EUR:528;24;23;24;64;15000,;EUR:040;24;23;24;64;15000,;EUR:620;24;23;24;64;15000,;EUR:724;24;23;24;64;15000,;EUR:826;24;23;24;64;15000,;EUR:474;24;23;24;64;15000,;EUR:352;24;23;24;64;15000,;EUR:300;24;23;24;64;15000,;EUR:250;24;23;24;64;15000,;EUR:638;24;23;24;64;15000,;EUR:254;24;23;24;64;15000,;EUR:292;24;23;24;64;15000,;EUR:312;24;23;24;64;15000,;EUR:470;24;23;24;64;15000,;EUR:196;24;23;24;64;15000,;EUR:233;24;23;24;64;15000,;EUR:428;24;23;24;64;15000,;EUR:276;24;23;24;64;15000,;EUR:578;24;23;24;64;15000,;EUR'HILASS:13:4:4+1+1+14:04:05'HIPINS:14:1:4+1+1+1+5:6:6:BENUTZER:KUNDEN:HKUEB:J:HKSUB:J:HKKAZ:N:HKSLA:J:HKTUE:J:HKTUA:J:HKTUB:N:HKTUL:J:HKAOM:J:HKTAN:N'HITANS:15:2:4+1+1+1+N:J:1:900:1:ITAN:ITAN:6:1:TAN:6:1:N:1:0:N:N:N'HIUPA:16:2:4+XXXX+0+0'HIUPD:17:4:4+10023340::280:33020000+XXXX+EUR+Jan Kahl++Jan Kahl++HKKAZ:1+HKUEB:1+HKSUB:1+HKSAL:1+HKTAN:1'HISYN:18:3:5+1241978588'HNSHA:19:1+2++XXXXX'HNHBS:20:1+1'
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class RubyFintsTest < Minitest::Test
4
+
5
+ # this test tries to go as far as it can to retrieve a list of sepa accounts.
6
+ # currently we don‘t have the fixtures to make this fully test the entire method.
7
+ def test_it_raises_when_it_gets_a_bad_response
8
+ Delorean.time_travel_to(Time.new(2017, 4, 20, 17, 17)) do
9
+ # we have to mock random number generation
10
+ Kernel.stubs(:rand).with(1000000..9999999).returns(9999999)
11
+
12
+ response = File.read(File.join(File.dirname(__FILE__), 'fixtures', 'bpd-allowedgv.txt'))
13
+ stub_request(:post, "https://banking-bb6.de/fints30")
14
+ .to_return(status: 200, body: Base64.encode64(response), headers: {})
15
+
16
+ f = FinTS::PinTanClient.new('788000111', 'my?user', 'mypw', 'https://banking-bb6.de/fints30')
17
+ FinTS::Client.logger.level = Logger::ERROR
18
+
19
+ assert_raises FinTS::SegmentNotFoundError do
20
+ f.get_sepa_accounts
21
+ end
22
+ end
23
+ end
24
+ end