Einführung
Warum Web Scraping?
Viele Banken betreiben mittlerweile einen FinTS/HBCI-Server für Finanzsoftware. Einige Banken bieten jedoch leider überhaupt keine maschinenlesbare Schnittstelle an, über die eine Finanzsoftware (wie MoneyMoney) die Umsätze abrufen könnte. In so einem Fall können die Umsätze von einer Finanzsoftware nur mittels Web Scraping von der Website der Bank heruntergeladen werden.
Die Web Banking Engine
Die Web Banking Engine von MoneyMoney besteht aus einem recht umfangreichen Kern, der in C und Objective-C implementiert ist. Der Kern wird durch mehrere schlanke Extensions ergänzt. Diese Web Banking Extensions sind kurze Lua-Skripte, die einfach zu erstellen, zu modifizieren und auszuwechseln sind. Die Lua-Skripte werden von der Web Banking Engine in einer virtuellen Maschine ausgeführt und kommunizieren über eine dokumentierte API mit MoneyMoney. Das vorliegende Dokument spezifiziert diese API.
Die Wahl der Skriptsprache fiel auf Lua, da sie relativ leicht zu erlernen ist und sich gut mit C/C++/Objective-C kombinieren lässt. Für unsere Extensions reicht es vollkommen aus, die ersten fünf Kapitel von »Programming in Lua« gelesen zu haben. Die meisten innerhalb einer Extension aufgerufenen Funktionen sind nämlich gar nicht Bestandteil von Lua, sondern existieren ausschließlich in MoneyMoney.
Ein Praxisbeispiel
Das folgende Stück Lua-Code soll einen Eindruck davon vermitteln, wie eine Web Banking Extension in der Praxis vorgeht:
➊ connection = Connection()
html = HTML(connection:get("/onlinebanking"))
➋ html:xpath("//input[@name='kontonummer']"):attr("value", username)
html:xpath("//input[@name='pin']"):attr("value", password)
➌ connection:request(html:xpath("//input[@name='loginbutton']"):click())
Zuerst wird die Login-Seite vom Server geholt und aus ihrem HTML-Code eine Baumstruktur aufgebaut ➊. Mit Hilfe dieser Baumstruktur wird im HTML-Dokument mit XPath-Ausdrücken zu den Texteingabefeldern navigiert. Deren HTML-Attribute value werden dann mit den Anmeldedaten ausgefüllt ➋. Danach wird das Login-Formular abgeschickt ➌. Offensichtlich sind nur wenige Code-Zeilen notwendig, um den typischen Anmeldevorgang beim Online-Banking durchzuführen.
Das Skript erzeugt das gleiche Ergebnis, also die gleiche Serverkommunikation, wie sie ein Mensch mit einem Webbrowser beim Ausfüllen derselben Login-Seite erzeugen würde. Die Web Banking Engine kann man daher mit einem automatisch gesteuerten Webbrowser vergleichen.
Vom Skript zur Extension
Installation
Das Verzeichnis, in dem eigene Extensions abgelegt werden, kann über Menü Hilfe → Zeige Datenbank im Finder im Finder geöffnet werden:
~/Library/Containers/com.moneymoney-app.retail/Data/Library/Application Support/MoneyMoney/Extensions
Jede Änderung an Dateien in diesem Verzeichnis wirkt sich unmittelbar auf die Web Banking Engine aus, d.h. es ist nicht nötig, MoneyMoney neu zu starten.
Fehlermeldungen werden im Protokoll-Fenster von MoneyMoney angezeigt. Das Protokoll-Fenster lässt sich mit der Menüfunktion »Fenster« → »Protokollfenster« erreichen.
Hinweis: Für die Entwicklung eigener Extensions lässt sich die Überprüfung der digitalen Signatur in den Einstellungen von MoneyMoney ausschalten. Die Option lässt sich mit der Menüfunktion »MoneyMoney« → »Einstellungen« → »Erweiterungen« → »Digitale Signatur von Extensions überprüfen« erreichen.
Registrierung einer Extension
Ein Skript weist sich als Web Banking Extension aus, indem es am Beginn des Skripts einen Aufruf der Art
WebBanking{
version = 1.00,
url = "/onlinebanking",
services = {"Premium Account"},
description = "Demo"
}
enthält. Bei den benannten Parametern der Funktion WebBanking handelt es sich um:
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
version | Number | nein | Versionsnummer der Extension |
url | String | ja | URL der Einstiegsseite des Online-Bankings |
services | Array | ja | Die in diesem Array enthaltenen Service-Namen werden in MoneyMoney in der Auswahlliste beim Anlegen eines Kontos angezeigt. |
description | String | ja | Beschreibung der Extension |
Zugangsdaten und Feldbeschriftungen
Beim Einrichten eines Bankzugangs fragt MoneyMoney die Zugangsdaten in einem Dialog ab. Der Dialog besteht aus einem Feld für den Benutzernamen, einem Feld für das Passwort und bei Bedarf bis zu zwei weiteren Feldern, z. B. für eine Kundennummer oder ein API-Secret. Die Beschriftungen dieser Felder (»E-Mail-Adresse«, »Teilnehmernummer«, »API-Key« usw.), ihre Anzahl und Reihenfolge, die Eingaberegeln (Länge, nur Ziffern) und ob überhaupt ein Passwort abgefragt wird, sind Bankparameter, die MoneyMoney zentral für jeden Service-Namen pflegt. Sie sind nicht Bestandteil des Aufrufs von WebBanking und können von der Extension nicht gesetzt werden.
Für einen neuen Service-Namen gelten die Standardwerte: ein Feld »Benutzername«, ein Feld »Passwort«, keine weiteren Felder. Wer für eine Community-Extension andere Beschriftungen oder zusätzliche Felder benötigt, teilt sie bei der Einreichung der Extension mit; sie werden dann in die Bankdatenbank von MoneyMoney aufgenommen und mit dem nächsten Update an alle Anwender verteilt.
Die Reihenfolge der Felder im Dialog entspricht der Reihenfolge, in der die Werte an das Skript übergeben werden: als Parameter username, customer, password und credential von InitializeSession bzw. als Elemente des Arrays credentials von InitializeSession2, wobei Felder, die der Bankzugang nicht besitzt, im Array ausgelassen werden.
Lua-Laufzeitumgebung
Die Parameter der Funktion WebBanking sind später im Skript als globale Variablen version, url, services und description zugänglich. Zusätzlich ist auch noch die globale Variable extensionName mit dem Namen der Extension definiert.
Die Variablen MM.productName und MM.productVersion enthalten Informationen zur Anwendung, also MoneyMoney.
Die Ausgabe der Standard-Funktion print wird im Protokoll-Fenster von MoneyMoney angezeigt.
Die Standard-Funktion error bricht die Ausführung des Skripts ab. Die Fehlermeldung wird im Protokoll-Fenster und je nach Kontext auch in einem GUI-Dialog angezeigt.
Das Objekt LocalStorage kann über die Laufzeit des Skripts hinaus zur Speicherung von Informationen genutzt werden.
Das Skript selbst muss UTF-8-kodiert sein und es werden auch alle Strings als UTF-8-Strings zwischen dem Skript und MoneyMoney übergeben, außer es steht in der API-Beschreibung, dass es sich um Binärdaten handelt.
Ablauf
Die Web Banking Engine treibt die Ausführung des Skripts, was bedeutet, dass jedes Skript bestimmte Funktionen als Einsprungspunkte zur Verfügung stellen muss.
Es gibt zwei Anwendungsfälle, für die MoneyMoney die Web Banking Engine startet.
Für den Anwendungsfall Bankzugang einrichten ruft die Web Banking Engine nacheinander folgende Funktionen des Skripts auf:
SupportsBank(Klärung der Zuständigkeit)InitializeSession(Anmeldung)ListAccounts(Auflistung der verfügbaren Konten)- für jedes Konto:
RefreshAccount(Aktualisierung eines Kontos) EndSession(Abmeldung)
Der Anwendungsfall Kontenrundruf läuft ähnlich ab:
SupportsBank(Klärung der Zuständigkeit)InitializeSession(Anmeldung)- für jedes Konto:
RefreshAccount(Aktualisierung eines Kontos) EndSession(Abmeldung)
Die einzelnen Einsprungspunkte sind im Referenzteil dokumentiert.
Vorlage
Folgende Vorlage kann als Ausgangspunkt für eigene Web Banking Extensions dienen.
WebBanking{
version = 1.00,
url = "/onlinebanking",
services = {"Premium Account"},
description = "Demo"
}
function SupportsBank (protocol, bankCode)
return protocol == ProtocolWebBanking and bankCode == "Premium Account"
end
function InitializeSession (protocol, bankCode, username, customer, password)
-- Login.
end
function ListAccounts (knownAccounts)
-- Return array of accounts.
local account = {
name = "Premium Account",
owner = "Jane Doe",
accountNumber = "111222333444",
bankCode = "80007777",
currency = "EUR",
type = AccountTypeGiro
}
return {account}
end
function RefreshAccount (account, since)
-- Return balance and array of transactions.
local transaction = {
bookingDate = 1325764800,
purpose = "Hello World!",
amount = 42.00
}
return {balance=42.00, transactions={transaction}}
end
function EndSession ()
-- Logout.
end
Tipp: Um während der Entwicklung einer Extension nicht bei jeder Skriptänderung die Kontoeinrichtung von MoneyMoney durchlaufen zu müssen, kann man ListAccounts wie in der Vorlage statische Informationen zurückgeben lassen. Wenn man dann erst einmal die Funktionen InitializeSession und EndSession implementiert hat, kann man sich in Ruhe den Funktionen ListAccounts und RefreshAccount widmen.
Tipp: In der Anfangsphase der Entwicklung einer Extension ist es gar nicht nötig, eine Online-Verbindung aufzubauen. Vorab mit einem Browser gespeicherte HTML-Seiten können über Lua-Funktionen geladen werden, so dass man gefahrlos mit dem Skript experimentieren kann.
Einsprungspunkte
SupportsBank
function SupportsBank (protocol, bankCode)
Klärt die Zuständigkeit: Um herauszufinden, welche Extension für welchen Bankzugang zuständig ist, ruft die Web Banking Engine diese Funktion auf.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
protocol | Konstante | nein | Protokoll des Bankzugangs. Mögliche Werte sind ProtocolFinTS und ProtocolWebBanking. Der erste Wert ist dazu gedacht, einen FinTS/HBCI-Bankzugang um Konten zu bereichern, die von der Bank nicht über das FinTS/HBCI-Protokoll zur Verfügung gestellt werden. Der zweite Wert ist für Bankzugänge gedacht, die ausschließlich über Web Scraping abgefragt werden. |
bankCode | String | nein | Bankleitzahl oder Service-Name |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
| — | Boolean oder String | false, wenn die Extension für den besagten Bankzugang das Web Scraping nicht übernehmen kann. true, wenn die Extension für den besagten Bankzugang das Web Scraping übernehmen kann. Anstelle von true kann auch die URL der Einstiegsseite des Online-Bankings zurückgegeben werden. |
InitializeSession
function InitializeSession (protocol, bankCode, username, customer, password, credential)
Führt einen einfachen Anmeldevorgang durch.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
protocol | Konstante | nein | Protokoll des Bankzugangs. Mögliche Werte sind ProtocolFinTS und ProtocolWebBanking. |
bankCode | String | nein | Bankleitzahl oder Service-Name |
username | String | nein | Inhalt des ersten Eingabefelds des Anmeldedialogs (Benutzername) |
customer | String | nein | Inhalt des zweiten Eingabefelds (z. B. Kundennummer). Leer, wenn der Bankzugang kein solches Feld besitzt. Siehe Abschnitt »Zugangsdaten und Feldbeschriftungen«. |
password | String | nein | Passwort |
credential | String | ja | Inhalt des dritten Eingabefelds (z. B. API-Secret). Leer, wenn der Bankzugang kein solches Feld besitzt. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
| — | nil | Nichts oder nil, wenn die Anmeldung erfolgreich war. |
| — | Konstante | LoginFailed, wenn die Zugangsdaten vom Server abgewiesen wurden. Um eine Sperrung des Passworts durch den Server zu vermeiden, werden die betroffenen Konten durch MoneyMoney nicht mehr automatisch aktualisiert, bis die Zugangsdaten durch den Anwender erneut eingegeben wurden. |
| — | String | Eine Fehlermeldung. |
Siehe auch: InitializeSession2
InitializeSession2
function InitializeSession2 (protocol, bankCode, step, credentials, interactive, hbciTanMethods, session)
Diese Alternative zur Funktion InitializeSession führt einen Anmeldevorgang mit Zwei-Faktor-Authentifizierung durch. Beim ersten Aufruf (step=1) enthält credentials die Zugangsdaten. Gibt die Funktion eine Tabelle mit einer Aufforderung zur Zwei-Faktor-Authentifizierung zurück, zeigt MoneyMoney den passenden Dialog an und ruft die Funktion anschließend mit erhöhtem step erneut auf; credentials enthält dann die Antwort des Anwenders. Das wiederholt sich, bis die Funktion nil, LoginFailed oder eine Fehlermeldung zurückgibt.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
protocol | Konstante | nein | Protokoll des Bankzugangs. Mögliche Werte sind ProtocolFinTS und ProtocolWebBanking. |
bankCode | String | nein | Bankleitzahl oder Service-Name |
step | Number | nein | Schritt der Anmeldung, beginnend bei 1. Wird nach jeder Aufforderung zur Zwei-Faktor-Authentifizierung erhöht, siehe unten. |
credentials | Array | nein | Beim ersten Aufruf die vom Anwender eingegebenen Zugangsdaten in der Reihenfolge der Eingabefelder des Anmeldedialogs: Benutzername, gegebenenfalls zweites und drittes Feld, Passwort (siehe Abschnitt »Zugangsdaten und Feldbeschriftungen«). Bei Folgeaufrufen die Antwort auf die vorherige Aufforderung, siehe unten. |
interactive | Boolean | nein | true, wenn MoneyMoney im Vordergrund läuft und Dialoge anzeigen kann; false bei einer Aktualisierung im Hintergrund. |
hbciTanMethods | Array | ja | Nur bei ProtocolFinTS: die TAN-Verfahren des FinTS/HBCI-Zugangs als Array von Tabellen (siehe Abschnitt »Datenstruktur eines TAN-Verfahrens«), sonst ein leeres Array. |
session | String | ja | Anlass der Sitzung: "refresh" (Kontenrundruf), "new account" (Einrichtung eines Bankzugangs), "statement" (Abruf von Kontoauszügen), "payment" (Zahlungsauftrag) oder "tan media" (Abfrage der TAN-Verfahren). |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
| — | nil | Nichts oder nil, wenn die Anmeldung erfolgreich war. |
| — | Konstante | LoginFailed, wenn die Zugangsdaten vom Server abgewiesen wurden. Um eine Sperrung des Passworts durch den Server zu vermeiden, werden die betroffenen Konten durch MoneyMoney nicht mehr automatisch aktualisiert, bis die Zugangsdaten durch den Anwender erneut eingegeben wurden. |
| — | String | Eine Fehlermeldung. |
| — | Table | Eine Aufforderung zur Zwei-Faktor-Authentifizierung, siehe unten. |
Aufforderung zur Zwei-Faktor-Authentifizierung
Die zurückgegebene Tabelle beschreibt, welchen Dialog MoneyMoney anzeigen soll. Mindestens eines der Felder challenge, label, tanMethod oder tanMethods muss belegt sein, sonst wird die Tabelle nicht als Aufforderung erkannt.
| Feld | Typ | Optional | Beschreibung |
|---|---|---|---|
challenge | String oder Binary | ja | Die eigentliche Aufforderung: ein Text, die Binärdaten eines Bildes im PNG- oder JPEG-Format, eine URL (https://…) oder die Daten eines chipTAN-Verfahrens (QR-Code, Flickercode). Wie der Inhalt dargestellt wird, ist im Abschnitt »Dialogvarianten« beschrieben. HTML-Tags in einem Text werden entfernt. |
label | String | ja | Beschriftung des Eingabefelds, z. B. "TAN" oder "Code". Ohne label zeigt der Dialog kein Eingabefeld an. |
title | String | ja | Anleitungstext über der Aufforderung. Ohne Angabe erzeugt MoneyMoney einen zum Verfahren und zum Anlass passenden Text. |
poll | Boolean | ja | true bei entkoppelten Verfahren (Freigabe in einer Banking-App), bei denen die Extension den Status wiederholt abfragt, statt auf eine Eingabe zu warten. Wirkt nur, wenn kein label angegeben ist. |
tanMethod | Table | ja | Das für diese Aufforderung verwendete TAN-Verfahren, siehe Abschnitt »Datenstruktur eines TAN-Verfahrens«. Bestimmt Länge und Zeichenvorrat der Eingabe sowie die von MoneyMoney erzeugten Texte. |
tanMethods | Array | ja | TAN-Verfahren, aus denen der Anwender zunächst eines auswählen soll (Array von Tabellen, siehe »Datenstruktur eines TAN-Verfahrens«). Wird mit tanMethods ein Auswahldialog angezeigt, werden challenge, label und tanMethod ignoriert. |
button | String | ja | "next", wenn der Bestätigungsknopf des Dialogs »Weiter« statt »OK« heißen soll, weil danach eine weitere Aufforderung folgt. |
startCode | String | ja | Startcode eines chipTAN-Verfahrens. Wird in den von MoneyMoney erzeugten Anleitungstext eingesetzt. |
appToApp | String | ja | Name einer Banking-App. Eine URL in challenge wird dann nicht im Browser geöffnet, sondern als QR-Code angezeigt, den der Anwender mit der Kamera seines Smartphones scannt, um die App zu starten. |
state | String | ja | Der state-Parameter einer OAuth-URL in challenge, siehe »Freigabe im Browser«. |
Folgeaufrufe
Nach jeder Aufforderung ruft MoneyMoney die Funktion erneut auf. step wird dabei normalerweise um 1 erhöht. Wird tanMethod direkt mit einer Aufforderung angegeben, wird step um 2 erhöht, weil der Schritt für die Auswahl des Verfahrens entfällt, aber mitgezählt wird. Bei entkoppelten Verfahren bleibt step während des Pollings unverändert, solange die Extension dieselbe Aufforderung zurückgibt. Robuste Extensions verlassen sich deshalb nicht auf exakte Werte von step, sondern merken sich ihren Zustand in lokalen Variablen.
Bei Folgeaufrufen hat credentials eine andere Bedeutung als beim ersten Aufruf:
| Index | Typ | Beschreibung |
|---|---|---|
credentials[1] | String oder Table | Die Antwort des Anwenders auf die vorherige Aufforderung: bei einem Eingabefeld der eingegebene Text, bei einem Captcha das Lösungs-Token, bei einer Freigabe im Browser der code-Parameter der Weiterleitung, bei entkoppelten Verfahren ein leerer String. Nach der Auswahl eines TAN-Verfahrens die Tabelle des gewählten Verfahrens (siehe »Datenstruktur eines TAN-Verfahrens«). |
credentials[2] | String | Lokalisierte Abbruchmeldung, die die Extension zurückgeben sollte, wenn das Polling erfolglos beendet werden muss. Fehlt nach der Auswahl eines TAN-Verfahrens. |
credentials[3] | Boolean | true, solange ein weiterer Polling-Versuch erlaubt ist. Die Anzahl der Versuche steuert MoneyMoney; die Extension sollte kein eigenes Zeitlimit implementieren. Fehlt nach der Auswahl eines TAN-Verfahrens. |
Welche Art von Dialog MoneyMoney anzeigt, ergibt sich aus der Kombination der Felder. Die folgenden Dialogvarianten decken die üblichen Fälle ab.
Eingabe einer TAN oder eines Codes
Ein Text in challenge und eine Beschriftung in label ergeben einen Dialog mit Anleitungstext und Eingabefeld. Mit tanMethod legt die Extension Länge und Zeichenvorrat der Eingabe fest; ohne tanMethod akzeptiert das Feld beliebigen Text.
return {
title="Bitte geben Sie den per SMS erhaltenen Code ein.",
label="Code",
tanMethod={
name="SMS",
tanLength=6,
isNumeric=true
}
}
Die kürzeste Form ist ein Eingabefeld ohne weiteren Text:
return {label="mobileTAN"}
Bild
Sind in challenge die Binärdaten eines PNG- oder JPEG-Bildes enthalten, zeigt der Dialog das Bild an, z. B. eine photoTAN-Grafik oder ein Bild-Captcha. Mit label kommt ein Eingabefeld hinzu.
local image = connection:get(
html:xpath("//img[contains(@alt,'photoTAN')]"):attr("src")
)
return {label="photoTAN", challenge=image}
QR-Code
Für einen QR-Code gibt es zwei Wege. Entweder liefert die Extension den QR-Code als Bild (siehe oben), oder sie überlässt MoneyMoney die Darstellung: Enthält challenge eine URL (https://…) und ist tanMethod.name der lokalisierte Name MM.localizeText("QR Code"), erzeugt MoneyMoney den QR-Code selbst. Der Name muss exakt über MM.localizeText gebildet werden, da er je nach Sprache von MoneyMoney unterschiedlich lautet; andernfalls wird die URL als Text angezeigt.
Ohne label wird der QR-Code als entkoppeltes Verfahren behandelt: MoneyMoney zeigt einen Wartehinweis an und die Extension fragt mit poll=true den Status ab. Mit label erscheint zusätzlich ein Eingabefeld, z. B. für chipTAN QR.
return {
challenge=qrUrl,
tanMethod={
name=MM.localizeText("QR Code")
},
poll=true
}
Entkoppeltes Verfahren
Bei einer Freigabe in einer Banking-App gibt es nichts einzugeben. Die Extension gibt einen Text in challenge und poll=true zurück, MoneyMoney zeigt einen Wartehinweis mit Abbrechen-Knopf an und ruft die Funktion so lange erneut auf, bis die Extension nil (Freigabe erteilt) oder eine Fehlermeldung zurückgibt. Zwischen den Aufrufen sollte die Extension mit MM.sleep eine kurze Pause einlegen. Ist tanMethod.name ein MoneyMoney bekanntes App-Verfahren (z. B. "pushTAN", "appTAN", "photoTAN push"), erzeugt MoneyMoney die Texte des Dialogs selbst.
if step > 1 then
if pollAuthorizationStatus() == "approved" then
return nil
elseif credentials[3] then
MM.sleep(2)
return {
challenge="Bitte bestätigen Sie die Anmeldung in der Banking-App.",
poll=true
}
else
return credentials[2]
end
end
Auswahl des TAN-Verfahrens
Bietet die Bank mehrere Verfahren an, gibt die Extension sie in tanMethods zurück. MoneyMoney zeigt einen Auswahldialog an und übergibt beim nächsten Aufruf die Tabelle des gewählten Verfahrens in credentials[1]. Die Extension gibt daraufhin die eigentliche Aufforderung zurück. MoneyMoney merkt sich die Auswahl anhand von hbciMethod und wählt das Verfahren beim nächsten Mal vor. Verfahren mit errorMessage werden angezeigt, sind aber nicht auswählbar; die Meldung erklärt dem Anwender den Grund.
if step == 1 then
-- Login.
return {
tanMethods={
{
name="pushTAN",
hbciMethod="700"
},
{
name="mobileTAN",
hbciMethod="701",
mediumName="+49 *** 4567"
}
}
}
elseif step == 2 then
local tanMethod = credentials[1]
if tanMethod.name == "pushTAN" then
-- Trigger push notification.
return {challenge="pushTAN", poll=true}
else
-- Request SMS.
return {label=tanMethod.label}
end
else
-- Poll pushTAN or submit mobileTAN from credentials[1].
end
Hat die Bank bereits beim Login eine Push-Freigabe ausgelöst, kann zusammen mit tanMethods auch poll=true gesetzt werden. Der Auswahldialog wartet dann parallel auf die Freigabe über das erste App-Verfahren der Liste, und die Funktion wird wie bei entkoppelten Verfahren wiederholt aufgerufen.
Captcha
Enthält challenge die Script-URL eines unterstützten Captcha-Anbieters, zeigt MoneyMoney das Captcha in einem eingebetteten Browser an; unsichtbare Varianten werden zunächst ohne Zutun des Anwenders versucht. Das Lösungs-Token wird beim nächsten Aufruf in credentials[1] übergeben. Unterstützt werden Google reCAPTCHA (https://www.recaptcha.net/recaptcha/api.js oder enterprise.js), hCaptcha (https://js.hcaptcha.com/1/api.js), FriendlyCaptcha (https://cdn.jsdelivr.net/npm/friendly-challenge/widget.module.min.js oder @friendlycaptcha/sdk/site.min.js) und Amazon WAF (https://….token.awswaf.com/…/challenge.js). Als Query-Parameter erwartet MoneyMoney den sitekey der Website, optional type=checkbox für die sichtbare Variante und referer mit der URL der Seite, in die das Captcha eingebettet ist.
return {
challenge="https://www.recaptcha.net/recaptcha/api.js?sitekey=" ..
siteKey ..
"&type=checkbox&referer=" ..
MM.urlencode(loginUrl)
}
Freigabe im Browser
Enthält challenge eine sonstige https://-URL, öffnet MoneyMoney sie in einem eigenen Browserfenster, z. B. für eine OAuth-Autorisierung. Leitet die Website anschließend auf die vereinbarte Weiterleitungs-URL um, übergibt MoneyMoney den code-Parameter (ersatzweise access_token, auth_code, tokenid oder ähnliche Parameter) beim nächsten Aufruf in credentials[1]. Den state-Parameter der URL kann die Extension in state mitgeben; fehlt er, liest MoneyMoney ihn aus der URL oder hängt selbst einen zufälligen Wert an. Der Host der URL muss in MoneyMoney freigeschaltet sein, andernfalls bricht die Sitzung mit einer entsprechenden Fehlermeldung ab. Für Community-Extensions ist diese Variante deshalb nur in Absprache mit dem MoneyMoney-Support nutzbar.
return {challenge=authorizeUrl, state=state}
Siehe auch: InitializeSession, FetchStatements
ListAccounts
function ListAccounts (knownAccounts)
Listet alle Konten auf, die mittels Web Scraping abgefragt werden können.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
knownAccounts | Array | nein | Wenn das Protokoll des Bankzugangs FinTS/HBCI ist, Web Scraping also nur als Ergänzung dient, dann enthält dieser Parameter ein Array mit schon bekannten Konten. Das Skript kann anhand dieses Arrays feststellen, welche Kontoinformationen es nicht mehr über Web Scraping abzufragen braucht. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Kontos« beschrieben. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
| — | Array | Konten, die mittels Web Scraping abgefragt werden können. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Kontos« beschrieben. |
| — | String | Eine Fehlermeldung. |
Für jedes Konto muss mindestens die Kontonummer zurückgegeben werden, andernfalls wird das Konto ignoriert.
RefreshAccount
function RefreshAccount (account, since)
Fragt Saldo- und Umsatzinformationen oder den Wertpapierbestand eines Kontos ab.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
account | Table | nein | Das Konto, das abgefragt werden soll. Die Struktur ist im Abschnitt »Datenstruktur eines Kontos« beschrieben. |
since | Number | nein | Der Buchungstag, ab dem Umsätze geliefert werden sollten. Das Skript braucht ältere Umsätze nicht mehr zu liefern. Die Angabe erfolgt in Form eines POSIX-Zeitstempels. Bei Depots wird anstelle dieses Parameters nil übergeben. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
| — | Table | Eine Tabelle mit den unten beschriebenen Feldern. |
| — | String | Eine Fehlermeldung. |
Felder der zurückgegebenen Tabelle:
| Feld | Typ | Beschreibung |
|---|---|---|
balance | Number | Kontostand |
balances | Array | Ein Array mit Tupeln (Kontostand, Währung). Dieses Feld sollte nur dann an Stelle von balance zurückgegeben werden, wenn das Konto mehrere Kontostände in unterschiedlichen Währungen besitzt. |
pendingBalance | Number | Summe der vorgemerkten Umsätze |
transactions | Array | Ein Array mit Umsätzen. Diese Umsätze werden als »neu« klassifiziert, wenn sie noch nicht in der Datenbank von MoneyMoney vorhanden sind. Andernfalls werden sie als Duplikate verworfen. Das Array sollte nach Buchungstag geordnet sein, mit den neuesten Umsätzen vorne. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Umsatzes« beschrieben. |
securities | Array | Ein Array mit Depotpositionen. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur von Wertpapieren« beschrieben. |
bonusPoints | Number | Anzahl der Punkte in einem Bonusprogramm |
Bei Depots wird nur das Feld securities erwartet, bei allen anderen Konten die Felder balance/balances und transactions. Wenn diese fehlen oder den Wert nil enthalten, wird in der GUI eine Fehlermeldung angezeigt, dass der Kontostand bzw. die Umsätze bzw. der Wertpapierbestand nicht abgefragt werden konnte.
Für jeden Umsatz müssen mindestens Betrag und Buchungstag angegeben werden, andernfalls führt dies ebenfalls zu einer Fehlermeldung.
FetchStatements
function FetchStatements (accounts, knownIdentifiers, step, credentials, interactive)
Ruft elektronische Kontoauszüge und andere Postfach-Dokumente (PDF) ab. Diese Funktion ist optional — nur wenn das Skript sie definiert, bietet MoneyMoney den Dokumentenabruf für den Bankzugang an. Anders als RefreshAccount wird sie nicht je Konto aufgerufen, sondern einmal mit allen betroffenen Konten.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
accounts | Array | nein | Die Konten, für die Dokumente abgerufen werden sollen. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Kontos« beschrieben. |
knownIdentifiers | Table | nein | Tabelle, deren Schlüssel die identifier bereits früher abgerufener Dokumente sind. Dokumente, deren Kennung hier enthalten ist, braucht das Skript nicht erneut herunterzuladen. |
step | Number | nein | Schritt der Zwei-Faktor-Authentifizierung, beginnend bei 1 — falls der Server für den Dokumentenabruf eine Freigabe verlangt. |
credentials | Array | nein | Bei Folgeaufrufen nach einer Challenge belegt wie bei InitializeSession2 (Antwort, Abbruchmeldung, Polling-Status). |
interactive | Boolean | nein | MoneyMoney wird im Vordergrund oder Hintergrund ausgeführt |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
| — | Table | Eine Tabelle mit dem Feld statements: ein Array von Dokumenten, geordnet mit dem neuesten Dokument vorne. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Kontoauszugs« beschrieben. |
| — | Table | Eine Aufforderung zur Zwei-Faktor-Authentifizierung wie bei InitializeSession2 (siehe dort »Aufforderung zur Zwei-Faktor-Authentifizierung«) — die Funktion wird dann mit erhöhtem step erneut aufgerufen. |
| — | String | Eine Fehlermeldung. |
Siehe auch: InitializeSession2
EndSession
function EndSession ()
Führt den Abmeldevorgang durch.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
| — | nil | Nichts oder nil, wenn die Abmeldung erfolgreich war. |
| — | String | Eine Fehlermeldung. |
Datenstrukturen
Datenstruktur eines Kontos
Die Informationen eines Kontos werden in einer Lua-Tabelle gespeichert. Folgende Felder können belegt werden, soweit deren Inhalt bekannt ist:
| Feld | Typ | Beschreibung |
|---|---|---|
name | String | Bezeichnung des Kontos |
owner | String | Name des Kontoinhabers |
accountNumber | String | Kontonummer |
subAccount | String | Unterkontomerkmal |
portfolio | Boolean | true für Depots und false für alle anderen Konten |
bankCode | String | Bankleitzahl |
currency | String | Kontowährung |
iban | String | IBAN |
bic | String | BIC |
type | Konstante | Kontoart, siehe unten |
Mögliche Werte für die Kontoart type:
| Konstante | Bedeutung |
|---|---|
AccountTypeGiro | Girokonto |
AccountTypeSavings | Sparkonto |
AccountTypeFixedTermDeposit | Festgeldanlage |
AccountTypeLoan | Darlehenskonto |
AccountTypeCreditCard | Kreditkarte |
AccountTypePortfolio | Wertpapierdepot |
AccountTypeOther | Sonstige |
Fehlt das Feld type, versucht MoneyMoney beim Anlegen des Kontos, die Kontoart aus Kontonummer und Kontobezeichnung abzuleiten. Eine Kontonummer mit 16 Zeichen oder mit maskierten Stellen (x, *) wird dabei als Kreditkarte gewertet. Ein explizit angegebener Wert wird unverändert übernommen, auch AccountTypeOther. Die Kontoart wird nur beim Anlegen gesetzt und beim Aktualisieren nicht mehr verändert.
Datenstruktur eines Umsatzes
Die Daten eines Umsatzes werden in einer Lua-Tabelle gespeichert:
| Feld | Typ | Beschreibung |
|---|---|---|
name | String | Name des Auftraggebers/Zahlungsempfängers |
accountNumber | String | Kontonummer oder IBAN des Auftraggebers/Zahlungsempfängers |
bankCode | String | Bankleitzahl oder BIC des Auftraggebers/Zahlungsempfängers |
amount | Number | Betrag |
currency | String | Währung |
bookingDate | Number | Buchungstag; Die Angabe erfolgt in Form eines POSIX-Zeitstempels. |
valueDate | Number | Wertstellungsdatum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels. |
purpose | String | Verwendungszweck; Mehrere Zeilen können durch Zeilenumbrüche (\n) getrennt werden. |
transactionCode | Number | Geschäftsvorfallcode |
textKeyExtension | Number | Textschlüsselergänzung |
purposeCode | String | SEPA-Verwendungsschlüssel |
bookingKey | String | SWIFT-Buchungsschlüssel |
bookingText | String | Umsatzart |
primanotaNumber | String | Primanota-Nummer |
batchReference | String | Sammlerreferenz |
endToEndReference | String | SEPA-Ende-zu-Ende-Referenz |
mandateReference | String | SEPA-Mandatsreferenz |
creditorId | String | SEPA-Gläubiger-ID |
returnReason | String | Rückgabegrund |
booked | Boolean | Gebuchter oder vorgemerkter Umsatz |
Datenstruktur von Wertpapieren
Die Daten von Wertpapieren werden in einer Lua-Tabelle gespeichert:
| Feld | Typ | Beschreibung |
|---|---|---|
name | String | Bezeichnung des Wertpapiers |
isin | String | ISIN |
securityNumber | String | WKN |
quantity | Number | Nominalbetrag oder Stückzahl |
currencyOfQuantity | String | Währung bei Nominalbetrag oder nil bei Stückzahl |
purchasePrice | Number | Kaufpreis oder Kaufkurs |
currencyOfPurchasePrice | String | Von der Kontowährung abweichende Währung des Kaufpreises |
exchangeRateOfPurchasePrice | Number | Wechselkurs zum Kaufzeitpunkt |
price | Number | Aktueller Preis oder Kurs |
currencyOfPrice | String | Von der Kontowährung abweichende Währung des Preises |
exchangeRateOfPrice | Number | Aktueller Wechselkurs |
amount | Number | Wert der Depotposition in Kontowährung |
originalAmount | Number | Wert der Depotposition in Originalwährung |
currencyOfOriginalAmount | String | Originalwährung |
market | String | Name des Börsenplatzes |
tradeTimestamp | Number | Notierungszeitpunkt; Die Angabe erfolgt in Form eines POSIX-Zeitstempels. |
Datenstruktur eines Kontoauszugs
Die von FetchStatements gelieferten Dokumente werden in Lua-Tabellen gespeichert:
| Feld | Typ | Beschreibung |
|---|---|---|
pdf | Binary | Das Dokument als PDF. Alternativ kann ein ZIP-Archiv übergeben werden; die darin enthaltenen PDF-Dateien werden automatisch entpackt. Dieses Feld ist Pflicht. |
identifier | String | Eindeutige Kennung des Dokuments, z. B. eine Dokument-ID des Servers. Anhand dieser Kennung erkennt MoneyMoney bereits abgerufene Dokumente (siehe Parameter knownIdentifiers von FetchStatements). |
name | String | Anzeigename des Dokuments |
filename | String | Dateiname des Dokuments |
creationDate | Number | Erstellungsdatum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels. |
timezone | String | Zeitzone, in der creationDate zu interpretieren ist, z. B. "Europe/Berlin" |
account | Table | Das Konto, dem das Dokument zugeordnet werden soll (aus dem accounts-Parameter von FetchStatements). Ohne dieses Feld wird das Dokument dem aktuellen Konto zugeordnet. |
Datenstruktur eines TAN-Verfahrens
TAN-Verfahren werden bei InitializeSession2 und FetchStatements in den Feldern tanMethod und tanMethods an MoneyMoney übergeben und nach der Auswahl durch den Anwender in credentials[1] an die Extension zurückgegeben. Auch die TAN-Verfahren eines FinTS/HBCI-Zugangs (Parameter hbciTanMethods) haben diese Struktur.
| Feld | Typ | Beschreibung |
|---|---|---|
name | String | Anzeigename des Verfahrens, z. B. "pushTAN", "mobileTAN" oder "photoTAN". Dieses Feld ist Pflicht. Für MoneyMoney bekannte App-Verfahren (z. B. "pushTAN", "appTAN", "photoTAN push") und für MM.localizeText("QR Code") erzeugt MoneyMoney passende Dialogtexte, siehe »Dialogvarianten« bei InitializeSession2. |
mediumName | String | Bezeichnung des TAN-Mediums, z. B. eine maskierte Mobilfunknummer oder ein Gerätename. Wird im Auswahldialog neben dem Namen angezeigt. |
hbciMethod | String | Kennung des Verfahrens, üblicherweise dreistellig wie bei FinTS (z. B. "700"). Anhand dieser Kennung merkt sich MoneyMoney die Auswahl des Anwenders. |
errorMessage | String | Ist dieses Feld belegt, wird das Verfahren im Auswahldialog angezeigt, ist aber nicht auswählbar; die Meldung erklärt den Grund (z. B. Verfahren muss erst auf der Website freigeschaltet werden). |
tanLength | Number | Feste Länge der Eingabe. Standard: 6. |
minLength | Number | Mindestlänge der Eingabe, alternativ zu tanLength. |
maxLength | Number | Maximale Länge der Eingabe, alternativ zu tanLength. |
isNumeric | Boolean | true (Standard), wenn nur Ziffern eingegeben werden dürfen. Bei false sind auch Buchstaben erlaubt; die Eingabe wird dann in Großbuchstaben umgewandelt, sofern isUppercase nicht false ist. |
isUppercase | Boolean | true, wenn die Eingabe in Großbuchstaben umgewandelt werden soll. |
isPreferred | Boolean | true, wenn das Verfahren im Auswahldialog vorausgewählt sein soll. |
label | String | Nur in den von MoneyMoney übergebenen Tabellen: die aus dem Namen abgeleitete Beschriftung für das Eingabefeld, z. B. "TAN". Kann von der Extension als label der Aufforderung weiterverwendet werden. |
Objekt für eine HTTPS-Verbindung
Connection
connection = Connection()
Erzeugt ein Objekt, mit dem eine HTTPS-Verbindung zu einem Webserver aufgebaut werden kann.
connection:request
content, charset, mimeType, filename, headers = connection:request(method, url[, postContent, postContentType, headers])
Fordert eine Ressource vom Webserver an.
Falls noch keine HTTPS-Verbindung zum Server besteht, wird diese aufgebaut. Das Connection-Objekt verwendet HTTP-Pipelining. Wenn der Server dies auch anbietet und solange über den URL-Parameter nicht der Server gewechselt wird, werden alle Anfragen über dieselbe HTTPS-Verbindung geschickt.
Für JSON-basierte REST-APIs sollte im Parameter headers das HTTP-Header-Feld Accept auf "application/json" gesetzt werden. Dann wird auch bei einem HTTP-Fehler die Serverantwort im Skript zurückgegeben. Andernfalls wird im Fehlerfall die Ausführung des Skripts abgebrochen und stattdessen in der GUI eine Fehlermeldung angezeigt.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
method | String | nein | HTTP-Request-Methode; Mögliche Werte sind "GET", "POST", "PUT", "PATCH" und "DELETE". |
url | String | nein | Server-URL; Die URL darf absolut oder relativ sein. Bei der ersten Server-Anfrage muss eine absolute URL angegeben werden. Relative URLs beziehen sich wie üblich auf die gerade aktive, d.h. zuletzt aufgerufene URL. |
postContent | Binary | ja | Die Daten, die mit einem HTTP-POST-Request an den Server gesendet werden sollen |
postContentType | String | ja | Der Inhalt des Felds Content-Type für den HTTP-POST-Header |
headers | Dictionary | ja | Weitere HTTP-Header-Felder |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
content | Binary | Daten vom Server |
charset | String | Der Zeichensatz, mit dem die vom Server gelieferten Daten zu interpretieren sind |
mimeType | String | MIME-Type der vom Server gelieferten Daten |
filename | String | Dateiname aus dem HTTP-Header-Feld Content-Disposition |
headers | Dictionary | Vom Server gelieferte HTTP-Header-Felder |
Zur Bestimmung des Zeichensatzes und des MIME-Typs werden der HTTP-Header des Servers und <meta>-Tags im HTML-Code herangezogen.
content, charset, mimeType = connection:request(
"POST",
"/onlinebanking",
"username=foo&password=bar",
"application/x-www-form-urlencoded; charset=UTF-8"
)
print(content) -- "<html>\n<head>\n<title>[…]"
print(charset) -- "UTF-8"
print(mimeType) -- "text/html"
Tipp: Die Art und Reihenfolge der Rückgabewerte ist so gewählt, dass sie sich für die Erzeugung eines HTML-Objektes verwenden lassen:
html = HTML(connection:request("GET", "/onlinebanking"))
connection:get
content, charset, mimeType = connection:get(url)
Kurzform für: connection:request("GET", url)
Siehe auch: connection:request
connection:post
content, charset, mimeType = connection:post(url, postContent[, postContentType])
Kurzform für: connection:request("POST", url, postContent, postContentType)
Siehe auch: connection:request
connection:close
connection:close()
Schließt die HTTPS-Verbindung zum Server. Normalerweise braucht diese Methode nicht aufgerufen werden, da nach der Ausführung des Skripts alle offenen Verbindungen automatisch geschlossen werden.
connection:getBaseURL
url = connection:getBaseURL()
Gibt die zuletzt aufgerufene URL zurück.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
url | String | Die zuletzt aufgerufene URL |
connection:setCookie
connection:setCookie(cookie)
Fügt dem Cookie-Speicher weitere Cookies hinzu oder ändert vorhandene Cookies.
Jedes Skript erhält für die Dauer seiner Ausführung einen Speicher für HTTP-Cookies. Dieser Speicher wird von allen HTTP-Verbindungen, die innerhalb desselben Skripts aufgebaut werden, gemeinsam genutzt. Die Cookies werden automatisch aus dem HTTP-Header des Servers und den <meta>-Tags im HTML-Code extrahiert. Nach der Ausführung des Skripts werden alle Cookies wieder gelöscht.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
cookie | String | nein | HTTP-Cookie; Das Format ist identisch zum Feld Set-Cookie im HTTP-Header. |
connection:setCookie("SESSION=foobar; path=/")
connection:getCookies
cookies = connection:getCookies()
Fragt die HTTP-Cookies ab, die für die gerade aktive, d.h. zuletzt aufgerufene URL gültig sind.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
cookies | String | HTTP-Cookies; Das Format ist identisch zum Feld Cookie im HTTP-Header. |
connection.useragent
Dieses Attribut vom Typ String enthält den Wert des Felds User-Agent für den HTTP-Header. Durch Veränderung dieses Werts lässt sich gegenüber dem Webserver ein bestimmter Browser oder ein mobiles Endgerät simulieren.
connection.useragent = "Mozilla/5.0 (compatible; " ..
MM.productName ..
"/" ..
MM.productVersion ..
")"
connection.language
Dieses Attribut vom Typ String enthält den Wert des Felds Accept-Language für den HTTP-Header. Bei manchen Servern lässt sich so die Sprache der Inhalte auswählen. Als Standardwert ist die Sprache des Betriebssystems voreingestellt.
connection.language = "de-DE"
Objekt für ein HTML-Dokument
HTML
html = HTML(content[, charset])
Erzeugt ein neues Objekt, mit dem sich in einem HTML-Dokument navigieren lässt.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
content | Binary | nein | HTML-Code |
charset | String | ja | Der Zeichensatz, mit dem der HTML-Code zu interpretieren ist. Wenn dieser Parameter fehlt, wird der Zeichensatz aus den <meta>-Tags extrahiert. |
html:xpath
elements = html:xpath(query)
Wählt HTML-Elemente mittels eines XPath-Ausdrucks aus.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
query | String | nein | XPath-Ausdruck in der XML Path Language Version 1.0; Alle Tag- und Attributsnamen müssen klein geschrieben werden. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
elements | Objekt | Eine Liste von HTML-Elementen, die durch den XPath-Ausdruck ausgewählt wurden. Die Methoden, die auf dieses Objekt angewendet werden können, sind im Abschnitt »Objekt für HTML-Elemente« beschrieben. |
Tipp: Die Entwicklertools von Webbrowsern bieten komfortable Werkzeuge an, um XPath-Ausdrücke zu schreiben und zu testen.
html:html
text = html:html()
Generiert aus dem HTML-Dokument neuen, formatierten HTML-Code. Dieser ist nicht unbedingt identisch zum ursprünglichen HTML-Code. Der generierte HTML-Code ist immer UTF-8-kodiert.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
text | String | HTML-Code |
Objekt für HTML-Elemente
elements:length
count = elements:length()
Liefert die Anzahl der HTML-Elemente, die sich im Objekt elements befinden.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
count | Number | Anzahl der HTML-Elemente |
elements:get
elements = elements:get(n)
Wählt das n-te HTML-Element aus elements aus.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
n | Number | nein | Index des auszuwählenden HTML-Elements; Wie in Lua üblich, beginnt die Indexierung bei 1. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
elements | Objekt | Der Rückgabewert besteht selbst wieder aus einem Objekt für HTML-Elemente. Wenn n ein gültiger Index ist, enthält elements das n-te HTML-Element. Andernfalls ist elements leer. |
if elements:get(2):length() == 1 then print "Fnord!" end
elements:each
elements:each(function (index, element))
Durchläuft alle HTML-Elemente von elements und führt für jedes HTML-Element eine Aktion aus.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
function | Function | nein | Eine Funktion, die für jedes HTML-Element ausgeführt werden soll. Ihre Parameter: index (Number) — Index des aktuellen HTML-Elements, beginnend bei 1; element (Objekt) — ein Objekt für HTML-Elemente mit genau einem HTML-Element. |
Wenn die Funktion den Wert false zurückgibt, wird die Methode each abgebrochen.
elements:each(function (index, element)
print (index .. "=" .. element:text())
end)
elements:reverse
elements = elements:reverse()
Dreht die Reihenfolge der HTML-Elemente von elements um.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
elements | Objekt | Der Rückgabewert besteht selbst wieder aus einem Objekt für HTML-Elemente, welches die HTML-Elemente in umgekehrter Reihenfolge enthält. |
elements:children
elements = elements:children()
Wählt die unmittelbaren Kindelemente der HTML-Elemente aus elements aus.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
elements | Objekt | Der Rückgabewert besteht selbst wieder aus einem Objekt für HTML-Elemente und enthält die HTML-Kindelemente. |
elements:xpath
elements = elements:xpath(query)
Wählt mittels eines XPath-Ausdrucks HTML-Elemente relativ zum ersten HTML-Element von elements aus. Der XPath-Ausdruck query muss dazu ebenfalls relativ sein, d.h. mit einem Punkt beginnen.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
query | String | nein | Relativer XPath-Ausdruck (beginnend mit einem Punkt) in der XML Path Language Version 1.0; Alle Tag- und Attributsnamen müssen klein geschrieben werden. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
elements | Objekt | Eine Liste von HTML-Elementen, die durch den XPath-Ausdruck ausgewählt wurden. |
elements:text
text = elements:text()
Liefert den kombinierten Text, der sich zwischen den HTML-Tags der HTML-Elemente elements und deren Kindelementen befindet.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
text | String | Text, der sich zwischen den HTML-Tags befindet. |
elements:attr (lesen)
value = elements:attr(attribute)
Gibt den Inhalt eines Attributs des ersten HTML-Elements aus elements zurück.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
attribute | String | nein | Name des Attributs |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
value | String | Inhalt des Attributs |
elements:attr (schreiben)
elements:attr(attribute, value)
Ändert ein Attribut für alle HTML-Elemente aus elements.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
attribute | String | nein | Name des Attributs |
value | String | nein | Neuer Inhalt des Attributs |
elements:val
value = elements:val()
Gibt den Wert eines Formularfelds zurück. Das erste HTML-Element in elements muss ein Formularfeld sein. Im Gegensatz zur Methode elements:attr("value") berücksichtigt diese Methode auch das Attribut disabled und wertet die ausgewählte Option von Auswahllisten (<select>-Tag) aus.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
value | String | Wert des Formularfelds |
elements:select
elements:select(value)
Wählt eine Option in einer Auswahlliste (<select>-Tag) aus. Das erste HTML-Element in elements muss eine Auswahlliste sein. Im Gegensatz zur Methode elements:attr("selected", "selected") berücksichtigt diese Methode auch das Attribut disabled und wählt die übrigen Optionen ab.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
value | String | nein | Ausgewählte Option |
elements:click
method, url[, postContent, postContentType] = elements:click()
Erzeugt aus einem HTML-Link oder einem HTML-Formular die Parameter für einen HTTP-Request. In elements muss als erstes HTML-Element ein Link (<a href>-Tag) oder ein Submit-Button (<input type="submit">-Tag, <button>-Tag) oder ein Image-Button (<input type="image">-Tag) vorhanden sein.
Bei einem HTML-Link wird die verlinkte URL zurückgegeben. Bei einem Formular werden die Werte der <input>-Tags URL-kodiert und entweder als GET-Parameter an die URL angehängt oder als POST-Parameter zurückgegeben.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
method | String | HTTP-Request-Methode; Mögliche Werte sind "GET" und "POST". |
url | String | Server-URL |
postContent | Binary | Die Daten, die mit einem HTTP-POST-Request an den Server gesendet werden sollen. |
postContentType | String | Der Inhalt des Felds Content-Type für den HTTP-POST-Header. |
Tipp: Die Art und Reihenfolge der Rückgabewerte ist so gewählt, dass sie sich für einen HTTP-Request verwenden lassen:
connection:request(elements:click())
elements:submit
method, url[, postContent, postContentType] = elements:submit()
Erzeugt aus einem HTML-Formular ohne Submit-Button die Parameter für einen HTTP-Request. In elements muss als erstes HTML-Element ein Formular (<form>-Tag) vorhanden sein. Die Werte der <input>-Tags werden URL-kodiert und entweder als GET-Parameter an die URL angehängt oder als POST-Parameter zurückgegeben. Die Werte von Submit-Buttons (<input type="submit">-Tag) werden ignoriert, da das Formular ohne Submit-Button generiert wird.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
method | String | HTTP-Request-Methode; Mögliche Werte sind "GET" und "POST". |
url | String | Server-URL |
postContent | Binary | Die Daten, die mit einem HTTP-POST-Request an den Server gesendet werden sollen. |
postContentType | String | Der Inhalt des Felds Content-Type für den HTTP-POST-Header. |
Tipp: Die Art und Reihenfolge der Rückgabewerte ist so gewählt, dass sie sich für einen HTTP-Request verwenden lassen:
connection:request(elements:submit())
Objekt für ein JSON-Dokument
JSON():dictionary
fields = JSON(json):dictionary()
Konvertiert ein JSON-Dokument in eine Lua-Datenstruktur.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
json | Binary | nein | JSON-Dokument |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
fields | Dictionary oder Array | Lua-Datenstruktur des JSON-Dokuments |
JSON():set():json
json = JSON():set(fields):json()
Konvertiert eine Lua-Datenstruktur in ein JSON-Dokument.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
fields | Dictionary oder Array | nein | Lua-Datenstruktur des JSON-Dokuments |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
json | Binary | JSON-Dokument |
Objekt für ein PDF-Dokument
PDF():text
text = PDF(pdf):text()
Extrahiert, so gut wie möglich, den unformatierten Text aus einem PDF-Dokument.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
pdf | Binary | nein | PDF-Dokument |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
text | String | Unformatierter Text |
Persistenter Speicher
LocalStorage
Das globale Objekt LocalStorage ist eine Lua-Tabelle, deren Inhalt über die Laufzeit des Skripts hinaus erhalten bleibt. Der Speicher ist je Bankzugang getrennt und wird nach der Ausführung des Skripts automatisch gesichert und beim nächsten Lauf wiederhergestellt — typischer Einsatz sind Geräteschlüssel, Registrierungs-IDs oder Sitzungs-Tokens, die eine erneute starke Kundenauthentifizierung ersparen.
if not LocalStorage.deviceKey then
LocalStorage.deviceKey = MM.ecGenerateKeys("prime256v1")
end
Beim Sichern werden folgende Werte unterstützt:
| Typ | Verhalten |
|---|---|
| Number, Boolean, String | Werden unverändert gesichert; Strings dürfen Binärdaten enthalten. |
| Table | Wird einschließlich verschachtelter Tabellen gesichert. |
| Connection-Objekt | Wird als Sonderfall gesichert: Die zuletzt aufgerufene URL, alle HTTP-Cookies, useragent und language bleiben erhalten. Beim nächsten Lauf steht damit eine Connection mit der alten Cookie-Sitzung zur Verfügung — Server-Sitzungen können so App-Neustarts überleben. |
| HTML-Objekt | Wird als UTF-8-HTML-Code gesichert und beim Laden wieder geparst. |
| Funktionen und andere Objekte | Werden nicht gesichert; sie sind beim nächsten Lauf nil (betrifft z. B. JSON-Objekte und HTML-Elementlisten — bei Bedarf stattdessen den Ursprungs-String speichern). |
Skripte sollten beim Lesen stets mit fehlenden Werten rechnen (nil-Prüfung wie im Beispiel): Der Speicher ist leer, wenn der Bankzugang neu eingerichtet wurde, und einzelne Felder können nil sein, wenn eine ältere Skriptversion sie noch nicht geschrieben hat.
MM-Funktionen
Protokoll und Ablauf
MM.printStatus
MM.printStatus(...)
Zeigt eine Statusmeldung an. Diese Funktion arbeitet ähnlich zur Lua-Funktion print: Die Parameter werden mittels der Lua-Funktion tostring zu einem String konvertiert und im Protokoll-Fenster von MoneyMoney angezeigt. Zusätzlich wird der String als Statusmeldung in der GUI angezeigt.
Siehe auch: MM.printDebug
MM.printDebug
MM.printDebug(...)
Schreibt eine Debug-Meldung ins Protokoll-Fenster. Diese Funktion arbeitet wie print, kennzeichnet die Ausgabe aber als Debug-Meldung — anders als MM.printStatus erscheint sie nicht als Statusmeldung in der GUI.
Siehe auch: MM.printStatus
MM.sleep
MM.sleep(seconds)
Unterbricht die Ausführung des Skripts für ein paar Sekunden.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
seconds | Number | nein | Anzahl der Sekunden |
Lokalisierung
MM.localizeText
str = MM.localizeText(str)
Übersetzt einen Text. Diese Funktion ist primär für die mit MoneyMoney ausgelieferten Extensions gedacht. Sie ist ein Wrapper für die Cocoa-Funktion NSLocalizedString und liefert natürlich nur dann eine Übersetzung, wenn der Text in MoneyMoney hinterlegt worden ist.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
str | String | nein | Englischer Text |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
str | String | Übersetzter Text |
MM.localizeDate
str = MM.localizeDate([format, ]date)
Lokalisiert eine Zeitangabe. Da die von Lua unterstützten POSIX Locales innerhalb von macOS-Apps nicht zur Verfügung stehen, baut diese Funktion auf der Cocoa-Klasse NSDateFormatter auf.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
format | String | ja | Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSDateFormatter nach dem Unicode Technical Standard #35. |
date | Number | nein | Datum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
str | String | Datum im lokalisierten Format |
MM.localizeNumber
str = MM.localizeNumber([format, ]num)
Lokalisiert eine Zahl. Da die von Lua unterstützten POSIX Locales innerhalb von macOS-Apps nicht zur Verfügung stehen, baut diese Funktion auf der Cocoa-Klasse NSNumberFormatter auf.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
format | String | ja | Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSNumberFormatter nach dem Unicode Technical Standard #35. |
num | Number | nein | Zahl |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
str | String | Zahl im lokalisierten Format |
MM.localizeAmount
str = MM.localizeAmount([format, ]amount[, currency])
Lokalisiert einen Währungsbetrag.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
format | String | ja | Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSNumberFormatter nach dem Unicode Technical Standard #35. |
amount | Number | nein | Betrag |
currency | String | ja | Währung; Ohne diesen Parameter wird nur der Betrag ohne Währungsangabe zurückgegeben. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
str | String | Währungsbetrag im lokalisierten Format |
Datum und Zeit
MM.time
timestamp = MM.time()
Gibt die aktuelle Uhrzeit zurück. Im Gegensatz zum Aufruf os.time() enthält der Rückgabewert auch Millisekunden als Nachkommastellen.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
timestamp | Number | Aktuelle Uhrzeit in Form eines POSIX-Zeitstempels. |
MM.date
timestamp = MM.date()
timestamp = MM.date(timestamp, offset)
fields = MM.date(timestamp, "*t")
timestamp = MM.date(fields)
Datumsberechnungen in vier Formen:
- Ohne Parameter: der aktuelle Zeitpunkt als ganzzahliger POSIX-Zeitstempel.
- Mit einem Offset-String: verschiebt den Zeitstempel um die angegebene Anzahl Tage (
"D"), Wochen ("W"), Monate ("M"), Quartale ("Q") oder Jahre ("Y"), z. B."-30D"oder"1M". Fürtimestampkannnilübergeben werden, dann gilt der aktuelle Zeitpunkt. - Mit
"*t"als zweitem Parameter: zerlegt den Zeitstempel in eine Tabelle mit den Felderntimestamp,year,month,day(Number) undisBusinessDay(Boolean; berücksichtigt die Bankfeiertage des Landes des Bankzugangs). - Mit einer Tabelle: setzt einen Zeitstempel aus Feldern zusammen. Unterstützte Felder:
year,month,day(Standard: heutiges Datum),hour(Standard 12),min,sec(Standard 0) sowiefromundto(Zeitzonen-Namen für die Umrechnung, z. B."Europe/Berlin").
local monthAgo = MM.date(nil, "-1M")
local parts = MM.date(MM.date(), "*t")
local noonCET = MM.date{year=2026, month=9, day=3, from="Europe/Berlin"}
MM.timezone
name = MM.timezone()
Gibt den Namen der lokalen Zeitzone des Anwenders zurück.
| Rückgabe | Typ | Beschreibung |
|---|---|---|
name | String | Zeitzonen-Name, z. B. "Europe/Berlin"; "GMT", falls keine Zeitzone ermittelt werden kann. |
MM.gmtOffset
offset = MM.gmtOffset([timezone[, timestamp]])
Gibt die Abweichung einer Zeitzone von GMT in Sekunden zurück, unter Berücksichtigung der Sommerzeit zum angegebenen Zeitpunkt.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
timezone | String | ja | Zeitzonen-Name, z. B. "Europe/Berlin"; Standard ist die lokale Zeitzone. |
timestamp | Number | ja | Zeitpunkt als POSIX-Zeitstempel; Standard ist der aktuelle Zeitpunkt. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
offset | Number | Abweichung von GMT in Sekunden, z. B. 7200 für die mitteleuropäische Sommerzeit. |
Zeichenketten und Kodierung
MM.urlencode
urlencoded = MM.urlencode(str[, charset])
Wendet eine URL-Kodierung an.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
str | String | nein | Zu kodierender Text |
charset | String | ja | Zeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA. Ohne diesen Parameter wird ISO-8859-1 verwendet. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
urlencoded | String | URL-kodierter Text |
Siehe auch: MM.urldecode
MM.urldecode
str = MM.urldecode(urlencoded)
Entfernt die URL-Kodierung.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
urlencoded | String | nein | URL-kodierter Text |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
str | String | Text ohne URL-Kodierung |
Siehe auch: MM.urlencode
MM.toEncoding
data = MM.toEncoding(charset, str[, bom])
Konvertiert einen Text von UTF-8 zu einem anderen Zeichensatz.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
charset | String | nein | Zeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA. |
str | String | nein | Text in UTF-8 |
bom | Boolean | ja | Wenn dieser Parameter mit true belegt ist, wird der Rückgabewert um eine Byte Order Mark (BOM) ergänzt, sofern sie für den angegebenen Zeichensatz existiert. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
data | Binary | Text im angegebenen Zeichensatz |
Siehe auch: MM.fromEncoding
MM.fromEncoding
str = MM.fromEncoding(charset, data)
Konvertiert einen Text von einem anderen Zeichensatz zu UTF-8.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
charset | String | nein | Zeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA. |
data | Binary | nein | Text im angegebenen Zeichensatz |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
str | String | Text in UTF-8 |
Siehe auch: MM.toEncoding
MM.base64
encoded = MM.base64(data[, linebreaks])
Konvertiert Daten zu Base64.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
data | Binary | nein | Zu konvertierende Daten |
linebreaks | Boolean | ja | Wenn dieser Parameter mit true belegt ist, wird die Ausgabe wie bei PEM alle 64 Zeichen umbrochen. Standard: keine Zeilenumbrüche. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
encoded | String | Base64-kodierte Daten |
Siehe auch: MM.base64decode, MM.base64urlencode
MM.base64urlencode
encoded = MM.base64urlencode(data)
Konvertiert Daten in das URL-sichere Base64-Format (Base64URL nach RFC 4648, mit - und _ statt + und /, ohne =-Padding) — z. B. für JWTs und OAuth-Parameter.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
data | Binary | nein | Zu konvertierende Daten |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
encoded | String | Base64URL-kodierte Daten |
Siehe auch: MM.base64, MM.base64decode
MM.base64decode
data = MM.base64decode(encoded)
Konvertiert Daten von Base64. Auch Base64URL-kodierte Eingaben (-/_, fehlendes Padding) und Eingaben mit Zeilenumbrüchen werden akzeptiert.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
encoded | String | nein | Base64- oder Base64URL-kodierte Daten |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
data | Binary | Konvertierte Daten |
Siehe auch: MM.base64, MM.base64urlencode
MM.binToHex
hex = MM.binToHex(data)
Konvertiert Binärdaten in einen Hexadezimal-String.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
data | Binary | nein | Zu konvertierende Daten |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
hex | String | Hexadezimal-String in Großbuchstaben, ohne Trennzeichen |
Siehe auch: MM.hexToBin
MM.hexToBin
data = MM.hexToBin(hex)
Konvertiert einen Hexadezimal-String in Binärdaten.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
hex | String | nein | Hexadezimal-String; Groß-/Kleinschreibung ist egal, :-Trennzeichen werden ignoriert. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
data | Binary | Konvertierte Daten |
Fehlerverhalten: nil bei ungültiger Eingabe.
Siehe auch: MM.binToHex
MM.utf8len
count = MM.utf8len(str)
Liefert die Länge eines UTF-8-Strings in Unicode-Zeichen — im Gegensatz zum Lua-Operator #, der die Anzahl der Bytes liefert. (Gezählt werden UTF-16-Einheiten; Zeichen außerhalb der Basic Multilingual Plane, z. B. Emoji, zählen doppelt.)
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
str | String | nein | UTF-8-Text |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
count | Number | Anzahl der Zeichen |
MM.utf8sub
str = MM.utf8sub(str, start[, end])
Liefert einen Teilstring, wobei die Positionen wie bei MM.utf8len in Zeichen statt in Bytes zählen. Die Parameter verhalten sich wie bei der Lua-Funktion string.sub: Die Indexierung beginnt bei 1, negative Positionen zählen vom Ende, end ist standardmäßig -1 (Ende des Strings).
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
str | String | nein | UTF-8-Text |
start | Number | nein | Erste Zeichenposition |
end | Number | ja | Letzte Zeichenposition (Standard: -1) |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
str | String | Teilstring |
MM.utf8lower
str = MM.utf8lower(str)
Konvertiert einen UTF-8-String in Kleinbuchstaben — im Gegensatz zur Lua-Funktion string.lower Unicode-korrekt, also auch für Umlaute und andere Nicht-ASCII-Zeichen.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
str | String | nein | UTF-8-Text |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
str | String | Text in Kleinbuchstaben |
Hashes und Message Authentication Codes
MM.sha512, MM.sha256, MM.sha1, MM.sha3_256, MM.md5
digest = MM.sha512(data)
digest = MM.sha256(data)
digest = MM.sha1(data)
digest = MM.sha3_256(data)
digest = MM.md5(data)
Berechnet einen SHA512-, SHA256-, SHA1-, SHA3-256- oder MD5-Hashwert.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
data | Binary | nein | Daten, über die der Hashwert berechnet werden soll. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
digest | String | Hashwert als hexadezimaler String in Großbuchstaben |
MM.hmac512, MM.hmac384, MM.hmac256, MM.hmac1
digest = MM.hmac512(key, data)
digest = MM.hmac384(key, data)
digest = MM.hmac256(key, data)
digest = MM.hmac1(key, data)
Berechnet einen HMAC512-, HMAC384-, HMAC256- oder HMAC1-Message-Authentication-Code.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Binary | nein | HMAC-Schlüssel |
data | Binary | nein | Daten, über die der Message Authentication Code berechnet werden soll. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
digest | Binary | Message Authentication Code als binärer String |
Zufallswerte
MM.random
data = MM.random(length)
Generiert zufällige binäre Daten mit der angegebenen Länge.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
length | Number | nein | Anzahl der Bytes |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
data | Binary | Zufällig generierte Daten |
MM.uuid
uuid = MM.uuid()
Generiert eine zufällige UUID (Version 4).
| Rückgabe | Typ | Beschreibung |
|---|---|---|
uuid | String | UUID in Kleinbuchstaben, z. B. "f81d4fae-7dec-41d0-a765-00a0c91e6bf6" |
Umgebung
MM.productName, MM.productVersion, MM.productBuild
Diese Attribute enthalten Informationen zur Anwendung: productName (String) ist der Name der Anwendung, also "MoneyMoney", productVersion (String) die Versionsnummer, z. B. "2.4.38", und productBuild (Number) die fortlaufende Build-Nummer. Für Versionsvergleiche eignet sich productBuild, da es sich um eine Zahl handelt.
connection.useragent = "Mozilla/5.0 (compatible; " ..
MM.productName ..
"/" ..
MM.productVersion ..
")"
MM.language
Dieses Attribut vom Typ String enthält das Sprachkürzel der MoneyMoney-Benutzeroberfläche, z. B. "de" oder "en" — etwa um Fehlermeldungen der Extension in der Sprache des Anwenders auszugeben.
MM.deviceUuid
Dieses Attribut vom Typ String enthält eine zufällig erzeugte, dauerhaft gespeicherte Gerätekennung (UUID) — z. B. um bei einer Geräteregistrierung gegenüber dem Bankserver stabil dasselbe Gerät zu identifizieren. Das Attribut kann nil sein, wenn noch keine Kennung erzeugt wurde.
MM.DEBUG, MM.BETA, MM.RETAIL, MM.APPSTORE
Genau eines dieser Attribute ist gesetzt (als leerer String) und kennzeichnet die Build-Variante der laufenden Anwendung; die übrigen sind nil. Damit lässt sich Verhalten auf einzelne Varianten beschränken:
local DEBUG = MM.DEBUG ~= nil
if DEBUG then print("Rohantwort: " .. content) end
MM-Funktionen: Kryptographie
RSA
MM.rsaGenerateKeys
key = MM.rsaGenerateKeys(bits)
Erzeugt ein neues RSA-Schlüsselpaar mit dem öffentlichen Exponenten 65537.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
bits | Number | nein | Schlüssellänge in Bit (512 bis 4096) |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
key | Table | Schlüssel-Tabelle mit den Feldern n, e, d, p, q, dmp1, dmq1, iqmp (alle Binary, Big-Endian) |
Fehlerverhalten: nil bei ungültiger Schlüssellänge.
Siehe auch: MM.rsaSign, MM.rsaDecrypt, MM.pkcs8decode
MM.rsaSign
signature = MM.rsaSign(key, data, algorithm)
Signiert Daten mit einem privaten RSA-Schlüssel. Die Daten werden mit SHA-256 gehasht und der Hash nach RSASSA-PKCS1-v1_5 signiert.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Table | nein | Schlüssel-Tabelle; benötigt werden n, e, d, p, q, optional die CRT-Felder dmp1, dmq1, iqmp. |
data | Binary | nein | Zu signierende Daten |
algorithm | String | nein | "pkcs1-v1_5 sha256" |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
signature | Binary | Signatur; die Länge entspricht der Schlüssellänge. |
Fehlerverhalten: nil bei unbekanntem Algorithmus oder unpassenden Schlüsselfeldern.
Siehe auch: MM.rsaVerify, MM.ecSign
MM.rsaVerify
valid = MM.rsaVerify(key, data, signature, algorithm)
Prüft, ob eine RSA-Signatur zu den Daten und dem öffentlichen Schlüssel passt — das Gegenstück zu MM.rsaSign.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Table | nein | Schlüssel-Tabelle; benötigt werden nur n und e. |
data | Binary | nein | Signierte Daten |
signature | Binary | nein | Zu prüfende Signatur |
algorithm | String | nein | "pkcs1-v1_5 sha256" |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
valid | Boolean | true, wenn die Signatur gültig ist, sonst false. |
Fehlerverhalten: false auch bei fehlerhaften Parametern.
Siehe auch: MM.rsaSign, MM.ecVerify
MM.rsaEncrypt
encrypted = MM.rsaEncrypt(key, data, algorithm)
Verschlüsselt Daten mit einem öffentlichen RSA-Schlüssel nach RSAES-OAEP.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Table | nein | Schlüssel-Tabelle; benötigt werden nur n und e. |
data | Binary | nein | Zu verschlüsselnde Daten |
algorithm | String | nein | "pkcs1-oaep sha256" (OAEP mit SHA-256 für Hash und MGF1), "pkcs1-oaep sha512" (SHA-512 für Hash und MGF1) oder "pkcs1-oaep sha256 sha1" (SHA-256 für den Hash, SHA-1 für MGF1) |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
encrypted | Binary | Verschlüsselte Daten; die Länge entspricht der Schlüssellänge. |
Fehlerverhalten: nil bei unbekanntem Algorithmus oder unpassenden Schlüsselfeldern.
Siehe auch: MM.rsaDecrypt
MM.rsaDecrypt
data = MM.rsaDecrypt(key, encrypted, algorithm)
Entschlüsselt RSAES-OAEP-verschlüsselte Daten mit einem privaten RSA-Schlüssel.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Table | nein | Schlüssel-Tabelle; benötigt werden n, e, d, p, q, optional die CRT-Felder dmp1, dmq1, iqmp. |
encrypted | Binary | nein | Verschlüsselte Daten |
algorithm | String | nein | "pkcs1-oaep sha256" oder "pkcs1-oaep sha512" (jeweils derselbe Hash für Label und MGF1) |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
data | Binary | Entschlüsselte Daten |
Fehlerverhalten: nil bei unbekanntem Algorithmus, unpassenden Schlüsselfeldern oder fehlgeschlagener Entschlüsselung.
Siehe auch: MM.rsaEncrypt
MM.rsaPkcs1
encrypted = MM.rsaPkcs1(modulus, exponent, data)
Verschlüsselt Daten mit einem öffentlichen RSA-Schlüssel nach dem älteren RSAES-PKCS1-v1_5-Verfahren. Anders als die übrigen RSA-Funktionen nimmt diese Funktion Modulus und Exponent direkt entgegen statt einer Schlüssel-Tabelle.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
modulus | Binary | nein | Modulus n des öffentlichen Schlüssels (Big-Endian) |
exponent | Binary | nein | Öffentlicher Exponent e (Big-Endian) |
data | Binary | nein | Zu verschlüsselnde Daten |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
encrypted | Binary | Verschlüsselte Daten; die Länge entspricht der Schlüssellänge. |
Fehlerverhalten: nil bei ungültigen Parametern oder zu langen Daten.
Siehe auch: MM.rsaEncrypt
Elliptische Kurven
MM.ecGenerateKeys
key = MM.ecGenerateKeys(curve)
Erzeugt ein neues Schlüsselpaar für elliptische-Kurven-Kryptographie. Typischer Einsatz: einmalige Erzeugung eines Geräteschlüssels bei der Kontoeinrichtung, der in LocalStorage abgelegt und bei späteren Anmeldungen zum Signieren verwendet wird.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
curve | String | nein | Name der elliptischen Kurve, z. B. "prime256v1". Der Wert "ed25519" (Groß-/Kleinschreibung egal) erzeugt ein Ed25519-Schlüsselpaar. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
key | Table | Schlüssel-Tabelle, siehe unten. |
Für ECDSA-Kurven enthält die Schlüssel-Tabelle die Felder curve (String), x und y (Binary, Koordinaten des öffentlichen Punkts) sowie d (Binary, privater Skalar). Für "ed25519" enthält sie curve, x (Binary, 32 Byte, öffentlicher Schlüssel) und d (Binary, 32 Byte, privater Schlüssel).
Fehlerverhalten: nil bei unbekannter Kurve.
Siehe auch: MM.ecSign, MM.ecVerify, MM.pkcs8decode
MM.ecSign
signature = MM.ecSign(key, data, algorithm)
Signiert Daten mit einem privaten elliptische-Kurven-Schlüssel — etwa zum Signieren von API-Requests oder JWTs (mit "eddsa" auch JWTs mit dem Algorithmus EdDSA nach RFC 8037).
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Table | nein | Schlüssel-Tabelle, siehe MM.ecGenerateKeys |
data | Binary | nein | Zu signierende Daten |
algorithm | String | nein | "ecdsa sha256", "ecdsa sha512" oder "eddsa" |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
signature | Binary | Signatur; bei ECDSA DER-codiert, bei EdDSA die rohe 64-Byte-Signatur. |
Bei "ecdsa sha256"/"ecdsa sha512" werden die Daten gehasht und der Hash signiert; benötigt werden die Schlüsselfelder curve, x, y und d. Bei "eddsa" (PureEdDSA nach RFC 8032) werden die Daten direkt signiert, ohne vorgelagerten Hash; benötigt werden nur curve (= "ed25519") und d.
Fehlerverhalten: nil bei unbekanntem Algorithmus, unbekannter Kurve oder unpassenden Schlüsselfeldern.
Siehe auch: MM.ecVerify, MM.ecGenerateKeys
MM.ecVerify
valid = MM.ecVerify(key, data, signature, algorithm)
Prüft, ob eine Signatur zu den Daten und dem öffentlichen Schlüssel passt — das Gegenstück zu MM.ecSign.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Table | nein | Schlüssel-Tabelle; nur die öffentlichen Felder werden benötigt (bei ECDSA curve, x, y; bei EdDSA curve, x). Ein enthaltener privater Schlüssel d wird ignoriert. |
data | Binary | nein | Signierte Daten |
signature | Binary | nein | Zu prüfende Signatur (DER bei ECDSA, 64 Byte roh bei EdDSA) |
algorithm | String | nein | "ecdsa sha256", "ecdsa sha512" oder "eddsa" |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
valid | Boolean | true, wenn die Signatur gültig ist, sonst false. |
Fehlerverhalten: false auch bei fehlerhaften Parametern.
Siehe auch: MM.ecSign, MM.rsaVerify
Symmetrische Verschlüsselung
MM.aes256encrypt
encrypted = MM.aes256encrypt(key, iv, data)
encrypted, tag = MM.aes256encrypt(key, iv, data, "aes256 gcm", aad)
Verschlüsselt Daten mit AES-256.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Binary | nein | Schlüssel, 32 Byte |
iv | Binary | nein | Initialisierungsvektor; 16 Byte bei CBC, 12 Byte bei GCM |
data | Binary | nein | Zu verschlüsselnde Daten |
algorithm | String | ja | "aes256 cbc" (Standard) oder "aes256 gcm" |
aad | Binary | bei GCM nein | Zusätzliche authentifizierte Daten (Additional Authenticated Data); bei GCM erforderlich, darf leer sein. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
encrypted | Binary | Verschlüsselte Daten; bei CBC mit PKCS#7-Padding. |
tag | Binary | Nur bei GCM: der 16-Byte-Authentication-Tag als zweiter Rückgabewert. |
Fehlerverhalten: nil bei unbekanntem Algorithmus oder falschen Schlüssel-/IV-Längen.
Siehe auch: MM.aes256decrypt
MM.aes256decrypt
data = MM.aes256decrypt(key, iv, encrypted)
data = MM.aes256decrypt(key, iv, encrypted, "aes256 gcm", aad, tag)
Entschlüsselt AES-256-verschlüsselte Daten.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Binary | nein | Schlüssel, 32 Byte |
iv | Binary | nein | Initialisierungsvektor; 16 Byte bei CBC, 12 Byte bei GCM |
encrypted | Binary | nein | Verschlüsselte Daten |
algorithm | String | ja | "aes256 cbc" (Standard) oder "aes256 gcm" |
aad | Binary | bei GCM nein | Zusätzliche authentifizierte Daten, wie bei der Verschlüsselung übergeben |
tag | Binary | bei GCM nein | Der 16-Byte-Authentication-Tag aus der Verschlüsselung |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
data | Binary | Entschlüsselte Daten (bei CBC ohne Padding) |
Fehlerverhalten: nil bei falschen Parametern, ungültigem Padding oder — bei GCM — fehlgeschlagener Authentifizierung.
Siehe auch: MM.aes256encrypt
Schlüsselformate
MM.pkcs8decode
key = MM.pkcs8decode(data)
Liest einen Schlüssel aus dem Standard-Auslieferungsformat ein, in dem Dienste API-Schlüssel bereitstellen, und wandelt ihn in die Schlüssel-Tabelle um, die die Sign- und Verify-Funktionen erwarten. Der Schlüsseltyp (RSA, EC, Ed25519) und die Frage privat/öffentlich werden automatisch erkannt — der vom Anwender eingefügte Schlüsselblock kann also unverändert durchgereicht werden.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
data | String | nein | Schlüssel im PKCS#8- bzw. SubjectPublicKeyInfo-Format: PEM (-----BEGIN PRIVATE KEY----- / -----BEGIN PUBLIC KEY-----, auch traditionelle PEM-Formate) oder binäres DER; privat oder öffentlich. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
key | Table | Schlüssel-Tabelle mit dem Feld type ("rsa", "ec" oder "ed25519") und den typabhängigen Feldern, siehe unten. |
Typabhängige Felder der Schlüssel-Tabelle (alle Binary; die privaten Felder nur bei privaten Schlüsseln):
type | Öffentliche Felder | Private Felder | Passend für |
|---|---|---|---|
"rsa" | n, e | d, p, q, dmp1, dmq1, iqmp | MM.rsaSign, MM.rsaVerify, MM.rsaEncrypt |
"ec" | curve, x, y | d | MM.ecSign, MM.ecVerify |
"ed25519" | curve (= "ed25519"), x | d | MM.ecSign/MM.ecVerify mit "eddsa" |
Alle Zahlen-/Schlüsselfelder sind Binärstrings (Big-Endian bei RSA/EC, Rohformat bei Ed25519). Fehlt in einer EC-Schlüsseldatei der öffentliche Punkt, wird er aus dem privaten Skalar abgeleitet.
Fehlerverhalten: nil, wenn der Schlüssel nicht gelesen werden konnte.
local key = MM.pkcs8decode(apiKeyPem)
if key == nil then
return "Der API-Schlüssel konnte nicht gelesen werden."
end
local signature = MM.ecSign(key, message, "eddsa")
Siehe auch: MM.ecSign, MM.rsaSign
MM.rsaPkcs8
pem = MM.rsaPkcs8(key)
Erzeugt aus einem RSA-Schlüssel den PEM-Block des öffentlichen Schlüssels (SubjectPublicKeyInfo, -----BEGIN PUBLIC KEY-----) — z. B. um den öffentlichen Schlüssel bei einer Geräteregistrierung an einen Server zu übertragen.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
key | Table | nein | Schlüssel-Tabelle; benötigt werden nur n und e. |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
pem | String | Öffentlicher Schlüssel als PEM-Block |
Fehlerverhalten: nil bei unpassenden Schlüsselfeldern.
Siehe auch: MM.rsaGenerateKeys, MM.pkcs8decode
MM.rsaPkcs8decode
key = MM.rsaPkcs8decode(pem)
Liest einen öffentlichen RSA-Schlüssel aus einem PEM-Block (-----BEGIN PUBLIC KEY-----) und liefert die Felder n und e. Für neue Extensions wird das universellere MM.pkcs8decode empfohlen, das zusätzlich private Schlüssel, DER-Eingaben sowie EC- und Ed25519-Schlüssel versteht.
| Parameter | Typ | Optional | Beschreibung |
|---|---|---|---|
pem | String | nein | Öffentlicher RSA-Schlüssel als PEM-Block |
| Rückgabe | Typ | Beschreibung |
|---|---|---|
key | Table | Schlüssel-Tabelle mit den Feldern n und e (Binary) |
Fehlerverhalten: nil, wenn der Schlüssel nicht gelesen werden konnte.
Siehe auch: MM.pkcs8decode, MM.rsaPkcs8