ruby_fints 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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