diff --git a/Securitas/.gitignore b/Securitas/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/Securitas/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/Securitas/.vscode/extensions.json b/Securitas/.vscode/extensions.json new file mode 100644 index 0000000..0f0d740 --- /dev/null +++ b/Securitas/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} diff --git a/Securitas/.vscode/settings.json b/Securitas/.vscode/settings.json new file mode 100644 index 0000000..22ba5ac --- /dev/null +++ b/Securitas/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "files.associations": { + "cstddef": "cpp", + "ranges": "cpp", + "functional": "cpp" + } +} \ No newline at end of file diff --git a/Securitas/include/README b/Securitas/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/Securitas/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/Securitas/lib/README b/Securitas/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/Securitas/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/Securitas/platformio.ini b/Securitas/platformio.ini new file mode 100644 index 0000000..9778b2c --- /dev/null +++ b/Securitas/platformio.ini @@ -0,0 +1,23 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:wemos_d1_mini32] +platform = espressif8266 +board = d1_mini_pro +framework = arduino +lib_deps = + https://git.aterve.com/Frozenverse/SimpleSerialProtocol.git + https://git.aterve.com/Frozenverse/KeyValueEEPROM.git + adafruit/Adafruit Fingerprint Sensor Library@^2.0.7 + plerup/EspSoftwareSerial@^6.15.2 + adafruit/Adafruit GFX Library@^1.10.12 + adafruit/Adafruit SSD1306@^2.5.1 + adafruit/Adafruit BusIO@^1.10.1 + diff --git a/Securitas/src/connections.h b/Securitas/src/connections.h new file mode 100644 index 0000000..a2331ff --- /dev/null +++ b/Securitas/src/connections.h @@ -0,0 +1,127 @@ +#pragma once +#include +#include +#include +#include +#include + +#define SERIAL_PACKET_BUFFER_SIZE 25 + +namespace Connections { + void init(); + void handle(); + void sendPacket(char *id, char *type, char *data); + void onSerialPacket(Packet packet); + + long lastPacketTransmit = 0; + Packet serialPackets[SERIAL_PACKET_BUFFER_SIZE]; + SimpleSerialProtocol device; + + Packet *name_packet; +} + +void Connections::init() { + Display::drawStatus("Init serial: ..."); + + for (int i = 0; i < SERIAL_PACKET_BUFFER_SIZE; i++) { + serialPackets[i].id = "--"; + serialPackets[i].type = "--"; + serialPackets[i].data = "--"; + } + + Connections::device.init(Serial, 9600); + Display::drawStatus("Init serial: ok!"); + + Serial.print("!***!"); + delay(750); +} + +void Connections::handle() { + device.receivePackets(Connections::onSerialPacket); + + for (int i = 0; i < SERIAL_PACKET_BUFFER_SIZE; i++) { + if (!(strcmp(serialPackets[i].id, "--") == 0)) { + if ((millis() - lastPacketTransmit) > 500) { + device.sendPacket(serialPackets[i].id, serialPackets[i].type, serialPackets[i].data); + + serialPackets[i].id = "--"; + serialPackets[i].type = "--"; + serialPackets[i].data = "--"; + + lastPacketTransmit = millis(); + + break; + } + } + } +} + +void Connections::sendPacket(char *id, char *type, char *data) { + for (int i = 0; i < SERIAL_PACKET_BUFFER_SIZE; i++) { + if (strcmp(serialPackets[i].id, "--") == 0) { + serialPackets[i].id = id; + serialPackets[i].type = type; + serialPackets[i].data = data; + + break; + } + } +} + +void Connections::onSerialPacket(Packet packet) { + if (strcmp(packet.id, "test") == 0) { + Connections::sendPacket("received", "received", "received"); + } + + if (strcmp(packet.id, "passwords") == 0 && strcmp(packet.type, "available") == 0) { + char* passwords = (char*)Passwords::available(); + Connections::sendPacket("passwords", "available_passwords", passwords); + } + + if (strcmp(packet.id, "fingerprint") == 0 && strcmp(packet.type, "enroll") == 0) { + int id = atoi(packet.data); + bool status = FingerPrintSensor::enroll(id); + + if (status) { + + Connections::sendPacket("fingerprint", "auth_status", "valid"); + } else { + Connections::sendPacket("fingerprint", "auth_status", "invalid"); + } + // char* status = (char*)char(enroll_status); + Connections::sendPacket("fingerprint", "enroll_status", ""); + } + + if (strcmp(packet.id, "fingerprint") == 0 && strcmp(packet.type, "auth") == 0) { + int status = FingerPrintSensor::authenticate(); + if (status) { + Connections::sendPacket("fingerprint", "auth_status", "valid"); + Display::drawStatus("Ready!"); + FingerPrintSensor::color(2); + + } else { + Connections::sendPacket("fingerprint", "auth_status", "invalid"); + Display::drawStatus("Not authenticated!"); + FingerPrintSensor::color(1); + } + } + + if (strcmp(packet.id, "passwords") == 0 && strcmp(packet.type, "available") == 0) { + const char * data = Passwords::available(); + Connections::sendPacket("passwords", "available_passwords", (char*)data); + } + + if (strcmp(packet.id, "new_password") == 0) { + Passwords::store(packet.type, packet.data); + } + + if (strcmp(packet.id, "passwords") == 0 && strcmp(packet.type, "new_available") == 0) { + Passwords::setAvailable(packet.data); + } + + if (strcmp(packet.id, "passwords") == 0 && strcmp(packet.type, "load") == 0) { + const char* password = Passwords::get(packet.data); + // const char* password = "ds"; + Connections::sendPacket("passwords", "password", (char*)password); + } +} \ No newline at end of file diff --git a/Securitas/src/display.h b/Securitas/src/display.h new file mode 100644 index 0000000..b0bb9ff --- /dev/null +++ b/Securitas/src/display.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include + +#define SCREEN_RESET 0 // GPIO0 +#define SCREEN_ADDRESS 0x3C +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 32 // OLED display height, in pixels + +namespace Display +{ + Adafruit_SSD1306 _display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, SCREEN_RESET); + + void init(); + void drawText(int x, int y, char* text); + void drawRectangle(int x, int y, int w, int h); + void drawStatus(char* status); +} + + +void Display::init() { + // Init screen bus + if(!_display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { + return; + } + + // Init screen buffer + _display.display(); + _display.clearDisplay(); + + Display::drawRectangle(0, 0, 128, 32); + Display::drawText(24, 3, "Securitas Mk 1"); + Display::drawText(8, 16, "Made by Nick Leeman"); + + delay(750); +} + +void Display::drawStatus(char* status) { + _display.clearDisplay(); + Display::drawRectangle(0, 0, 128, 32); + Display::drawText(3, 3, "Securitas Mk 1"); + Display::drawText(95, 3, "21:28"); + Display::drawText(3, 20, status); +} + +void Display::drawText(int x, int y, char* text) { + // Normal 1:1 pixel scale + _display.setTextSize(1); + + // Draw white text + _display.setTextColor(SSD1306_WHITE); + + // Start at top-left corner + _display.setCursor(x, y); + + // Use full 256 char 'Code Page 437' font + _display.cp437(true); + + // Write text + _display.printf(text); + + // Update buffer + _display.display(); +} + +void Display::drawRectangle(int x, int y, int w, int h) { + _display.drawRect(x, y, w, h, SSD1306_WHITE); +} \ No newline at end of file diff --git a/Securitas/src/fingersensor.h b/Securitas/src/fingersensor.h new file mode 100644 index 0000000..3646829 --- /dev/null +++ b/Securitas/src/fingersensor.h @@ -0,0 +1,356 @@ +#pragma once + +#include +#include + +namespace FingerPrintSensor +{ + SoftwareSerial fingerSensorSerial(12, 14); + Adafruit_Fingerprint finger = Adafruit_Fingerprint(&fingerSensorSerial); + + bool authenticated = false; + + void init(); + bool enroll(int id); + bool authenticate(); + void color(int type); +} + +void FingerPrintSensor::init() { + Display::drawStatus("Init fingerprint: ..."); + + // set the data rate for the sensor serial port + finger.begin(57600); + delay(50); + + if (!finger.verifyPassword()) { + Display::drawStatus("Init fingerprint: err!"); + return; + } + + finger.getParameters(); + + Display::drawStatus("Init fingerprint: ok!"); + delay(750); +} + +bool FingerPrintSensor::enroll(int id) { + Display::drawStatus("Enrolling process"); + delay(1000); + + int status = -1; + + while (status != FINGERPRINT_OK) { + status = finger.getImage(); + + switch (status) { + case FINGERPRINT_OK: + Display::drawStatus("Image captured!"); + delay(1000); + break; + + case FINGERPRINT_NOFINGER: + Display::drawStatus("Place finger..."); + delay(250); + break; + + case FINGERPRINT_PACKETRECIEVEERR: + Display::drawStatus("Comms error..."); + delay(1000); + break; + + case FINGERPRINT_IMAGEFAIL: + Display::drawStatus("Image error!"); + delay(1000); + break; + + default: + Display::drawStatus("Unknown error!"); + delay(1000); + break; + } + } + + status = finger.image2Tz(1); + switch (status) { + case FINGERPRINT_OK: + Display::drawStatus("Image Converted!"); + delay(1000); + break; + + case FINGERPRINT_IMAGEMESS: + Display::drawStatus("Bad image quality!"); + delay(1000); + return false; + + case FINGERPRINT_PACKETRECIEVEERR: + Display::drawStatus("Comms error..."); + delay(1000); + return false; + + case FINGERPRINT_FEATUREFAIL: + Display::drawStatus("No features!"); + delay(1000); + return false; + + case FINGERPRINT_INVALIDIMAGE: + Display::drawStatus("Invalid features!"); + delay(1000); + return false; + + default: + Display::drawStatus("Unknown error!"); + delay(1000); + return false; + } + + status = 0; + while (status != FINGERPRINT_NOFINGER) { + status = finger.getImage(); + } + + + status = -1; + Display::drawStatus("Place finger again!"); + delay(1000); + + while (status != FINGERPRINT_OK) { + status = finger.getImage(); + + switch (status) { + case FINGERPRINT_OK: + Display::drawStatus("Image captured!"); + delay(1000); + break; + + case FINGERPRINT_NOFINGER: + Display::drawStatus("Place finger..."); + delay(250); + break; + + case FINGERPRINT_PACKETRECIEVEERR: + Display::drawStatus("Comms error..."); + delay(1000); + break; + + case FINGERPRINT_IMAGEFAIL: + Display::drawStatus("Image error!"); + delay(1000); + break; + + default: + Display::drawStatus("Unknown error!"); + delay(1000); + break; + } + } + + status = finger.image2Tz(2); + switch (status) { + case FINGERPRINT_OK: + Display::drawStatus("Image converted!"); + delay(1000); + break; + + case FINGERPRINT_IMAGEMESS: + Display::drawStatus("Bad image quality!"); + delay(1000); + return false; + + case FINGERPRINT_PACKETRECIEVEERR: + Display::drawStatus("Comms error..."); + delay(1000); + return false; + + case FINGERPRINT_FEATUREFAIL: + Display::drawStatus("No features!"); + delay(1000); + return false; + + case FINGERPRINT_INVALIDIMAGE: + Display::drawStatus("Invalid features!"); + delay(1000); + return false; + + default: + Display::drawStatus("Unknown error!"); + delay(1000); + return false; + } + + Display::drawStatus("Creating model..."); + delay(1000); + + status = finger.createModel(); + if (status == FINGERPRINT_OK) { + Display::drawStatus("Enroll match!"); + delay(1000); + } + + else if (status == FINGERPRINT_PACKETRECIEVEERR) { + Display::drawStatus("Comms error..."); + delay(1000); + return false; + } + + else if (status == FINGERPRINT_ENROLLMISMATCH) { + Display::drawStatus("Finger mismatch!"); + delay(1000); + return false; + } + + else { + Display::drawStatus("Unknown error!"); + delay(1000); + return false; + } + + Serial.print("ID "); Serial.println(id); + status = finger.storeModel(id); + if (status == FINGERPRINT_OK) { + Display::drawStatus("Enroll success!"); + delay(1000); + } + + else if (status == FINGERPRINT_PACKETRECIEVEERR) { + Display::drawStatus("Comms error..."); + delay(1000); + return false; + } + + else if (status == FINGERPRINT_BADLOCATION) { + Display::drawStatus("Invalid id!"); + delay(1000); + return false; + } + + else if (status == FINGERPRINT_FLASHERR) { + Display::drawStatus("Invalid flash!"); + delay(1000); + return false; + } + + else { + Display::drawStatus("Unknown error!"); + delay(1000); + return false; + } + + return true; +} + +bool FingerPrintSensor::authenticate() { + uint8_t status = finger.getImage(); + + while (status != FINGERPRINT_OK) + { + status = finger.getImage(); + switch (status) { + case FINGERPRINT_OK: + Display::drawStatus("Finger scanned!"); + delay(1000); + break; + + case FINGERPRINT_NOFINGER: + Display::drawStatus("Place finger..."); + delay(1000); + break; + + case FINGERPRINT_PACKETRECIEVEERR: + Display::drawStatus("Comms error..."); + delay(1000); + return false; + + case FINGERPRINT_IMAGEFAIL: + Display::drawStatus("Image error!"); + delay(1000); + return false; + + default: + Display::drawStatus("Unknown error!"); + delay(1000); + return false; + } + } + + + + // OK success! + + status = finger.image2Tz(); + switch (status) { + case FINGERPRINT_OK: + Display::drawStatus("Image converted!"); + delay(1000); + break; + + case FINGERPRINT_IMAGEMESS: + Display::drawStatus("Bad image quality!"); + delay(1000); + return false; + + case FINGERPRINT_PACKETRECIEVEERR: + Display::drawStatus("Comms error..."); + delay(1000); + return false; + + case FINGERPRINT_FEATUREFAIL: + Display::drawStatus("Invalid features!"); + delay(1000); + return false; + + case FINGERPRINT_INVALIDIMAGE: + Display::drawStatus("Invalid features!"); + delay(1000); + return false; + + default: + Display::drawStatus("Unknown error!"); + delay(1000); + return false; + } + + // OK converted! + status = finger.fingerSearch(); + if (status == FINGERPRINT_OK) { + Display::drawStatus("Fingerprint valid!"); + authenticated = true; + delay(1000); + return true; + } + + else if (status == FINGERPRINT_PACKETRECIEVEERR) { + Display::drawStatus("Comms error!"); + delay(1000); + return false; + } + + else if (status == FINGERPRINT_NOTFOUND) { + Display::drawStatus("No match found!"); + delay(1000); + return false; + } + + else { + Display::drawStatus("Unknown error!"); + delay(1000); + return false; + } +} + +void FingerPrintSensor::color(int type) { + switch (type) + { + case 0: + finger.LEDcontrol(FINGERPRINT_LED_OFF, 0, FINGERPRINT_LED_RED); + break; + + case 1: + finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_RED); + break; + + case 2: + finger.LEDcontrol(FINGERPRINT_LED_ON, 0, FINGERPRINT_LED_BLUE); + break; + } +} diff --git a/Securitas/src/main.cpp b/Securitas/src/main.cpp new file mode 100644 index 0000000..6c8ad69 --- /dev/null +++ b/Securitas/src/main.cpp @@ -0,0 +1,23 @@ +#include + +#include +#include +#include +#include + + +void setup() +{ + Display::init(); + Connections::init(); + Passwords::init(); + FingerPrintSensor::init(); + Connections::sendPacket("device", "init", "ready"); + + FingerPrintSensor::color(1); + Display::drawStatus("Not authenticated!"); +} + +void loop() { + Connections::handle(); +} \ No newline at end of file diff --git a/Securitas/src/passwords.h b/Securitas/src/passwords.h new file mode 100644 index 0000000..83fd7da --- /dev/null +++ b/Securitas/src/passwords.h @@ -0,0 +1,53 @@ +#pragma once +#include +#include +#include + +namespace Passwords +{ + void init(); + const char* available(); + void setAvailable(char * passwords); + void store(char* name, char* password); + const char* get(char* name); +} + +void Passwords::init() { + Display::drawStatus("Init Passwords..."); + KeyValueEEPROM.begin(); + + if(!KeyValueEEPROM.exists("stored-passwords")) { + KeyValueEEPROM.set("stored-passwords", ""); + } + + delay(750); +} + +const char* Passwords::available() { + if (FingerPrintSensor::authenticated) { + char * key = "stored-passwords"; + return KeyValueEEPROM.get(key); + } else { + return "-"; + } +} + +void Passwords::setAvailable(char * passwords) { + if (FingerPrintSensor::authenticated) { + KeyValueEEPROM.set("stored-passwords", passwords); + } +} + +void Passwords::store(char* name, char* password) { + if (FingerPrintSensor::authenticated) { + KeyValueEEPROM.set(name, password); + } +} + +const char* Passwords::get(char* name) { + if (FingerPrintSensor::authenticated) { + return KeyValueEEPROM.get(name, "--"); + } + + return "-"; +} \ No newline at end of file diff --git a/Securitas/test/README b/Securitas/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/Securitas/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/SecuritasApp/go.mod b/SecuritasApp/go.mod new file mode 100644 index 0000000..509267c --- /dev/null +++ b/SecuritasApp/go.mod @@ -0,0 +1,32 @@ +module frozenverse/securitas + +go 1.17 + +require fyne.io/fyne/v2 v2.1.2 + +require ( + github.com/creack/goselect v0.1.2 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f // indirect + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be // indirect + github.com/godbus/dbus/v5 v5.0.4 // indirect + github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect + github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect + github.com/stretchr/testify v1.7.0 // indirect + github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 + github.com/yuin/goldmark v1.3.8 // indirect + go.bug.st/serial v1.3.4 + golang.org/x/image v0.0.0-20200430140353-33d19683fad8 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect + golang.org/x/text v0.3.3 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect +) diff --git a/SecuritasApp/go.sum b/SecuritasApp/go.sum new file mode 100644 index 0000000..6b5cfef --- /dev/null +++ b/SecuritasApp/go.sum @@ -0,0 +1,98 @@ +fyne.io/fyne/v2 v2.1.2 h1:avp9CvLAUdvE7fDMtH1tVKyjxEWHWcpow6aI6L7Kvvw= +fyne.io/fyne/v2 v2.1.2/go.mod h1:p+E/Dh+wPW8JwR2DVcsZ9iXgR9ZKde80+Y+40Is54AQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= +github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA= +github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f h1:s0O46d8fPwk9kU4k1jj76wBquMVETx7uveQD9MCIQoU= +github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f/go.mod h1:wjpnOv6ONl2SuJSxqCPVaPZibGFdSci9HFocT9qtVYM= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be h1:Z28GdQBfKOL8tNHjvaDn3wHDO7AzTRkmAXvHvnopp98= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= +github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= +github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= +github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM= +github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= +github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM= +github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E= +github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.bug.st/serial v1.3.4 h1:fMpfNEOsPQjYGZ3VHcs/xxsxoaPgbcjrm4YnMkcir3Y= +go.bug.st/serial v1.3.4/go.mod h1:z8CesKorE90Qr/oRSJiEuvzYRKol9r/anJZEb5kt304= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/SecuritasApp/main.go b/SecuritasApp/main.go new file mode 100644 index 0000000..b4f9ec8 --- /dev/null +++ b/SecuritasApp/main.go @@ -0,0 +1,252 @@ +package main + +import ( + "fmt" + "log" + "strings" + "time" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/dialog" + "fyne.io/fyne/v2/widget" + "go.bug.st/serial" + "go.bug.st/serial/enumerator" +) + +type Packet struct { + Id string + Type string + Data string +} + +var serialPort serial.Port +var isAuthenticated bool = false +var application = app.New() +var window = application.NewWindow("Securitas") + +var authBtn = widget.NewButton("Authenticate", func() { + go sendPacket("fingerprint", "auth", "-") +}) + +var loadPasswordsBtn = widget.NewButton("Load Passwords", func() { + go sendPacket("passwords", "available", "-") +}) + +var addPasswordBtn = widget.NewButton("Add password", func() { + nameEntry := widget.NewEntry() + passwordEntry := widget.NewEntry() + + var items = []*widget.FormItem{ + {Text: "Name", Widget: nameEntry}, + {Text: "Password", Widget: passwordEntry}, + } + + go dialog.ShowForm("New Password", "Create", "Cancel", items, func(status bool) { + if !status { + return + } + + sendPacket("new_password", nameEntry.Text, passwordEntry.Text) + time.Sleep(time.Millisecond * 750) + + newPasswordsArray := append(passwordSelector.Options, nameEntry.Text) + newPasswords := strings.Join(newPasswordsArray[:], "-") + sendPacket("passwords", "new_available", newPasswords) + time.Sleep(time.Millisecond * 750) + + go sendPacket("passwords", "available", "-") + }, window) +}) + +var enrollBtn = widget.NewButton("Enroll", func() { + go sendPacket("fingerprint", "enroll", "1") +}) + +var passwordSelector = widget.NewSelect([]string{}, func(value string) { + log.Println("Select set to", value) +}) + +var getPasswordBtn = widget.NewButton("Get", func() { + go sendPacket("passwords", "load", passwordSelector.Selected) +}) + +func main() { + window.Resize(fyne.NewSize(600, 400)) + window.CenterOnScreen() + window.SetFixedSize(true) + + titleText := widget.NewLabel("Password manager") + titleText.TextStyle.Bold = true + + txtResults := widget.NewTextGrid() + txtResults.ShowLineNumbers = true + + loadPasswordsBtn.Disable() + // addPasswordBtn.Disable() + enrollBtn.Disable() + + cntButtons := container.NewGridWithColumns(4, authBtn, loadPasswordsBtn, addPasswordBtn, enrollBtn) + cntSelection := container.NewGridWithColumns(2, passwordSelector, getPasswordBtn) + cntContent := container.NewGridWithRows(3, titleText, cntSelection, cntButtons) + + window.SetContent(cntContent) + + go handleSerial() + + window.ShowAndRun() +} + +func handleSerial() { + ports, err := enumerator.GetDetailedPortsList() + if err != nil { + log.Fatal(err) + } + if len(ports) == 0 { + fmt.Println("No serial ports found!") + return + } + for _, port := range ports { + fmt.Printf("Found port: %s\n", port.Name) + if port.IsUSB { + fmt.Printf(" USB ID %s:%s\n", port.VID, port.PID) + fmt.Printf(" USB serial %s\n", port.SerialNumber) + } + } + + fmt.Println("") + + for { + var device string = "/dev/ttyUSB0" + fmt.Println("Trying to connect to: ", device) + + mode := &serial.Mode{ + BaudRate: 9600, + } + + port, err := serial.Open(device, mode) + if err != nil { + log.Fatal(err) + time.Sleep(time.Second * 2) + } + + serialPort = port + + fmt.Println("Connected to: ", device) + fmt.Println("") + + reading := false + for { + data := "" + buffer := make([]byte, 512) + + for { + n, err := port.Read(buffer) + + if err != nil { + fmt.Printf("Error occured: %v", err.Error()) + break + } + + if n == 0 { + fmt.Println("\nEOF") + break + } + + if strings.Contains(string(buffer[:n]), "!***!") { + reading = true + data = "" + buffer = make([]byte, 1024) + } + + if !reading { + break + } + + data += string(buffer[:n]) + + if strings.Contains(string(buffer[:n]), "\n") { + fmt.Printf("%#v\n", data) + break + } + } + + if !reading { + continue + } + + data = strings.ReplaceAll(data, "\x00", "") + data = strings.ReplaceAll(data, "\xb4", "") + data = strings.ReplaceAll(data, "\xc3", "") + data = strings.ReplaceAll(data, "\r\n", "") + + pieces := strings.Split(data, "\xc4") + + var packet Packet + packet.Id = pieces[0] + packet.Type = pieces[1] + packet.Data = pieces[2] + + go handlePacket(&packet) + // fmt.Printf("%#v\n", data) + } + + // var newPacket Packet + // err = json.Unmarshal([]byte(`{\"id\":\"fingerprint_init\",\"type\":""\"found\",\"data\":\"true\",\"overflow\""":false}`), &newPacket) + // if err != nil { + // fmt.Println(err) + // } + } +} + +func sendPacket(pId string, pType string, pData string) { + n, err := serialPort.Write([]byte("\xb4" + pId + "\xc4" + pType + "\xc4" + pData + "\xc3\r\n")) + if err != nil { + log.Fatal(err) + } + + fmt.Println("-------- Send Packet --------") + fmt.Println("ID: ", pId) + fmt.Println("Type: ", pType) + fmt.Println("Data: ", pData) + fmt.Printf("Send %v bytes\n", n) +} + +func handlePacket(packet *Packet) { + fmt.Println("-------- New Packet --------") + fmt.Printf("ID: %#v\n", packet.Id) + fmt.Printf("Type: %#v\n", packet.Type) + fmt.Printf("Data: %#v\n", packet.Data) + + if packet.Id == "fingerprint" { + if packet.Type == "enroll_status" { + + } + + if packet.Type == "auth_status" { + if packet.Data == "valid" { + isAuthenticated = true + authBtn.Disable() + loadPasswordsBtn.Enable() + addPasswordBtn.Enable() + enrollBtn.Enable() + } else { + isAuthenticated = false + } + } + } + + if packet.Id == "passwords" { + if packet.Type == "available_passwords" { + if len(packet.Data) >= 1 { + passwordSelector.Options = strings.Split(packet.Data, "-") + } else { + var empty [0]string + passwordSelector.Options = empty[:] + } + + loadPasswordsBtn.Disable() + } + } +} diff --git a/securitas-bottom.stl b/securitas-bottom.stl new file mode 100644 index 0000000..e221562 Binary files /dev/null and b/securitas-bottom.stl differ diff --git a/securitas-casing.stl b/securitas-casing.stl new file mode 100644 index 0000000..ad93dd3 Binary files /dev/null and b/securitas-casing.stl differ diff --git a/securitas-top.stl b/securitas-top.stl new file mode 100644 index 0000000..7f8ea73 Binary files /dev/null and b/securitas-top.stl differ diff --git a/securitas.FCStd b/securitas.FCStd new file mode 100644 index 0000000..7034d68 Binary files /dev/null and b/securitas.FCStd differ diff --git a/securitas.FCStd1 b/securitas.FCStd1 new file mode 100644 index 0000000..02896b4 Binary files /dev/null and b/securitas.FCStd1 differ diff --git a/workspace.code-workspace b/workspace.code-workspace new file mode 100644 index 0000000..d436dcb --- /dev/null +++ b/workspace.code-workspace @@ -0,0 +1,21 @@ +{ + "folders": [ + { + "path": "SecuritasApp" + }, + { + "path": "Securitas" + } + ], + "settings": { + "files.associations": { + "array": "cpp", + "string": "cpp", + "string_view": "cpp", + "ranges": "cpp", + "memory": "cpp", + "istream": "cpp", + "functional": "cpp" + } + } +} \ No newline at end of file