mirror of
https://github.com/Valeh2012/PersonalVotingMachine
synced 2025-12-08 10:05:12 +02:00
first commit
This commit is contained in:
508
basic-setup/main/include/controller.h
Normal file
508
basic-setup/main/include/controller.h
Normal file
@@ -0,0 +1,508 @@
|
||||
#ifndef MAIN_INCLUDE_CONTROLLER_H_
|
||||
#define MAIN_INCLUDE_CONTROLLER_H_
|
||||
|
||||
/**
|
||||
* @file controller.h
|
||||
* @brief definition of controllers.
|
||||
* */
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "string.h"
|
||||
#include "esp_log.h"
|
||||
#include "mbedtls/base64.h"
|
||||
#include "mbedtls/asn1.h"
|
||||
#include "mbedtls/asn1write.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "expat.h"
|
||||
#include "esp_gatts_api.h"
|
||||
|
||||
#include "module.h"
|
||||
#include "model.h"
|
||||
#include "view.h"
|
||||
|
||||
/**
|
||||
* \class Controller
|
||||
*
|
||||
* \brief abstract class Controller. C in MVC,
|
||||
*
|
||||
* Controllers are bridge between views and models. They take data from model, modify it if required and pass it to the view to present to client.
|
||||
* It has one main method - index(), which is called when controller is reached.
|
||||
* However, depending on their complexity , controller may have other methods.
|
||||
*
|
||||
* */
|
||||
class Controller {
|
||||
protected:
|
||||
View * vw; /**< associated view object*/
|
||||
|
||||
public:
|
||||
virtual void index() = 0; /**< abstract method index */
|
||||
virtual ~Controller(){}; /**< Destructor */
|
||||
};
|
||||
|
||||
/**
|
||||
* \class IndexController
|
||||
* \brief sample inherited controller
|
||||
* */
|
||||
class IndexController : public Controller {
|
||||
public:
|
||||
IndexController(); /**< constructor */
|
||||
void index(); /**< a method that only prints "Index ctrl"*/
|
||||
};
|
||||
|
||||
/**
|
||||
* \class AuthorizationController
|
||||
* \brief responsible for logic behind mobilID authorization
|
||||
*
|
||||
*
|
||||
* */
|
||||
class AuthorizationController : public Controller{
|
||||
private:
|
||||
UserModel * model; /**< user model*/
|
||||
|
||||
const char * TAG = "authController";
|
||||
const char* sni; /**< SNI for authorization */
|
||||
public:
|
||||
AuthorizationController(BaseModel *model, const char* sni); /**< constructor */
|
||||
|
||||
/**
|
||||
* @brief JSON body generator to retrieve Authentication Certificate
|
||||
* Example:
|
||||
*
|
||||
* {
|
||||
* "id": 0.0,
|
||||
* "method": "RPC.Authenticate",
|
||||
* "params": [
|
||||
* {
|
||||
* "OS": "Operating System,2,0",
|
||||
* "PhoneNo": "+37200000766",
|
||||
* "IdCode": "60001019906"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* */
|
||||
char* generateAuthenticateRequestJSON();
|
||||
|
||||
/**
|
||||
* @brief JSON body generator to retrieve Authentication Status
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* {
|
||||
* "id": 0.0,
|
||||
* "method": "RPC.AuthenticateStatus",
|
||||
* "params": [
|
||||
* {
|
||||
* "OS": "Operating System,2,0",
|
||||
* "SessionCode": "2127729011",
|
||||
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* */
|
||||
char* generateAuthenticateStatusRequestJSON();
|
||||
|
||||
/**
|
||||
* @brief index method
|
||||
*
|
||||
* This method does nothing specific.
|
||||
* */
|
||||
void index();
|
||||
|
||||
/**
|
||||
* @brief authorization request method.
|
||||
*
|
||||
* This method invokes authorization request to voting server.
|
||||
* Server doesn't directly send authorization token. Instead, sends a challenge to user to verify (PIN code)
|
||||
* Session ID is also returned which will be used in all upcoming requests.
|
||||
* */
|
||||
void auth();
|
||||
|
||||
/**
|
||||
* @brief authorization status method
|
||||
*
|
||||
* After auth() called, server returns challenge code, session id and session code. Challenge code is displayed to user verify itself.
|
||||
* To check whether user has been verified and get authorization token that is also going to be used in all upcoming requests, authorization status
|
||||
* request has to be sent to server. This function sends that request until user verifies itself every 10 seconds.
|
||||
*
|
||||
* Upon successful verification, authorization token is obtained and stored in model.
|
||||
* */
|
||||
void authStatus();
|
||||
};
|
||||
|
||||
/**
|
||||
* \class ChoiceController
|
||||
* \brief An authenticated user can request for list of candidates from voting server.
|
||||
*
|
||||
* Voting server returns list of candidates in special scheme in JSON format. ChoiceController parses that response and
|
||||
* make candidate names be displayed on screen.
|
||||
* */
|
||||
class ChoiceController : public Controller{
|
||||
private:
|
||||
ChoiceModel *model; /**< choices model */
|
||||
|
||||
const char * TAG = "choicesCtrl";
|
||||
const char* sni; /**< SNI for choices service */
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief JSON body generator to retrieve the List of Choices
|
||||
*
|
||||
* @param at Authentication token
|
||||
* @param ssid SessionID
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* {
|
||||
* "id": 0.0,
|
||||
* "method": "RPC.VoterChoices",
|
||||
* "params": [
|
||||
* {
|
||||
* "AuthMethod": "ticket",
|
||||
* "AuthToken": "G1RTZqBSBKrzqReuKYrmFUFXWFPvaxhJjdiZi6zqAnaK3OvrT...",
|
||||
* "OS": "Operating System,2,0",
|
||||
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* */
|
||||
char* generateChoicesRequestJSON(ChoiceModel *cm);
|
||||
ChoiceController(BaseModel *model, const char* sni); /**< constructor*/
|
||||
|
||||
/**
|
||||
* @brief fetches data from server and waits user select a candidate
|
||||
* */
|
||||
void index();
|
||||
|
||||
/**
|
||||
* Recursive function to parse JSON which holds the list of choices into choiceList,choiceListKeys and partyNameOf
|
||||
* @param item pointer to cJSON structure
|
||||
* @param par party (also, parent) name of current element, otherwise ""
|
||||
*
|
||||
* Example JSON body:
|
||||
*
|
||||
* {
|
||||
* "Kuused":{
|
||||
* "0000.101":"ARA SMIRNOVVVK",
|
||||
* "0000.102":"MARGUS OTT KOVTP"
|
||||
* },
|
||||
* "Männid":{
|
||||
* "0000.103":"ADINE SÄDEVVK"
|
||||
* },
|
||||
* "Üksikkandidaadid":{
|
||||
* "0000.104":"LEILI KOVTP",
|
||||
* "0000.107":"JUTA KOVVALAH",
|
||||
* "0000.105":"KAJA KOVVALAG",
|
||||
* "0000.106":"MAREK KOVVALAG"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* */
|
||||
void parse_object(cJSON *item, char* par);
|
||||
};
|
||||
|
||||
/**
|
||||
* \class EncryptionController
|
||||
* \brief A controller where selected candidate is turned into ballot and encrypted
|
||||
*
|
||||
* */
|
||||
class EncryptionController : public Controller{
|
||||
private:
|
||||
EncryptionModel *model; /**< encryption model*/
|
||||
const char * TAG = "encCtrl";
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief main controller method.
|
||||
*
|
||||
* Encrypt voters casted ballot using public election key
|
||||
*
|
||||
* */
|
||||
void index();
|
||||
EncryptionController(BaseModel *model); /**< constructor */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \class SignatureController
|
||||
* \brief digitally sign encrypted ballot
|
||||
* */
|
||||
class SignatureController : Controller{
|
||||
private:
|
||||
SignatureModel *model; /**< signature model*/
|
||||
const char* sni; /**< sni for signature service*/
|
||||
const char* TAG = "signCtrl";
|
||||
|
||||
/**
|
||||
* XML container for element SignedProperties
|
||||
* */
|
||||
const char * SignedProperties = ""
|
||||
"<xades:SignedProperties xmlns:asic=\"http://uri.etsi.org/02918/v1.2.1#\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:xades=\"http://uri.etsi.org/01903/v1.3.2#\" Id=\"S0-SignedProperties\">"
|
||||
"<xades:SignedSignatureProperties>"
|
||||
"<xades:SigningTime>%s</xades:SigningTime>"
|
||||
"<xades:SigningCertificate>"
|
||||
"<xades:Cert>"
|
||||
"<xades:CertDigest>"
|
||||
"<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></ds:DigestMethod>"
|
||||
"<ds:DigestValue>%s</ds:DigestValue>"
|
||||
"</xades:CertDigest>"
|
||||
"<xades:IssuerSerial>"
|
||||
"<ds:X509IssuerName>%s</ds:X509IssuerName>"
|
||||
"<ds:X509SerialNumber>%s</ds:X509SerialNumber>"
|
||||
"</xades:IssuerSerial>"
|
||||
"</xades:Cert>"
|
||||
"</xades:SigningCertificate>"
|
||||
"</xades:SignedSignatureProperties>"
|
||||
"<xades:SignedDataObjectProperties>"
|
||||
"<xades:DataObjectFormat ObjectReference=\"#S0-RefId0\">"
|
||||
"<xades:MimeType>application/octet-stream</xades:MimeType>"
|
||||
"</xades:DataObjectFormat>"
|
||||
"</xades:SignedDataObjectProperties>"
|
||||
"</xades:SignedProperties>";
|
||||
|
||||
/**
|
||||
* XML container for element SignedInfo
|
||||
* */
|
||||
const char * SignedInfo = ""
|
||||
"<ds:SignedInfo xmlns:asic=\"http://uri.etsi.org/02918/v1.2.1#\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:xades=\"http://uri.etsi.org/01903/v1.3.2#\">"
|
||||
"<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2006/12/xml-c14n11\"></ds:CanonicalizationMethod>"
|
||||
"<ds:SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256\"></ds:SignatureMethod>"
|
||||
"<ds:Reference Id=\"S0-RefId0\" URI=\"%s\">"
|
||||
"<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></ds:DigestMethod>"
|
||||
"<ds:DigestValue>%s</ds:DigestValue>"
|
||||
"</ds:Reference>"
|
||||
"<ds:Reference Id=\"S0-RefId1\" Type=\"http://uri.etsi.org/01903#SignedProperties\" URI=\"#S0-SignedProperties\">"
|
||||
"<ds:Transforms>"
|
||||
"<ds:Transform Algorithm=\"http://www.w3.org/2006/12/xml-c14n11\"></ds:Transform>"
|
||||
"</ds:Transforms>"
|
||||
"<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></ds:DigestMethod>"
|
||||
"<ds:DigestValue>%s</ds:DigestValue>"
|
||||
"</ds:Reference>"
|
||||
"</ds:SignedInfo>";
|
||||
|
||||
/**
|
||||
* XML container for element SignatureValue
|
||||
* */
|
||||
const char * SignatureValue = "<ds:SignatureValue xmlns:asic=\"http://uri.etsi.org/02918/v1.2.1#\" "
|
||||
"xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:xades=\"http://uri.etsi.org/01903/v1.3.2#\" Id=\"S0-SIG\">%s</ds:SignatureValue>";
|
||||
|
||||
/**
|
||||
* XML container for element XadESSignature
|
||||
* */
|
||||
const char * Signature = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
|
||||
"<asic:XAdESSignatures xmlns:asic=\"http://uri.etsi.org/02918/v1.2.1#\">"
|
||||
"<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" Id=\"S0\">"
|
||||
"%s"
|
||||
"%s"
|
||||
"<ds:KeyInfo>"
|
||||
"<ds:X509Data>"
|
||||
"<ds:X509Certificate>%s</ds:X509Certificate>"
|
||||
"</ds:X509Data>"
|
||||
"</ds:KeyInfo>"
|
||||
"<ds:Object>"
|
||||
"<xades:QualifyingProperties xmlns:xades=\"http://uri.etsi.org/01903/v1.3.2#\" Target=\"#S0\">"
|
||||
"%s"
|
||||
"</xades:QualifyingProperties>"
|
||||
"</ds:Object>"
|
||||
"</ds:Signature>"
|
||||
"</asic:XAdESSignatures>";
|
||||
|
||||
public:
|
||||
SignatureController(BaseModel *model, const char* sni);
|
||||
|
||||
/**
|
||||
* @brief retrieve user public key
|
||||
* */
|
||||
void index();
|
||||
|
||||
/**
|
||||
* @brief JSON body generator to get signing Certificate
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* {
|
||||
* "id": 0.0,
|
||||
* "method": "RPC.GetCertificate",
|
||||
* "params": [
|
||||
* {
|
||||
* "AuthMethod": "ticket",
|
||||
* "AuthToken": "G1RTZqBSBKrzqReuKYrmFUFXWFPvaxhJjdiZi6zqAnaK3OvrT...",
|
||||
* "OS": "Operating System,2,0",
|
||||
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
|
||||
* "PhoneNo": "+37200000766",
|
||||
* "IdCode": "60001019906"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* */
|
||||
char* generateGetCertificateRequestJSON();
|
||||
|
||||
/*
|
||||
* JSON body generator to initiate vote signing
|
||||
|
||||
* Example:
|
||||
* {
|
||||
* "id": 0.0,
|
||||
* "method": "RPC.Sign",
|
||||
* "params": [
|
||||
* {
|
||||
* "AuthMethod": "ticket",
|
||||
* "AuthToken": "G1RTZqBSBKrzqReuKYrmFUFXWFPvaxhJjdiZi6zqAnaK3OvrT...",
|
||||
* "Hash": "9IBrA05ylt2StdjxKkSTYMW/rQXY3Vub4upzShdfEzo=",
|
||||
* "OS": "Operating System,2,0",
|
||||
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
|
||||
* "PhoneNo": "+37200000766",
|
||||
* "IdCode": "60001019906"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* */
|
||||
char* generateSignRequestJSON();
|
||||
|
||||
/**
|
||||
* @brief send sign request for encrypted ballot hash
|
||||
*
|
||||
*
|
||||
* */
|
||||
void sign();
|
||||
|
||||
/*
|
||||
* @brief JSON body generator to retrieve Signing Status
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* {
|
||||
* "id": 0.0,
|
||||
* "method": "RPC.SignStatus",
|
||||
* "params": [
|
||||
* {
|
||||
* "OS": "Operating System,2,0",
|
||||
* "SessionCode": "2127729011",
|
||||
* "SessionID": "057229fdfa2df7d3c7f4ced81b02760b"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* */
|
||||
char* generateSignStatusRequestJSON();
|
||||
|
||||
/**
|
||||
* @brief check status of sign request
|
||||
* */
|
||||
void status();
|
||||
|
||||
/**
|
||||
* @brief a helper method to put all xml elements into one single large elements.
|
||||
* */
|
||||
void combine();
|
||||
};
|
||||
|
||||
/**
|
||||
* \class ZipController
|
||||
* \brief BDOC container creator for singature file
|
||||
* */
|
||||
class ZipController : public Controller{
|
||||
private:
|
||||
ZipModel *model;
|
||||
|
||||
const char* TAG = "zipCtrl";
|
||||
|
||||
/**
|
||||
* XML container for manifest.xml
|
||||
*/
|
||||
const char * manifest = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n"
|
||||
"<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n"
|
||||
" <manifest:file-entry manifest:full-path=\"/\" manifest:media-type=\"application/vnd.etsi.asic-e+zip\"/>\n"
|
||||
" <manifest:file-entry manifest:full-path=\"%s\" manifest:media-type=\"application/octet-stream\"/>\n"
|
||||
"</manifest:manifest>";
|
||||
|
||||
public:
|
||||
ZipController(BaseModel *model); /**< constructor */
|
||||
|
||||
/**
|
||||
* @brief create signature container according to BDOC 2.0 standards
|
||||
*
|
||||
* Using slightly modified miniz library, create .zip archieve with following file structure
|
||||
*
|
||||
* \META-INF
|
||||
* singature0.xml
|
||||
* manifest.xml
|
||||
* EP2065.1.ballot
|
||||
* mimetype
|
||||
*
|
||||
*/
|
||||
void index();
|
||||
};
|
||||
|
||||
/**
|
||||
* \class VoteController
|
||||
* \brief cast signed ballot file to voting service
|
||||
*
|
||||
* */
|
||||
class VoteController : public Controller{
|
||||
private:
|
||||
VoteModel *model;
|
||||
|
||||
const char * TAG = "voteCtrl";
|
||||
const char * sni;
|
||||
public:
|
||||
VoteController(BaseModel *model, const char* sni); /**< constructor */
|
||||
|
||||
/**
|
||||
* @brief send bdoc container to voting service to cast your vote.
|
||||
*
|
||||
* A vote id is returned after bdoc container and vote data is validated in server side
|
||||
* */
|
||||
void index();
|
||||
|
||||
/**
|
||||
* @brief JSON body generator to send signed vote
|
||||
*
|
||||
* Example
|
||||
*
|
||||
* {
|
||||
* "id": 0.0,
|
||||
* "method": "RPC.Vote",
|
||||
* "params": [
|
||||
* {
|
||||
* "AuthMethod": "ticket",
|
||||
* "AuthToken": "G1RTZqBSBKrzqReuKYrmFUFXWFPvaxhJjdiZi6zqAnaK3OvrT...",
|
||||
* "Choices": "0140.1",
|
||||
* "SessionID": "ec3a0cab353d552952289f2c7ad52e27",
|
||||
* "OS": "Operating System,2,0",
|
||||
* "Type": "bdoc",
|
||||
* "Vote": "UEsDBAoABgAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlv\nbi92bmQuZX..."
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* */
|
||||
char* generateVoteRequestJSON();
|
||||
};
|
||||
|
||||
/**
|
||||
* \class BluetoothController
|
||||
* \brief send vote data to verification app via BLE
|
||||
*
|
||||
* */
|
||||
class BluetoothController : public Controller{
|
||||
private:
|
||||
BluetoothModel *model; /**< bluetooth model */
|
||||
|
||||
const char* TAG = "btCtrl";
|
||||
public:
|
||||
BluetoothController(BaseModel* model); /**< controller */
|
||||
|
||||
/**
|
||||
* @brief turn on BLE and send session id, randomness and vote id over BLE channel
|
||||
* */
|
||||
void index();
|
||||
};
|
||||
|
||||
#endif /* MAIN_INCLUDE_CONTROLLER_H_ */
|
||||
141
basic-setup/main/include/converter.h
Normal file
141
basic-setup/main/include/converter.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifndef MAIN_INCLUDE_CONVERTER_H_
|
||||
#define MAIN_INCLUDE_CONVERTER_H_
|
||||
|
||||
/**
|
||||
* @file converter.h
|
||||
* @brief converter namespace - collection of frequently used conversion/encoding/decoding functions
|
||||
*
|
||||
* */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "expat.h"
|
||||
|
||||
/** Buffer size for xml parsing */
|
||||
#define output_size 10240
|
||||
|
||||
/**
|
||||
* \namespace converter
|
||||
* */
|
||||
namespace converter{
|
||||
|
||||
/** @brief a helper function to convert pem files to der.
|
||||
*
|
||||
* source: https://github.com/ARMmbed/mbedtls/blob/master/programs/util/pem2der.c
|
||||
*
|
||||
* @param input pem file buffer
|
||||
* @param ilen input buffer length
|
||||
* @param output buffer to store converted der content
|
||||
* @param olen length of data written in output buffer
|
||||
*
|
||||
* @returns 0 if OK, else -1
|
||||
* */
|
||||
int convert_pem_to_der( const unsigned char *input, size_t ilen,
|
||||
unsigned char *output, size_t *olen );
|
||||
|
||||
/**
|
||||
* @brief a helper function to convert long hex numbers to base b = 2^32
|
||||
*
|
||||
* In base 2^32, every digit is 32 bit length unsigned integers (uint32_t).
|
||||
* Therefore, each consequent 4 bytes in hex converted into one digit in base b.
|
||||
* Note: numbers may contain '0x00' in hex representation which is treated as end of string
|
||||
* in string functions. Another parameter is required to indicate length of hex representation
|
||||
*
|
||||
* @param hex input number buffer
|
||||
* @param len input buffer length
|
||||
*
|
||||
* @returns long base-b number
|
||||
*/
|
||||
uint32_t* hex2u32(unsigned char* hex, size_t len);
|
||||
|
||||
/**
|
||||
* @brief a helper function to convert long base-b number to hex values for DER encoding
|
||||
*
|
||||
* Inverse of hex2u32 function
|
||||
*
|
||||
* @param x long base-b number
|
||||
* @param length length of input number
|
||||
* @param len output buffer length
|
||||
*
|
||||
* @returns buffer containing number in hex representation
|
||||
* */
|
||||
unsigned char * nb(uint32_t *x, int length, size_t *olen);
|
||||
|
||||
/**
|
||||
* @brief a helper function convert to first hash, then base64 encode
|
||||
*
|
||||
* This function wraps to mbed_tls functions. Given input string buffer,
|
||||
* it first finds SHA256 hash, then converts the resulting hash into base64.
|
||||
*
|
||||
* @param input string buffer
|
||||
* @param len input buffer length
|
||||
*
|
||||
* @returns output buffer
|
||||
* */
|
||||
unsigned char * base64hash(unsigned char* input, size_t len);
|
||||
|
||||
/** @brief struct used in xml parsing functions
|
||||
* */
|
||||
typedef struct {
|
||||
int depth; /**< depth of recursion*/
|
||||
char* output; /**< output buffer (for parsed xml) */
|
||||
int output_off; /**< output buffer offset (last written index, i.e length of written data)*/
|
||||
const char *last_name; /**< last opened xml tag */
|
||||
} xml_data_t;
|
||||
|
||||
/**
|
||||
* @brief a helper function to insert space for indentation
|
||||
*
|
||||
* This function prints extra whitespaces to output buffer for indentation purposes.
|
||||
*
|
||||
* @param user_data parsed xml data
|
||||
* */
|
||||
static void insert_space(xml_data_t *user_data);
|
||||
|
||||
/**
|
||||
* @brief a callback function called at start of new xml node
|
||||
*
|
||||
* XMLParser traverses through xml nodes and each time it reaches a new node, this callback function is called.
|
||||
* Copy tag name and attributes to output buffer
|
||||
*
|
||||
* @param user_data parsed xml data
|
||||
* @param name just opened current xml node tag name
|
||||
* @param atts other attributes of current xml node
|
||||
* */
|
||||
static void XMLCALL start_element(void *userData, const XML_Char *name, const XML_Char **atts);
|
||||
|
||||
/**
|
||||
* @brief a callback function called at the end of new xml node
|
||||
*
|
||||
* XMLParser traverses through xml nodes and each time it reaches a closing tags of current node, this callback function is called.
|
||||
* If current node is leaf node, add closing tags immediately. Otherwise, add whitespace before closing tags.
|
||||
*
|
||||
* @param user_data parsed xml data
|
||||
* @param name to be closed current xml node tag name
|
||||
* */
|
||||
static void XMLCALL end_element(void *userData, const XML_Char *name);
|
||||
|
||||
/**
|
||||
* @brief a function to define how to parse xml elements
|
||||
*
|
||||
* In between starting and closing tags, this functions is called by XMLParser.
|
||||
* Here, it just copies data buffer to output buffer without adding extra whitespace.
|
||||
*
|
||||
* @param user_data parsed xml data
|
||||
* @param s data in current xml node
|
||||
* @param len length of data
|
||||
* */
|
||||
static void data_handler(void *userData, const XML_Char *s, int len);
|
||||
|
||||
/**
|
||||
* @brief a helper funciton to canonicalize xml data (XMLC14N11).
|
||||
*
|
||||
* Specifications can be found here: \see https://www.w3.org/TR/xml-c14n11/#Example-SETags
|
||||
*
|
||||
* @param str xml input buffer
|
||||
* @param len input buffer length
|
||||
* */
|
||||
void xmlc14n11(char* str, size_t len);
|
||||
}
|
||||
|
||||
#endif
|
||||
142
basic-setup/main/include/model.h
Normal file
142
basic-setup/main/include/model.h
Normal file
@@ -0,0 +1,142 @@
|
||||
#ifndef MAIN_INCLUDE_MODEL_H_
|
||||
#define MAIN_INCLUDE_MODEL_H_
|
||||
|
||||
#include <vector>
|
||||
#include "stdint.h"
|
||||
|
||||
/**
|
||||
* @file model.h
|
||||
* @brief header for model definitions
|
||||
* */
|
||||
|
||||
|
||||
/**
|
||||
* \class BaseModel
|
||||
* \brief base model class
|
||||
* */
|
||||
class BaseModel{
|
||||
public:
|
||||
char* ssid; /**< session ID*/
|
||||
char* authToken; /**< authentication token */
|
||||
};
|
||||
|
||||
/**
|
||||
* \class UserModel
|
||||
* \brief data model to use in AuthorizationController
|
||||
* */
|
||||
class UserModel : public BaseModel{
|
||||
public:
|
||||
char ID[12]; /**< ID code of user */
|
||||
char phone[13]; /**< Phone number of user */
|
||||
char* sscode; /**< session code for PIN confirmation */
|
||||
|
||||
UserModel(char* id, char* phone); /**< constructor */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief struct to store candidate details
|
||||
* */
|
||||
typedef struct{
|
||||
char * party; /**< candidate party name */
|
||||
char * code; /**< District code */
|
||||
char * candidate; /**< candidate full name */
|
||||
}choice_t;
|
||||
|
||||
/**
|
||||
* \class ChoiceModel
|
||||
* \brief data model to use in ChoiceController
|
||||
* */
|
||||
class ChoiceModel : public BaseModel{
|
||||
public:
|
||||
std::vector<choice_t> *choice_list; /**< list of candidates*/
|
||||
char* choices; /**< The voter’s district identifier */
|
||||
char* ballot; /**< ballot generated from selected candidate */
|
||||
|
||||
ChoiceModel(char *ssid, char* authToken); /**< constructor */
|
||||
};
|
||||
|
||||
/**
|
||||
* \class EncryptionModel
|
||||
* \brief data model to use in EncryptionController
|
||||
* */
|
||||
class EncryptionModel : public BaseModel{
|
||||
public:
|
||||
char* ballot; /**< ballot generated from selected candidate */
|
||||
unsigned char* ballotASN; /**< encoded encrypted ballot ballot data in ASN1 DER */
|
||||
size_t ballotLength; /**< ballotASN file length */
|
||||
unsigned char* rndBase64; /**< Base64 encoded randomness used in ecryption */
|
||||
unsigned char* ballotHash; /**< ballotASN hash */
|
||||
char* ballotFileName; /**< filename for encrypted ballot */
|
||||
char* election_id; /**< election id from public election key*/
|
||||
const unsigned char* keypem; /**< public election file in PEM */
|
||||
int keypem_length; /**< public key buffer length */
|
||||
|
||||
EncryptionModel(char* ballot,char* ssid, char * authToken, const uint8_t keypem[], int keypem_length); /**< constructor */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \class SignatureModel
|
||||
* \brief data model to use in SignatureController
|
||||
* */
|
||||
class SignatureModel : public BaseModel{
|
||||
public:
|
||||
char ID[12]; /**< ID code of user */
|
||||
char phone[13]; /**< Phone number of user */
|
||||
char* sscode; /**< session code for PIN confirmation */
|
||||
unsigned char* ballotHash; /**< ballotASN hash */
|
||||
size_t ballotLength; /**< ballotASN file length */
|
||||
char* ballotFileName; /**< filename for encrypted ballot */
|
||||
unsigned char* SignedInfoHash; /**< hash of SignedInfo element */
|
||||
char* signature; /**< digital signature returned from mobilID*/
|
||||
char* certificate; /**< signature certificate */
|
||||
char* SI_XML; /**< SignedInfo XML element*/
|
||||
char* SP_XML; /**< SignedProperties XML element*/
|
||||
char* SV_XML; /**< SignatureValue XML element*/
|
||||
char* Signature; /**< Signature XML element*/
|
||||
|
||||
SignatureModel(char* ssid, char * authToken, char* phone, char* id, unsigned char* ballotHash, size_t ballotLength, char* ballotFileName);
|
||||
};
|
||||
|
||||
/**
|
||||
* \class ZipModel
|
||||
* \brief data model to use in ZipController
|
||||
* */
|
||||
class ZipModel : public BaseModel {
|
||||
public:
|
||||
unsigned char* ballot; /**< encrypted digital ballot */
|
||||
char* ballotFileName; /**< ballot file name */
|
||||
size_t ballotLength; /**< ballot length */
|
||||
char* Signature; /**< Signature XML*/
|
||||
unsigned char* voteBase64; /**< Base64 encoded bdoc container*/
|
||||
|
||||
ZipModel(unsigned char* ballot, char* ballotFileName, size_t ballotLength, char* Signature); /** constructor */
|
||||
};
|
||||
|
||||
/**
|
||||
* \class VoteModel
|
||||
* \brief data model to use in VoteController
|
||||
* */
|
||||
class VoteModel : public BaseModel{
|
||||
public:
|
||||
unsigned char* voteBase64; /**< Base64 encoded bdoc container*/
|
||||
char* voteID; /**< voteID */
|
||||
char* choices; /**< voters district identifier */
|
||||
|
||||
VoteModel(char* ssid, char* authToken, unsigned char* voteBase64, char* choices); /**< constructor */
|
||||
};
|
||||
|
||||
/**
|
||||
* \class BluetoothModel
|
||||
* \brief data model to use in BluetoothController
|
||||
* */
|
||||
class BluetoothModel : public BaseModel{
|
||||
public:
|
||||
char* ssid; /**< session ID */
|
||||
char* voteID; /**< voteID */
|
||||
unsigned char* rndBase64; /**< Base64 encoded randomness used in encryption */
|
||||
|
||||
BluetoothModel(char* ssid, char* voteID, unsigned char* rndBase64); /**< constructor */
|
||||
};
|
||||
|
||||
#endif /* MAIN_INCLUDE_MODEL_H_ */
|
||||
202
basic-setup/main/include/module.h
Normal file
202
basic-setup/main/include/module.h
Normal file
@@ -0,0 +1,202 @@
|
||||
#ifndef MAIN_INCLUDE_MODULE_H_
|
||||
#define MAIN_INCLUDE_MODULE_H_
|
||||
|
||||
/**
|
||||
* @file module.h
|
||||
* @brief Header for module definitions
|
||||
* */
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_tls.h"
|
||||
#include "cJSON.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
|
||||
#include "rotary_encoder.h"
|
||||
|
||||
/**
|
||||
* \class Module
|
||||
* \brief base abstract module class
|
||||
* */
|
||||
class Module{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief module initialization abstract method
|
||||
* */
|
||||
virtual esp_err_t init()=0;
|
||||
|
||||
/**
|
||||
* @brief module deinitialization abstract method
|
||||
* */
|
||||
virtual esp_err_t deinit()=0;
|
||||
|
||||
/**
|
||||
* @brief default module destructor
|
||||
* */
|
||||
virtual ~Module(){};
|
||||
};
|
||||
|
||||
/**
|
||||
* \class RPC
|
||||
* \brief remote procedure call module
|
||||
*
|
||||
* This module follows singleton pattern to prevent concurrent tls communications which may abort program
|
||||
* */
|
||||
class RPC{
|
||||
private:
|
||||
const char* TLS_TAG = "rpc";
|
||||
|
||||
RPC();
|
||||
public:
|
||||
esp_tls_cfg_t *cfg; /**< tls connection config file */
|
||||
char* server; /**< host server address (full domain or ipaddress) */
|
||||
int port; /**< host server process port, default 443 */
|
||||
|
||||
/**
|
||||
* @brief RPC Communication method.
|
||||
*
|
||||
*
|
||||
* @param const char* sni SNI of the service to make a request
|
||||
* @param const char* req stringified JSON request body
|
||||
*
|
||||
* @returns pointer to cJSON structure variable that holds parsed JSON response
|
||||
* */
|
||||
cJSON * send_json_rpc(const char* sni, char* req);
|
||||
|
||||
public:
|
||||
static RPC& Instance(); /**< singleton RPC instance*/
|
||||
};
|
||||
|
||||
/**
|
||||
* \class ScreenModule
|
||||
* \brief screen device module
|
||||
*
|
||||
* This module follows singleton pattern to prevent unexpected behaviors when two process concurrently want to write data
|
||||
* */
|
||||
class ScreenModule : public Module{
|
||||
private:
|
||||
const char* TAG = "ssd_1306";
|
||||
uint8_t screen_id = 0; /**< connected screen id */
|
||||
uint8_t lineOff = 0; /**< last written line */
|
||||
|
||||
ScreenModule();
|
||||
public:
|
||||
gpio_num_t SCL_PIN; /**< SCL connection pin number */
|
||||
gpio_num_t SDA_PIN; /**< SDA connection pin number */
|
||||
gpio_num_t RESET_PIN; /**< RESET connection pin number */
|
||||
|
||||
void setSCL(gpio_num_t scl_pin); /**< set SCL pin */
|
||||
void setSDA(gpio_num_t sda_pin); /**< set SCL pin */
|
||||
void setRST(gpio_num_t rst_pin); /**< set RST pin */
|
||||
esp_err_t init();
|
||||
esp_err_t deinit();
|
||||
|
||||
/* UI method to write strings to screen */
|
||||
void print_screen(char *buff); /**< print char buffer to screen */
|
||||
void clear(); /**< clear screen */
|
||||
void refresh(); /**< refresh screen to update content */
|
||||
|
||||
/** @brief write one line to screen
|
||||
*
|
||||
* @param str char buffer to write
|
||||
* @param pl left padding
|
||||
* */
|
||||
void writeLine(char *str, uint8_t pl);
|
||||
|
||||
/** @brief draw white circle on screen
|
||||
*
|
||||
* @param x x coordinate of circle center
|
||||
* @param y y coordinate of circle center
|
||||
* @param r circle radius
|
||||
* */
|
||||
void FillCircle(uint8_t x, uint8_t y, uint8_t r);
|
||||
public:
|
||||
static ScreenModule& Instance(); /**< singleton ScreenModule instance*/
|
||||
};
|
||||
|
||||
/**
|
||||
* \class WiFiModule
|
||||
* \brief WiFi connections module
|
||||
* */
|
||||
class WiFiModule : public Module{
|
||||
private:
|
||||
const char * TAG = "wi-fi";
|
||||
char* WIFI_SSID; /**< WiFi SSID name */
|
||||
char* WIFI_PASS; /**< WiFi password */
|
||||
public:
|
||||
WiFiModule(char *ssid, char* pass);
|
||||
esp_err_t init();
|
||||
esp_err_t deinit();
|
||||
};
|
||||
|
||||
/**
|
||||
* \class NVSModule
|
||||
* \brief NVS module for board initialization
|
||||
* */
|
||||
class NVSModule : public Module{
|
||||
private:
|
||||
const char* TAG = "nvs";
|
||||
public:
|
||||
esp_err_t init();
|
||||
esp_err_t deinit();
|
||||
};
|
||||
|
||||
/**
|
||||
* \class RotaryEncoderModule
|
||||
* \brief RotaryEncoder module to control attached rotary encoder device. Listens to rotations and click events.
|
||||
* */
|
||||
class RotaryEncoderModule : public Module{
|
||||
private:
|
||||
const char* TAG = "RotEnc";
|
||||
RotaryEncoderModule();
|
||||
public:
|
||||
gpio_num_t ROT_ENC_A_GPIO, ROT_ENC_B_GPIO, ROT_ENC_C_GPIO;
|
||||
bool ENABLE_HALF_STEPS;
|
||||
bool FLIP_DIRECTION;
|
||||
rotary_encoder_info_t *info;
|
||||
|
||||
/** @brief set gpio pins connected to rotary encoder
|
||||
*
|
||||
* @param a pin connected to DT bus
|
||||
* @param b pin connected to CLK bus
|
||||
* @param c pin connected to SW bus
|
||||
* */
|
||||
void setPins(gpio_num_t a, gpio_num_t b, gpio_num_t c);
|
||||
|
||||
rotary_encoder_info_t* getInfo() const;
|
||||
esp_err_t init();
|
||||
esp_err_t deinit();
|
||||
static RotaryEncoderModule& Instance(); /**< singleton RotaryEncoderModule instance */
|
||||
RotaryEncoderModule(RotaryEncoderModule const&) = delete; /**< Delete public constructor */
|
||||
void operator=(RotaryEncoderModule const&) = delete; /**< Disallow object copying */
|
||||
};
|
||||
|
||||
/**
|
||||
* \class SNTPModule
|
||||
* \brief Time synchronization module
|
||||
* */
|
||||
class SNTPModule : public Module{
|
||||
private:
|
||||
const char* TAG = "sntp";
|
||||
public:
|
||||
static void initialize_sntp(void); /**< synchronize time over network*/
|
||||
esp_err_t init();
|
||||
esp_err_t deinit();
|
||||
};
|
||||
|
||||
/**
|
||||
* \class BLEModule
|
||||
* \brief BLE communication module
|
||||
* */
|
||||
class BLEModule : public Module{
|
||||
public:
|
||||
const char* TAG = "ble";
|
||||
|
||||
esp_err_t init();
|
||||
esp_err_t deinit();
|
||||
BLEModule();
|
||||
esp_ble_adv_params_t * adv; /**< bluetooth device advertisement params pointer*/
|
||||
};
|
||||
|
||||
#endif /* MAIN_INCLUDE_MODULE_H_ */
|
||||
41
basic-setup/main/include/u8g2_esp32_hal.h
Normal file
41
basic-setup/main/include/u8g2_esp32_hal.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* u8g2_esp32_hal.h
|
||||
*
|
||||
* Created on: Feb 12, 2017
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#ifndef U8G2_ESP32_HAL_H_
|
||||
#define U8G2_ESP32_HAL_H_
|
||||
#include "u8g2.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/i2c.h"
|
||||
|
||||
#define U8G2_ESP32_HAL_UNDEFINED (GPIO_NUM_NC)
|
||||
|
||||
#define I2C_MASTER_NUM I2C_NUM_1 // I2C port number for master dev
|
||||
#define I2C_MASTER_TX_BUF_DISABLE 0 // I2C master do not need buffer
|
||||
#define I2C_MASTER_RX_BUF_DISABLE 0 // I2C master do not need buffer
|
||||
#define I2C_MASTER_FREQ_HZ 50000 // I2C master clock frequency
|
||||
#define ACK_CHECK_EN 0x1 // I2C master will check ack from slave
|
||||
#define ACK_CHECK_DIS 0x0 // I2C master will not check ack from slave
|
||||
|
||||
typedef struct {
|
||||
gpio_num_t clk;
|
||||
gpio_num_t mosi;
|
||||
gpio_num_t sda; // data for I²C
|
||||
gpio_num_t scl; // clock for I²C
|
||||
gpio_num_t cs;
|
||||
gpio_num_t reset;
|
||||
gpio_num_t dc;
|
||||
} u8g2_esp32_hal_t ;
|
||||
|
||||
#define U8G2_ESP32_HAL_DEFAULT {U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED }
|
||||
|
||||
void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param);
|
||||
uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||
#endif /* U8G2_ESP32_HAL_H_ */
|
||||
72
basic-setup/main/include/view.h
Normal file
72
basic-setup/main/include/view.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef MAIN_INCLUDE_VIEW_H_
|
||||
#define MAIN_INCLUDE_VIEW_H_
|
||||
|
||||
/**
|
||||
* @file view.h
|
||||
* @brief View class
|
||||
* */
|
||||
|
||||
#include "module.h"
|
||||
#include "model.h"
|
||||
|
||||
/**
|
||||
* \class View
|
||||
* \brief V in MVC pattern. Each controller is associated with a view.
|
||||
* There is only one screen device attached to board. This view helps to display data and accept user input
|
||||
* */
|
||||
class View{
|
||||
public:
|
||||
ScreenModule screen = ScreenModule::Instance(); /**< singleton screen instance */
|
||||
virtual void render(void* data) = 0; /**< abstract method to render data*/
|
||||
virtual ~View(){}; // destructor
|
||||
};
|
||||
|
||||
/**
|
||||
* \class IndexView
|
||||
* @brief default inherited class
|
||||
* */
|
||||
class IndexView : public View{
|
||||
public:
|
||||
IndexView();
|
||||
|
||||
/**
|
||||
* @brief display data on screen
|
||||
*
|
||||
* @param data (void *) casted string buffer to display
|
||||
* */
|
||||
void render(void * data);
|
||||
};
|
||||
|
||||
/**
|
||||
* \class ChoiceView
|
||||
* @brief more functional view class that ChoiceController uses.
|
||||
* */
|
||||
class ChoiceView : public View{
|
||||
public:
|
||||
ChoiceView();
|
||||
|
||||
/**
|
||||
* @brief render ChoiceController data
|
||||
*
|
||||
* Here, users allowed to interact with device using RotaryEncoder. Every time encoder state is changed,
|
||||
* screen is updated. A small circle in front of candidate names represent selected option index. This method
|
||||
* will listen rotary encoder until click event is fired, and then create ballot based on selected candidate data.
|
||||
*
|
||||
* @param data (void *) casted ChoiceModel * model.
|
||||
* */
|
||||
void render(void * data);
|
||||
|
||||
/**
|
||||
* @brief show all candidates
|
||||
*
|
||||
* Given list of candidates, this method print name of candidates on screen with small circle to highlight
|
||||
* "cursor" location, in other words hovered element.
|
||||
*
|
||||
* @param v list of choices
|
||||
* @param r position to draw circle
|
||||
* */
|
||||
void list(std::vector<choice_t>& v, int r);
|
||||
};
|
||||
|
||||
|
||||
#endif /* MAIN_INCLUDE_VIEW_H_ */
|
||||
Reference in New Issue
Block a user