diff --git a/fossa/100_config.ino b/fossa/100_config.ino index e6ed7c0..6fc592c 100644 --- a/fossa/100_config.ino +++ b/fossa/100_config.ino @@ -97,6 +97,8 @@ void setDefaultValues() { Serial.println("Max amount: " + String(maxamount)); maxBeforeReset = MAX_BEFORE_RESET; Serial.println("Max before reset: " + String(maxBeforeReset)); + convertStringToFloatArray(COIN_AMOUNTS, coinAmountFloat); + Serial.println("Coin amounts: " + String(COIN_AMOUNTS)); } void readFiles() { diff --git a/fossa/102_helpers.ino b/fossa/102_helpers.ino index 7fc88aa..9716a23 100644 --- a/fossa/102_helpers.ino +++ b/fossa/102_helpers.ino @@ -36,12 +36,20 @@ void splitSettings(String str) { int firstComma = str.indexOf(','); int secondComma = str.indexOf(',', firstComma + 1); baseURLATM = str.substring(0, firstComma); + Serial.println("baseURLATM: " + baseURLATM); + // remove /api/v1.... and add /atm?lightning= + int apiPos = baseURLATM.indexOf("api"); + baseUrlAtmPage = baseURLATM.substring(0, apiPos); + baseUrlAtmPage += "atm?lightning="; + Serial.println("baseUrlAtmPage: " + baseUrlAtmPage); secretATM = str.substring(firstComma + 1, secondComma); + Serial.println("secretATM: " + secretATM); currencyATM = str.substring(secondComma + 1); + Serial.println("currencyATM: " + currencyATM); } void convertStringToFloatArray(const char* str, float* floatArray) { - char buffer[20]; // Temporary buffer to hold each substring + char buffer[30]; // Temporary buffer to hold each substring int index = 0; // Index for the float array int bufferIndex = 0; // Index for the buffer @@ -55,7 +63,7 @@ void convertStringToFloatArray(const char* str, float* floatArray) { buffer[bufferIndex++] = str[i]; // Copy characters to buffer } } - + // Don't forget to convert the last number in the string buffer[bufferIndex] = '\0'; // Null-terminate the buffer floatArray[index] = atof(buffer); // Convert buffer to float diff --git a/fossa/103_lnurl.ino b/fossa/103_lnurl.ino index dde6ffb..67dfe59 100644 --- a/fossa/103_lnurl.ino +++ b/fossa/103_lnurl.ino @@ -1,23 +1,40 @@ -//////////////////////////////////////////// -///////////////LNURL STUFF////////////////// -////USING STEPAN SNIGREVS GREAT CRYTPO////// -////////////THANK YOU STEPAN//////////////// -//////////////////////////////////////////// - -void makeLNURL() { - int randomPin = random(1000, 9999); - byte nonce[8]; - for (int i = 0; i < 8; i++) { - nonce[i] = random(256); +void encrypt(const char* key, unsigned char* iv, int length, const char* plainText, unsigned char* outputBuffer){ + if (strlen(key) != 16) { + Serial.println("Key must be 16 bytes long. not " + String(strlen(key)) + " bytes."); + return; } + mbedtls_aes_context aes; + mbedtls_aes_init(&aes); + mbedtls_aes_setkey_enc(&aes, (const unsigned char*)key, strlen(key)*8); + mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iv, (const unsigned char*)plainText, outputBuffer); + mbedtls_aes_free(&aes); +} - byte payload[51]; // 51 bytes is max one can get with xor-encryption - - size_t payload_len = xor_encrypt(payload, sizeof(payload), (uint8_t *)secretATM.c_str(), secretATM.length(), nonce, sizeof(nonce), randomPin, float(total)); - String preparedURL = baseURLATM + "?atm=1&p="; - preparedURL += toBase64(payload, payload_len, BASE64_URLSAFE | BASE64_NOPADDING); +bool makeLNURL() { + int iv_length = 16; + unsigned char iv_init[iv_length]; + unsigned char iv[iv_length]; + for (int i = 0; i < iv_length; i++) { + iv[i] = random(0, 255); + iv_init[i] = iv[i]; + } + int randomPin = random(1000, 9999); + String payload = String(randomPin) + String(":") + String(total); + size_t payload_len = payload.length(); + int padding = 16 - (payload_len % 16); + unsigned char encrypted[payload_len + padding] = {0}; + encrypt(secretATM.c_str(), iv, payload_len + padding, payload.c_str(), encrypted); + String preparedURL = baseURLATM + "?p="; + preparedURL += toBase64(encrypted, payload_len, BASE64_URLSAFE | BASE64_NOPADDING); + preparedURL += "&iv="; + preparedURL += toBase64(iv_init, iv_length, BASE64_URLSAFE | BASE64_NOPADDING); Serial.println(preparedURL); + lnurl_encode(preparedURL); + return true; +} + +void lnurl_encode(String preparedURL) { char Buf[200]; preparedURL.toCharArray(Buf, 200); char *url = Buf; @@ -27,54 +44,6 @@ void makeLNURL() { char *charLnurl = (char *)calloc(strlen(url) * 2, sizeof(byte)); bech32_encode(charLnurl, "lnurl", data, len); to_upper(charLnurl); - qrData = baseURLATM.substring(0, baseURLATM.length() - 18) + "atm" + "?lightning=" + charLnurl; + qrData = baseUrlAtmPage + charLnurl; + Serial.println(qrData); } - -int xor_encrypt(uint8_t *output, size_t outlen, uint8_t *key, size_t keylen, uint8_t *nonce, size_t nonce_len, uint64_t pin, uint64_t amount_in_cents) { - // check we have space for all the data: - // - if (outlen < 2 + nonce_len + 1 + lenVarInt(pin) + 1 + lenVarInt(amount_in_cents) + 8) { - return 0; - } - - int cur = 0; - output[cur] = 1; // variant: XOR encryption - cur++; - - // nonce_len | nonce - output[cur] = nonce_len; - cur++; - memcpy(output + cur, nonce, nonce_len); - cur += nonce_len; - - // payload, unxored first - - int payload_len = lenVarInt(pin) + 1 + lenVarInt(amount_in_cents); - output[cur] = (uint8_t)payload_len; - cur++; - uint8_t *payload = output + cur; // pointer to the start of the payload - cur += writeVarInt(pin, output + cur, outlen - cur); // pin code - cur += writeVarInt(amount_in_cents, output + cur, outlen - cur); // amount - cur++; - - // xor it with round key - uint8_t hmacresult[32]; - SHA256 h; - h.beginHMAC(key, keylen); - h.write((uint8_t *)"Round secret:", 13); - h.write(nonce, nonce_len); - h.endHMAC(hmacresult); - for (int i = 0; i < payload_len; i++) { - payload[i] = payload[i] ^ hmacresult[i]; - } - - // add hmac to authenticate - h.beginHMAC(key, keylen); - h.write((uint8_t *)"Data:", 5); - h.write(output, cur); - h.endHMAC(hmacresult); - memcpy(output + cur, hmacresult, 8); - cur += 8; - - // return number of bytes written to the output - return cur; -} \ No newline at end of file diff --git a/fossa/105_display.ino b/fossa/105_display.ino index ad0f7cc..4b9c939 100644 --- a/fossa/105_display.ino +++ b/fossa/105_display.ino @@ -33,7 +33,7 @@ void feedmefiatloop() { delay(100); } -void qrShowCodeLNURL(String message) { +void qrShowCodeLNURL() { #ifdef PRINTER printMessage(printingT, waitT, "", TFT_WHITE, TFT_BLACK); delay(3000); @@ -59,7 +59,7 @@ void qrShowCodeLNURL(String message) { tft.setCursor(40, 290); tft.setTextSize(2); tft.setTextColor(TFT_BLACK, TFT_WHITE); - tft.println(message); + tft.println(scanMeT); delay(2000); waitForTap = true; while (waitForTap) { diff --git a/fossa/fossa.ino b/fossa/fossa.ino index cf44db8..0bf33d2 100644 --- a/fossa/fossa.ino +++ b/fossa/fossa.ino @@ -4,28 +4,30 @@ #include #include #include -#include #include #include "qrcoded.h" #include "Bitcoin.h" -#include -#include +#include +#include "mbedtls/aes.h" + #define FORMAT_ON_FAIL true #define PARAM_FILE "/elements.json" -#include +#define VERSION "0.3.0" + +//#define BILL_ACCEPTOR +#define BILL_RX 32 // RX Bill acceptor +#define BILL_TX 33 // TX Bill acceptor -//#define PRINTER -#define BILL_ACCEPTOR #define COIN_ACCEPTOR +#define COIN_TX 34 // TX Coinmech +#define COIN_INHIBIT 35 // Coinmech interrupt -#define BTN1 39 // Screen tap button -#define BILL_RX 32 // RX Bill acceptor -#define BILL_TX 33 // TX Bill acceptor -#define COIN_TX 4 // TX Coinmech -#define COIN_INHIBIT 2 // Coinmech -#define PRINTER_RX 22 // RX of the thermal printer -#define PRINTER_TX 23 // TX of the thermal printer +//#define PRINTER +#define PRINTER_RX 22 // RX of the thermal printer +#define PRINTER_TX 23 // TX of the thermal printer + +#define BTN1 21 // Screen tap button // uncomment to use always hardcoded default settings #define HARDCODED @@ -35,7 +37,10 @@ #define CHARGE 10 // % you will charge people for service, set in LNbits extension #define MAX_AMOUNT 30 // max amount per withdraw #define MAX_BEFORE_RESET 300 // max amount you want to sell in the atm before having to reset power -#define DEVICE_STRING "https://XXXX.lnbits.com/fossa/api/v1/lnurl/XXXXX,XXXXXXXXXXXXXXXXXXXXXX,USD" +//#define DEVICE_STRING "https://XXXX.lnbits.com/fossa/api/v1/lnurl/XXXXX,XXXXXXXXXXXXXXXX,EUR" +#define DEVICE_STRING "https://test.b1tco1n.org/fossa/api/v1/lnurl/atm/T7HxgedvRJCZVHTm,9rtVvLAsx22hk9W6,USD" +#define COIN_AMOUNTS "0.05,1.0,0.25,0.5,0.1,2.0" +//#define BILL_AMOUNTS "0.01,0.05,0.1,0.25,0.5,1" int billAmountInt[16]; float coinAmountFloat[6]; @@ -46,6 +51,7 @@ String language; String deviceString; String baseURLATM; +String baseUrlAtmPage; String secretATM; String currencyATM; @@ -86,8 +92,10 @@ Adafruit_Thermal printer(&SerialPrinter); TFT_eSPI tft = TFT_eSPI(TFT_WIDTH, TFT_HEIGHT); Button BTNA(BTN1); + void setup() { Serial.begin(115200); + Serial.println("Welcome to FOSSA, running on version: " + String(VERSION)); Serial.println("TFT: " + String(TFT_WIDTH) + "x" + String(TFT_HEIGHT)); Serial.println("TFT pin MISO: " + String(TFT_MISO)); Serial.println("TFT pin CS: " + String(TFT_CS)); @@ -116,21 +124,30 @@ void setup() { readFiles(); translateAll(language); # endif + + splitSettings(deviceString); + BTNA.begin(); FlashFS.begin(FORMAT_ON_FAIL); + tft.init(); tft.setRotation(1); tft.invertDisplay(false); + + char buf[100]; + sprintf(buf, "TFT (%dx%d) initialized.", TFT_WIDTH, TFT_HEIGHT); + Serial.println(buf); + printMessage("", "Loading..", "", TFT_WHITE, TFT_BLACK); - splitSettings(deviceString); #ifdef BILL_ACCEPTOR - SerialBillAcceptor.begin(300, SERIAL_8N2, BILL_TX, BILL_RX); + SerialBillAcceptor.begin(300, SERIAL_8N2, BILL_RX, BILL_TX); Serial.println("Bill Acceptor serial started."); #endif #ifdef COIN_ACCEPTOR + pinMode(COIN_TX, INPUT); + pinMode(COIN_INHIBIT, INPUT); SerialCoinAcceptor.begin(4800, SERIAL_8N1, COIN_TX); - pinMode(COIN_INHIBIT, OUTPUT); Serial.println("Coin Acceptor serial started."); #endif #ifdef PRINTER @@ -141,24 +158,30 @@ void setup() { void loop() { if (maxBeforeResetTally >= maxBeforeReset) { + Serial.println("Max amount reached, please reset power."); printMessage("", tooMuchFiatT, contactOwnerT, TFT_WHITE, TFT_BLACK); delay(100000000); } else { +#ifdef BILL_ACCEPTOR SerialBillAcceptor.write(184); - digitalWrite(COIN_INHIBIT, HIGH); +#endif +#ifdef COIN_ACCEPTOR + digitalWrite(COIN_INHIBIT, LOW); +#endif tft.fillScreen(TFT_BLACK); BTNA.read(); // needed to clear accidental taps moneyTimerFun(); - Serial.println(total); - Serial.println(maxBeforeResetTally); + Serial.println("Total: " + String(total)); + Serial.println("maxBeforeResetTally: " + String(maxBeforeResetTally)); maxBeforeResetTally = maxBeforeResetTally + (total / 100); - Serial.println(maxBeforeResetTally); + Serial.println("maxBeforeResetTally: " + String(maxBeforeResetTally)); makeLNURL(); - qrShowCodeLNURL(scanMeT); + qrShowCodeLNURL(); } } void moneyTimerFun() { + Serial.println("Waiting for money..."); waitForTap = true; coins = 0; bills = 0; @@ -171,10 +194,10 @@ void moneyTimerFun() { feedmefiat(); feedmefiatloop(); } + #ifdef BILL_ACCEPTOR if (SerialBillAcceptor.available()) { int x = SerialBillAcceptor.read(); - for (int i = 0; i < billAmountSize; i++) { if ((i + 1) == x) { bills = bills + billAmountInt[i]; @@ -183,24 +206,25 @@ void moneyTimerFun() { } } } - // Turn off - SerialBillAcceptor.write(185); #endif + #ifdef COIN_ACCEPTOR if (SerialCoinAcceptor.available()) { int x = SerialCoinAcceptor.read(); - printMessage("", "WARNING: print bool", String(x), TFT_WHITE, TFT_BLACK); - delay(3000); - for (int i = 0; i < coinAmountSize; i++) { - if ((i + 1) == x) { - coins = coins + coinAmountFloat[i]; - total = (coins + bills); - printMessage(coinAmountFloat[i] + currencyATM, totalT + String(total) + currencyATM, tapScreenT, TFT_WHITE, TFT_BLACK); - } + //printMessage("", "WARNING: print bool", String(x), TFT_WHITE, TFT_BLACK); + //delay(3000); + for (int i = 0; i < coinAmountSize; i++) { + if (i + 1 == x) { + coins = coins + coinAmountFloat[i]; + total = (coins + bills); + String printCoin = coinAmountFloat[i] + currencyATM; + Serial.println("Coin inserted: " + String(i) + " -> " + printCoin); + String printTotal = totalT + String(total) + currencyATM; + Serial.println(printTotal); + printMessage(printCoin, printTotal, tapScreenT, TFT_WHITE, TFT_BLACK); } + } } - // Turn off - digitalWrite(COIN_INHIBIT, LOW); #endif BTNA.read(); if (BTNA.wasReleased() || total > maxamount) { @@ -209,4 +233,12 @@ void moneyTimerFun() { homeScreenNumColorCount++; } total = (coins + bills) * 100; +#ifdef BILL_ACCEPTOR + // Turn off + SerialBillAcceptor.write(185); +#endif +#ifdef COIN_ACCEPTOR + // Turn off + digitalWrite(COIN_INHIBIT, LOW); +#endif }