Hilfe
abbrechen
Suchergebnisse werden angezeigt für 
Stattdessen suchen nach 
Meintest du: 

gelöst: Postbox-Sammeldownload

dg2210
Legende
6.256 Beiträge

Dank der REST-Schnittstelle habe ich eine saubere Lösung zum Postbox-Sammeldownload!

 

Der untenstehende Code (vorgeschlagener Name: repobosado = REstPOstBOxSAmmelDOwnload) mag als Anregung für weitere Experimente dienen.

 

Kurzer Überblick:

Benötigt wird ein aktuelles ruby und das rest-client gem (falls es auf dem eigenen PC fehlt: gem install rest-client).

 

Die Datei enthält den REST-Clienten und ein kurzes Beispielprogramm (ab Zeile 133)

 

Die Klasse ComdirectClient kapselt die Kommunikation mit der Bank,  die Schnittstellen sind:

 

login_and_get_phototan_challenge(client_id:, client_secret:, access_number:, pin: )

 

Führt Login aus und liefert die Binärdaten für ein PNG-Bild (die Photo-TAN-Challenge) zurück. Parameter: OAUTH Client und Secret, Online-Zugangsnummer, Online-Passwort

 

finalize_login(tan: )

Beendet den login-Vorgang. Parameter: Die Photo-TAN aus dem challenge-Bild

 

get_postbox_document_list

Liefert eine Liste der Dokumente in der Postbox

 

get_document_pdf_from_id(id: )

Holt das pdf-Dokument mit der gewünschten ID aus der Postbox

 

 

BEISPIEL

 

Client initialisieren, login-Vorgang starten und die PNG-Bilddaten in die Datei "tan_challenge.png" schreiben:

client = ComdirectClient.new(ClientRequestId.new)

image = client.login_and_get_phototan_challenge(client_id: OAUTH_client_id,
                                                client_secret: OAUTH_client_secret,
                                                access_number: Zugangsnummer,
                                                pin: Pin)

File.open("tan_challenge.png","w") {|f| f.write image}



PhotoTAN einlesen und TAN eingeben:

puts "Bild geschrieben, bitte TAN eingeben"
tan = gets.chomp
client.finalize_login(tan: tan)

Liste der Dokumente in der Postbox holen (und Anzahl ausgeben):

postbox_documents = client.get_postbox_document_list
puts "Anzahl Dokumente in Postbox: #{postbox_documents.length}"

Alle PDF-Dokumente downloaden, dabei den Dateinamen anpassen (Leerzeichen entfernen, Dokument-Id zum Namen hinzufügen (sonst sind die Dateinamen nicht eindeutig)

postbox_documents.each do |doc|
  next unless doc["mimeType"] == "application/pdf"
  filename = doc["name"] + doc["documentId"][-4..-1] + ".pdf"

  # Leerzeichen und Schrägstrich entfernen
  filename.tr!(' /','_')
  puts "hole #{filename}"
  pdf = client.get_document_pdf_from_id(id: doc["documentId"])
  File.open(filename,"w") {|f| f.write pdf}
end

WICHTIG:

  1. Momentan werden nur maximal 20 Dokumente heruntergeladen. ursache unbekannt.
  2. Bei TAN-Fehleingabe wird der Online-Zugang gesperrt. Falls der Dokumentabruf nicht funktioniert, dann bitte TAN-Fehlerzähler so zurücksetzen: Online-Banking starten, einloggen und eine TAN-Aktion (z.B. Aufruf Postbox) durchführen.
  3.  Momentan wird nur Photo-TAN unterstützt

Der Code:

 

require 'rest-client'
require 'json'
require 'securerandom'
require 'base64'



# Erzeugt ClientRequests mit monoton steigender requestId
class ClientRequestId
  def initialize
    @session = SecureRandom.hex(12)
    @cnt = 0
  end

  def value
    @cnt += 1
    '{"clientRequestId":{"sessionId":"' + @session +'","requestId":"' + ("%09d" % @cnt) +'"}}'
  end
end

# REST-Client
class ComdirectClient
  AUTH_URL = "https://api.comdirect.de/oauth/token"
  URL = "https://api.comdirect.de/api/"

  def initialize(clientrequest)
    @client_request = clientrequest
  end

  # 'getter' für mehrfach benutzte Daten
  def authorisation_header
     {'Authorization' => "Bearer #{@access_token}",
      'x-http-request-info' => @client_request.value
     }
  end

  def json_header
    authorisation_header.merge({'accept' => 'application/json'})
  end

  def session_object
    '{"identifier" : "' + @sessionUUID + '", "sessionTanActive": true, "activated2FA": true}'
  end

  def oauth_flow(extra_payload: {})
    payload = {client_id:  @client_id, client_secret: @client_secret}.merge(extra_payload)
    result = RestClient.post AUTH_URL, payload

    raise "fehler bei oauth-login " unless result.code == 200
    @access_token = JSON.parse(result.body)["access_token"]
  end

  def get_session_object
    result =
    begin
      RestClient.get URL + 'session/clients/user/v1/sessions', json_header
    rescue RestClient::ExceptionWithResponse => e
       puts e.response
    end
    @sessionUUID = JSON.parse(result.body)[0]["identifier"]
  end

  def get_phototan_challenge_image
    result =
      begin
       RestClient.post URL + "session/clients/user/v1/sessions/#{@sessionUUID}/validate",
          session_object, json_header.merge({'Content-Type' => 'application/json'})
      rescue RestClient::ExceptionWithResponse => e
        puts "prepare_tan_challenge: rescue"
        puts e.response
      end

    raise "prepare_tan_challenge: ungülter response code " unless result.code == 201

    @authentication_info = JSON.parse(result.headers[:x_once_authentication_info])
    raise "Nur P_TAN unterstützt" unless @authentication_info["typ"] == "P_TAN"

    Base64.decode64(@authentication_info["challenge"])
  end

  def send_tan(tan: )
    begin
      RestClient.patch URL + "session/clients/user/v1/sessions/#{@sessionUUID}",
        session_object, json_header.merge(
          {'Content-Type' => 'application/json',
           'x-once-authentication-info' => "{\"id\": #{@authentication_info["id"]}}",
           'x-once-authentication' => tan})
    rescue RestClient::ExceptionWithResponse => e
      puts "prepare_tan_challenge: rescue"
      puts e.response
    end
  end

  def login_and_get_phototan_challenge(client_id:, client_secret:, access_number:, pin:)
    @client_id = client_id
    @client_secret = client_secret
    oauth_flow(extra_payload: {grant_type: 'password', username: access_number, password: pin})
    get_session_object
    get_phototan_challenge_image
  end

  def finalize_login(tan: )
    send_tan(tan: tan)
    oauth_flow(extra_payload: {grant_type: 'cd_secondary', token: @access_token})
  end

  def get_postbox_document_list
  result =
    begin
      RestClient.get URL + "messages/clients/user/v2/documents", json_header
    rescue RestClient::ExceptionWithResponse => e
      puts "prepare_tan_challenge: rescue"
      puts e.response
    end

    raise "get_postbox_document_list: ungueltiger code" unless result.code == 200

    JSON.parse(result.body)["values"]
  end

  def get_document_pdf_from_id(id:)
    result = RestClient.get URL + "messages/v2/documents/" + id, authorisation_header.merge({'accept' => 'application/pdf'})

    raise "get_document_pdf_from_id: ungueltiger code" unless result.code == 200
    result.body
  end
end




# MAIN
client = ComdirectClient.new(ClientRequestId.new)

image = client.login_and_get_phototan_challenge(client_id: OAUTH_client_id,
                                                client_secret: OAUTH_client_secret,
                                                access_number: Zugangsnummer,
                                                pin: Pin)

File.open("tan_challenge.png","w") {|f| f.write image}

puts "Bild geschrieben, bitte TAN eingeben"
tan = gets.chomp

client.finalize_login(tan: tan)

postbox_documents = client.get_postbox_document_list

puts "Anzahl Dokumente in Postbox: #{postbox_documents.length}"

postbox_documents.each do |doc|
  next unless doc["mimeType"] == "application/pdf"
  filename = doc["name"] + doc["documentId"][-4..-1] + ".pdf"

  # Leerzeichen und Schrägstrich entfernen
  filename.tr!(' /','_')
  puts "hole #{filename}"
  pdf = client.get_document_pdf_from_id(id: doc["documentId"])
  File.open(filename,"w") {|f| f.write pdf}
end

 

0 ANTWORTEN