From: server Date: Mon, 20 Jan 2025 02:43:18 +0000 (-0500) Subject: Sun Jan 19 09:43:18 PM EST 2025 X-Git-Url: http://www.foleosoft.com/?a=commitdiff_plain;h=9ddb400c86a7382db1c87c8efb7a21d0aff5e5d0;p=RosadoAPI.git Sun Jan 19 09:43:18 PM EST 2025 --- 9ddb400c86a7382db1c87c8efb7a21d0aff5e5d0 diff --git a/README.md b/README.md new file mode 100644 index 0000000..f15b7de --- /dev/null +++ b/README.md @@ -0,0 +1,147 @@ +# EstousAPI + +Easily transform as many CLI programs as you wish into web APIs. + +## Compilation + +Please click the `tree` link at the top and navigate to the +`bin` folder and download the following file to get the source +code for the simulator. + +``` + qansel-source-base.zip +``` + +To compile it, navigate to the folder it installed within and +run the following commands within that folder. + +```sh + mkdir qansel + mv *qansel-source-base.zip qansel + cd qansel + unzip *qansel-source-base.zip + make +``` + +If you are compiling for a device which cannot support +hardware acceleration, then you can use `make simple` which +will build the program with those features stripped out. + +## Usage + + + + + +Many example programs that can be executed inside of QAnsel can +be found by clicking the `tree` link at the top fo the page and +then navigating to the `examples` folder. Simply click on one of +the examples in order to see the source code. + +## Usage + +The QAnsel simulator expects programs to be written in a language +similar to OpenQASM 2.0. These programs must be piped into QAnsel +as standard input and the simulation results will be displayed as +standard output. Below is an example using a here document. + +```sh + $ ./QAnsel << EOF + > qreg q[2]; + > creg c[2]; + > h q[0]; + > cx q[0], q[1]; + > measure q[0] -> c[0]; + > measure q[1] -> c[1]; + > sample c; + > EOF + 00: 50.7% + 01: 0.0% + 10: 0.0% + 11: 49.3% +``` + +Please use the `-?` flag to see a help document. + +## Special Hardware + +To enable a hardware random number generator, the `-r` +flag must be used. This flag will select the hardware +random number generator based on an order of precedence. +The order is as follows. + +1. Quantis-PCIe-40M +2. TrueRNG V3 +3. Secure Key Technology + +To enable GPU acceleration, the `-oX` flag has to be +set replacing `X` with an optimization level equal to +4 or greater. + +It is recommended that you run a simple program with the +`-v` flag which will produce output stating which hardware +devices were actually found and enabled. + +QAnsel can handle up to 16 qubits, however, qubit counts +greater than 14 will not fit into most consumer-end GPUs. +The amount of qubits that can fit is limited by the +amount of VRAM. The GPU must have at least 8 GB for 14 +qubits, 16 GB for 15 qubits, and 48 GB for 16 qubits. + +## API and Web Interface + +There is a drag-and-drop interface that runs in the browser +that can be found by clicking the `tree` button and navigating +to the `bin` folder and downloading the following file. + +``` + qansel-source-web.zip +``` + +This web front end expects to connect to an API. The API +service is handled through FoleoAPI. Please see the FoleoAPI +project in order to set up this service. + +Once FoleoAPI is running, a ServiceInfo record will need to be +added to the APIService schema. Below is an example of how this +entry may look. + +```sql + MariaDB [APIService]> select * from ServiceInfo; + +----+---------+---------------------------------+-------------+ + | id | service | path | parameters | + +----+---------+---------------------------------+-------------+ + | 1 | qansel | /fakepath/QAnsel | -q14 -o5 -r | + +----+---------+---------------------------------+-------------+ +``` + +The `-qX` parameter is useful here as it allows one to cap +the maximum qubit count allowed for the process in case the +hardware running the simulator is not sufficient to handle large +qubit counts. In this case, it is capped at 14 to make sure that +programs that exceed the limitations of the GPU are rejected. + +The web interface expects an API key. The API key is formed in three +parts `A:B:C` where `A` is the `APIService.AuthInfo.username`, `B` is +the `APIService.AuthInfo.authkey`, and `C` is the URL which it needs +to ping. It is important that the address does not contain `http://` +or `https://`. For example, if the address is `http://example.com/api`, +then `C` should simply be written as `example.com/api`. + +Once `A:B:C` is filled out, the entire thing needs to be converted to +a base64 string. This can be done in JavaScript in the developer console +in the web browser using the `btoa()` function. This final encoded string +functions as the API key for the web interface. Any equal signs at the +end of the API key should be removed. + +The web interface allows for appending the URL with `?apikey=` followed by +an API key to auto fill the API key. This can be useful if the service is +linked from another source (such as another website or an email) and will +prevent the user from having to input the APIkey themselves. + +## Android + +The Android app version of this project merely is enclose a web view +containing the web interface. This means it requires pinging a server +running the API for it to work. It must be compiled using Android Studio. + diff --git a/bin/EstoulsAPI.apk b/bin/EstoulsAPI.apk new file mode 100644 index 0000000..fb5f8d6 Binary files /dev/null and b/bin/EstoulsAPI.apk differ diff --git a/bin/favicon.ico b/bin/favicon.ico new file mode 100644 index 0000000..e33686d Binary files /dev/null and b/bin/favicon.ico differ diff --git a/bin/frontend.html b/bin/frontend.html new file mode 100644 index 0000000..b77d983 --- /dev/null +++ b/bin/frontend.html @@ -0,0 +1,1069 @@ + + + + EstoulsAPI + + + + + + + + + +
+ +
+    +    +    + + +    +
  
+ +
+ + + + + + +
1
+
+
+
+
+
+
+ + + + + diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..5efefdf --- /dev/null +++ b/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash +if [ "$1" == "run" ] +then + while [ 1 ] + do + ./bin/APIServer + done +else + xxd -i ./rcs/frontend.html ./src/frontend.h + gcc ./src/main.c -o ./bin/APIServer $(mysql_config --cflags --libs) -lCryptoFoleo + rm ./src/frontend.h + cp ./rcs/* ./bin/ +fi diff --git a/rcs/EstoulsAPI.apk b/rcs/EstoulsAPI.apk new file mode 100644 index 0000000..fb5f8d6 Binary files /dev/null and b/rcs/EstoulsAPI.apk differ diff --git a/rcs/favicon.ico b/rcs/favicon.ico new file mode 100644 index 0000000..e33686d Binary files /dev/null and b/rcs/favicon.ico differ diff --git a/rcs/frontend.html b/rcs/frontend.html new file mode 100644 index 0000000..b77d983 --- /dev/null +++ b/rcs/frontend.html @@ -0,0 +1,1069 @@ + + + + EstoulsAPI + + + + + + + + + +
+ +
+    +    +    + + +    +
  
+ +
+ + + + + + +
1
+
+
+
+
+
+
+ + + + + diff --git a/src/CryptoFoleo.h b/src/CryptoFoleo.h new file mode 100644 index 0000000..e906681 --- /dev/null +++ b/src/CryptoFoleo.h @@ -0,0 +1,62 @@ +#ifndef __HEADERS__ +#define __HEADERS__ +#include +#include + +uint8_t* foleo_chacha20(uint8_t[32], uint8_t[12], uint32_t, size_t); +uint8_t* foleo_chacha20_poly1305(uint8_t[32], uint8_t[12], uint8_t*, size_t); +uint8_t* foleo_dhke(uint8_t*, uint8_t*); +uint16_t foleo_dhke_modsize(); + +uint8_t* foleo_poly1305(uint8_t[32], uint8_t*, size_t); +#define FOLEO_RSA_PADDING_NONE 99 +#define FOLEO_RSA_PADDING_ENCRYPTION 1 +#define FOLEO_RSA_PADDING_SIGNATURE 2 +#define FOLEO_RSA_PADDING_OAEP 3 +#define FOLEO_RSA_PADDING_PSS 4 +#define FOLEO_RAND_MODE_DEVR 1 +#define FOLEO_RAND_MODE_DEV 2 +#ifdef ENABLE_X86 +#define FOLEO_RAND_MODE_X86 3 +#endif +typedef struct +{ + mpz_t n, k; + uint8_t* label; + uint16_t bitWidth; +} rsakey_t; +void foleo_rsa_import(rsakey_t*, uint8_t*); +uint8_t* foleo_rsa_export(rsakey_t*); +void foleo_rsa_free(rsakey_t*); +void foleo_rsa_keygen(uint16_t, rsakey_t*, rsakey_t*); + +//The maximum message block size that can be used +// for a particular padding scheme. +uint16_t foleo_rsa_msgsize(rsakey_t*, uint8_t); + +//Size of the rsakey struct +uint16_t foleo_rsa_keysize(); + +//Size in bytes of RSA modulus, same thing as the number +// of bytes the encrypt() function will return +uint16_t foleo_rsa_modsize(rsakey_t*); + +uint8_t* foleo_rsa_encrypt(rsakey_t*, uint8_t, uint8_t*, uint16_t); +uint8_t* foleo_rsa_decrypt(rsakey_t*, uint8_t, uint8_t*, uint16_t*); +uint8_t* foleo_sha256(uint8_t*, uint32_t); + +#define FOLEO_SHA256 1 +uint8_t* foleo_hmac(uint8_t, uint8_t*, uint32_t, uint8_t*, uint32_t); +uint8_t* foleo_hmac_hkdf(uint8_t, uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t); +uint8_t* foleo_hmac_prf(uint8_t, uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t, uint8_t*, uint32_t); + +uint8_t foleo_hash_size(uint8_t); + +void foleo_rand_mode(uint8_t, uint8_t*); + +uint8_t* foleo_decode_base64(uint8_t*, size_t*); +uint8_t* foleo_decode_hex(uint8_t*); +uint8_t* foleo_encode_hex(uint8_t*, size_t); +uint8_t* foleo_encode_base64(uint8_t*, size_t); + +#endif diff --git a/src/http.c b/src/http.c new file mode 100644 index 0000000..1ba45a7 --- /dev/null +++ b/src/http.c @@ -0,0 +1,403 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *HTTP_SERVER = "Server: FoleoSoft\n"; + +int httpOpenSocket(char* ip, char* port) +{ + //get info about the server socket + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; //IPv4 or IPv6 + hints.ai_protocol = 0; //Only useful if family is specific + hints.ai_socktype = SOCK_STREAM; //TCP only (excludes UDP) + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + struct addrinfo *sockinfo = 0; + int err = getaddrinfo(ip, port, &hints, &sockinfo); + if (err != 0) + { + printf("getaddrinfo(): %i\n", err); + return -1; + } + + //create the server socket from that info + int server_fd = socket(sockinfo->ai_family, sockinfo->ai_socktype, sockinfo->ai_protocol); + if (server_fd == -1) + { + printf("socket(): %s", strerror(errno)); + return -1; + } + + //Allow network service to be restarted when need-be + int reuseaddr = 1; + if ( setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1 ) + { + printf("setsockopt(): %i\n", errno); + return -1; + } + + //Bind IP to socket + if ( bind(server_fd, sockinfo->ai_addr, sockinfo->ai_addrlen) == -1 ) + { + printf("bind(): %i\n", errno); + return -1; + } + + //Free no longer needed sockinfo + freeaddrinfo(sockinfo); + + //Start listening on the socket + if ( listen(server_fd, SOMAXCONN) ) + { + printf("listen(): %i\n", errno); + return -1; + } + + return server_fd; +} + +char* httpParseNext(char end, char* buff, int* buff_pos, int buff_len) +{ + char* ret = malloc(0); + int ret_len = 0; + for (int i = *buff_pos; i < buff_len && buff[i] != end; i++) + { + ret = realloc(ret, ret_len + 1); + ret[ret_len] = buff[i]; + *buff_pos += 1; + ret_len += 1; + } + ret = realloc(ret, ret_len + 1); + ret[ret_len] = 0; + *buff_pos += 1; + return ret; +} + +void httpNext(char end, char* buff, int* buff_pos, int buff_len) +{ + int pos = 0; + for (int i = *buff_pos; i < buff_len && buff[i] != end; i++) + { + *buff_pos += 1; + } + *buff_pos += 1; +} + +char* httpParse(char* search, char* buff, long buff_len) +{ + int buff_pos = 0; + + if ( strcmp(search, "Method") == 0 ) + { + return httpParseNext(' ', buff, &buff_pos, buff_len); + } + else if ( strcmp(search, "Path") == 0 ) + { + httpNext(' ', buff, &buff_pos, buff_len); + return httpParseNext(' ', buff, &buff_pos, buff_len); + } + else if ( strcmp(search, "Version") == 0 ) + { + if (buff[0] == 'H' && buff[1] == 'T' && buff[2] == 'T') + { + return httpParseNext(' ', buff, &buff_pos, buff_len); + } + else + { + httpNext(' ', buff, &buff_pos, buff_len); + httpNext(' ', buff, &buff_pos, buff_len); + return httpParseNext('\n', buff, &buff_pos, buff_len); + } + } + else if ( strcmp(search, "Content") == 0 ) + { + for (int i = 3; i < buff_len; i++) + { + if (buff[i - 3] == '\r' && buff[i - 2] == '\n' && buff[i - 1] == '\r' && buff[i - 0] == '\n') + { + i++; + char* ret = malloc(buff_len - i); + memcpy(ret, buff + i, buff_len - i); + return ret; + } + } + printf("hit a null\n"); + return NULL; + } + else + { + httpNext('\n', buff, &buff_pos, buff_len); + while (buff_pos < buff_len) + { + char* tmp = httpParseNext(':', buff, &buff_pos, buff_len); + if ( strcmp(tmp, search) == 0 ) + { + free(tmp); + buff_pos++; + return httpParseNext('\n', buff, &buff_pos, buff_len); + } + free(tmp); + httpNext('\n', buff, &buff_pos, buff_len); + } + return NULL; + } +} + +char* httpParsePost(char* search, char* post, long post_len) +{ + int rsearchL = strlen(search) + 1; + char* rsearch = malloc(rsearchL); + memcpy(rsearch, search, rsearchL); + rsearch[rsearchL - 1] = '='; + for (int i = 0; i < post_len - rsearchL; i++) + { + if (memcmp(rsearch, post + i, rsearchL) == 0) + { + i += rsearchL; + char* ret = malloc(1); + int retL = 1; + ret[0] = 0; + for (; i < post_len; i++) + { + if (post[i] == '&') break; + ret = realloc(ret, ++retL); + ret[retL - 2] = post[i]; + ret[retL - 1] = 0; + } + free(rsearch); + return ret; + } + } + free(rsearch); + return NULL; +} + +void httpBegin(int socket_fd, int* session_fd) +{ + *session_fd = accept(socket_fd, 0, 0); +} + +void httpEnd(int session_fd) +{ + close(session_fd); +} + +void httpRespond(int session_fd, char* str) +{ + size_t strL = strlen(str); + for (size_t i = 0; i < strL; i++) + { + if (write(session_fd, str + i, 1) <= 0) + { + i -= 1; + } + } +} + +void httpRespondByte(int session_fd, uint8_t byte) +{ + while (write(session_fd, &byte, 1) <= 0) ; +} + +void httpError(int session_fd, int error, char *msg) +{ + char headerTemplate[] = "HTTP/1.1 %i %s\n"; + int headerLen = snprintf(NULL, 0, headerTemplate, error, msg); + char *header = malloc(headerLen); + sprintf(header, headerTemplate, error, msg); + + char pageTemplate[] = "Error %i: %s\n"; + int pageLen = snprintf(NULL, 0, pageTemplate, error, msg); + char *page = malloc(pageLen); + sprintf(page, pageTemplate, error, msg); + + char contentLengthTemplate[] = "Content-Length: %i\n\n"; + int contentLengthLen = snprintf(NULL, 0, contentLengthTemplate, pageLen); + char *contentLength = malloc(contentLengthLen); + sprintf(contentLength, contentLengthTemplate, pageLen); + + httpRespond(session_fd, header); + httpRespond(session_fd, HTTP_SERVER); + httpRespond(session_fd, contentLength); + httpRespond(session_fd, page); + + free(header); + free(contentLength); + free(page); +} + +int httpFileOut(int session_fd, char* path, uint8_t fileType) +{ + char* safePath; + int safePathLen; + int pathLen = strlen(path); + if (pathLen == 0) return 0; + if (path[0] == '/') + { + safePath = malloc(1); + safePath[0] = '.'; + safePathLen = 1; + } + else + { + safePath = malloc(0); + safePathLen = 0; + } + for (int i = 0; i < pathLen; i++) + { + if (i > 0 && path[i] == '.') + { + if (path[i - 1] == '/' || path[i - 1] == '.') + { + continue; + } + } + if (path[i] == '/' && safePathLen > 0) + { + if (safePath[safePathLen - 1] == '/') + { + continue; + } + } + safePath = realloc(safePath, ++safePathLen); + safePath[safePathLen - 1] = path[i]; + } + safePath = realloc(safePath, ++safePathLen); + safePath[safePathLen - 1] = 0; + + FILE *fd = fopen(safePath, "r"); + free(safePath); + if (fd == NULL) + { + httpError(session_fd, 404, "Page Not Found"); + return 1; + } + fseek(fd, 0, SEEK_END); + size_t fileSize = ftell(fd); + rewind(fd); + char* fileData = malloc(fileSize); + fread(fileData, 1, fileSize, fd); + fclose(fd); + + + if (fileSize < 0) + { + httpError(session_fd, 404, "Page Not Found"); + return 1; + } + + //Good header + httpRespond(session_fd, "HTTP/1.1 200 OK\n"); + httpRespond(session_fd, HTTP_SERVER); + + //Spit out file content length part of the HTTP message + char* contentLengthTemplate; + const char contentLengthTemplate0[] = "Access-Control-Allow-Origin: *\nContent-Type: application/octet-stream\nContent-Length: %i\n\n"; + const char contentLengthTemplate1[] = "Access-Control-Allow-Origin: *\nContent-Type: image/x-icon\nContent-Length: %i\n\n"; + switch (fileType) + { + case 0: + contentLengthTemplate = malloc(strlen(contentLengthTemplate0) + 1); + strcpy(contentLengthTemplate, contentLengthTemplate0); + break; + case 1: + contentLengthTemplate = malloc(strlen(contentLengthTemplate1) + 1); + strcpy(contentLengthTemplate, contentLengthTemplate1); + break; + } + size_t contentLengthLen = snprintf(NULL, 0, contentLengthTemplate, fileSize); + char* contentLength = malloc(contentLengthLen + 1); + sprintf(contentLength, contentLengthTemplate, fileSize); + httpRespond(session_fd, contentLength); + free(contentLength); + for (size_t i = 0; i < fileSize; i++) + { + if (i == 0) + { + printf(">%02X<\n", fileData[i]); + } + httpRespondByte(session_fd, fileData[i]); + } + free(fileData); + free(contentLengthTemplate); +} + +int httpStringOut(int session_fd, char* str) +{ + //Good header + httpRespond(session_fd, "HTTP/1.1 200 OK\n"); + httpRespond(session_fd, HTTP_SERVER); + + int strSize = strlen(str); + //Spit out file content length part of the HTTP message + const char *contentLengthTemplate = "Access-Control-Allow-Origin: *\nContent-Type: text/html\nContent-Length: %i\n\n"; + int contentLengthLen = snprintf(NULL, 0, contentLengthTemplate, strSize); + char* contentLength = malloc(contentLengthLen + 1); + sprintf(contentLength, contentLengthTemplate, strSize); + httpRespond(session_fd, contentLength); + free(contentLength); + + httpRespond(session_fd, str); + httpRespond(session_fd, "\n"); +} + +void httpRequest(int session_fd, char** str, int* strlen) +{ + int flags = fcntl(session_fd, F_GETFL, 0); + fcntl(session_fd, F_SETFL, flags | O_NONBLOCK); + + *strlen = 0; + *str = malloc(0); + uint8_t buffer[1024]; + int32_t length; + int8_t tries = 3; + + while (tries > 0) + { + while ( (length = read(session_fd, buffer, sizeof(buffer))) > 0 ) + { + *str = realloc(*str, (*strlen) + length); + memcpy((*str) + (*strlen), buffer, length); + *strlen += length; + } + usleep(1000); + tries--; + } + + *str = realloc(*str, (*strlen) + 1); + (*str)[*strlen] = 0; + *strlen += 1; + + /* + ioctl(session_fd, FIONREAD, strlen); + if (*strlen > 0) + { + *str = malloc(*strlen * sizeof(char)); + read(session_fd, *str, *strlen); + } + else + { + *str = NULL; + *strlen = 0; + } + */ + + printf("-------------------------------\n"); + printf("Length: %i\n", *strlen); + printf("-------------------------------\n"); + for (int i = 0; i < *strlen; i++) + { + putchar((*str)[i]); + } + putchar('\n'); + printf("-------------------------------\n"); +} + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..82bd2e8 --- /dev/null +++ b/src/main.c @@ -0,0 +1,494 @@ +#include +#include +#include +#include +#include "http.c" +#include "frontend.h" +#include "CryptoFoleo.h" + +uint8_t HOSTNAME[1024]; +uint8_t HOSTNAME_I[1024]; + +//grabs auth info from the database +uint8_t* getDatabaseInfo(uint8_t type, uint8_t* a, uint8_t* b, uint8_t* c) +{ + uint8_t* ret = NULL; + MYSQL *conn; + MYSQL_RES *res; + MYSQL_ROW row; + conn = mysql_init(NULL); + FILE *f = fopen("/usr/share/estous/password", "r"); + if (!f) + { + fprintf(stderr, "Could not open /usr/share/estousapi/password\n"); + exit(1); + } + char* p = malloc(0); + int c; + while ( (c = fgetc(f)) != EOF) + + if (!mysql_real_connect(conn, "localhost", HOSTNAME, "", "APIService", 0, NULL, 0)) { + fprintf(stderr, "%s\n", mysql_error(conn)); + return NULL; + } + + if (type == 1) + { + uint8_t* prequery = "select %s from AuthInfo where service='%s' and username='%s' limit 1;"; + uint16_t queryLength = snprintf(NULL, 0, prequery, b, c, a); + uint8_t query[queryLength + 1]; + sprintf(query, prequery, b, c, a); + if (mysql_query(conn, query)) + { + fprintf(stderr, "%s\n", mysql_error(conn)); + return NULL; + } + } + else + { + uint8_t* prequery = "select %s from ServiceInfo where service='%s' limit 1;"; + uint16_t queryLength = snprintf(NULL, 0, prequery, b, a); + uint8_t query[queryLength + 1]; + sprintf(query, prequery, b, a); + if (mysql_query(conn, query)) + { + fprintf(stderr, "%s\n", mysql_error(conn)); + return NULL; + } + } + + res = mysql_use_result(conn); + if ((row = mysql_fetch_row(res)) != NULL) + { + ret = malloc(strlen(row[0]) + 1); + strcpy(ret, row[0]); + } + mysql_free_result(res); + mysql_close(conn); + + return ret; +} + +uint8_t* runService(uint8_t* service_name, uint8_t* service_data, uint32_t* service_dataL, uint32_t timeout) +{ + uint8_t* data = malloc(strlen(service_data) + 1); + strcpy(data, service_data); + uint8_t* service_path = getDatabaseInfo(2, service_name, "path", ""); + uint8_t* service_parms = getDatabaseInfo(2, service_name, "parameters", ""); + if (service_path == NULL || service_parms == NULL) + { + free(service_path); + free(service_parms); + return NULL; + } + + uint8_t heredoc[] = "HERE"; + uint16_t heredocL = strlen(heredoc); + uint32_t dataL = strlen(data); + for (uint32_t i = heredocL; i < dataL; i++) + { + if (memcmp(data + (i - heredocL), heredoc, heredocL) == 0) + { + memset(data + (i - heredocL), ' ', heredocL); + } + } + + uint8_t template[] = "/tmp/apiserviceXXXXXX"; + int8_t fd = mkstemp(template); + if (fd == -1) + { + perror("mkstemp"); + exit(EXIT_FAILURE); + } + write(fd, data, dataL); + close(fd); + + uint8_t precommand[] = "(cat %s | (timeout %is %s %s) || echo Timed out.)2>&1"; + uint16_t commandL = snprintf(NULL, 0, precommand, template, timeout, service_path, service_parms); + uint8_t command[commandL + 1]; + sprintf(command, precommand, template, timeout, service_path, service_parms); + free(service_path); + free(service_parms); + free(data); + + printf("-------------Command--------------\n"); + printf("%s\n", command); + printf("----------------------------------\n"); + FILE *service; + service = popen(command, "r"); + if (service == NULL) + { + perror("popen"); + return NULL; + } + + uint8_t* ret = malloc(0); + uint32_t retL = 0; + int32_t c; + while ((c = fgetc(service)) != EOF) + { + retL++; + ret = realloc(ret, retL); + ret[retL - 1] = (uint8_t)c; + } + + int status = pclose(service); + if (status == -1) + { + free(ret); + perror("pclose"); + return NULL; + } + *service_dataL = retL; + unlink(template); + return ret; +} + +//process a connection that was provided necessary info +void processUserAndData(int session_fd, char* user, char* data, char* session, char* digest, char* service) +{ + for (int i = 0; i < strlen(user); i++) + { + if (user[i] == '\'') + { + httpError(session_fd, 400, "Bad Request (6)"); + return; + } + } + + if (strlen(digest) != (32 * 2) || strlen(session) != (12 * 2)) + { + httpError(session_fd, 400, "Bad Request (7)"); + return; + } + + char* authkey = getDatabaseInfo(1, user, "authkey", service); + if (authkey == NULL) + { + free(authkey); + httpError(session_fd, 403, "Forbidden (1)"); + return; + } + + int keyid = 0; + uint8_t* sessionAsBinary = foleo_decode_hex(session); + uint8_t* authkeyAsBinary = foleo_decode_hex(authkey); + uint8_t* digestAsBinary = foleo_decode_hex(digest); + size_t dataSize; + uint8_t* dataAsBinary = foleo_decode_base64(data, &dataSize); + free(authkey); + + if (sessionAsBinary == NULL || authkeyAsBinary == NULL || dataAsBinary == NULL || digestAsBinary == NULL || dataSize == 0) + { + free(sessionAsBinary); + free(authkeyAsBinary); + free(dataAsBinary); + free(digestAsBinary); + httpError(session_fd, 400, "Bad Request (8)"); + return; + } + + uint8_t* mac = foleo_hmac(FOLEO_SHA256, authkeyAsBinary, 256 / 8, dataAsBinary, dataSize); + if (memcmp(mac, digestAsBinary, 256 / 8) != 0) + { + free(sessionAsBinary); + free(authkeyAsBinary); + free(dataAsBinary); + free(digestAsBinary); + free(mac); + httpError(session_fd, 403, "Forbidden (2)"); + return; + } + free(digestAsBinary); + free(mac); + + uint8_t* ret = foleo_chacha20(authkeyAsBinary, sessionAsBinary, 0, dataSize); + for (int i = 0; i < dataSize; i++) dataAsBinary[i] ^= ret[i]; + free(ret); + + uint32_t receivedL = dataSize + 1; + uint8_t* received = malloc(receivedL); + memcpy(received, dataAsBinary, receivedL - 1); + received[receivedL - 1] = 0; + free(dataAsBinary); + + uint32_t timeout = 10; + char* stimeout = getDatabaseInfo(1, user, "timeout", service); + timeout = atoi(stimeout); + free(stimeout); + + uint32_t resultL; + uint8_t* result = runService(service, received, &resultL, timeout); + free(received); + if (result != NULL) + { + uint8_t carry = 1; + for (int8_t i = 11; i >= 0; i--) + { + if (sessionAsBinary[i] == 0xFF) + { + if (carry == 1) sessionAsBinary[i] = 0; + else carry = 0; + } + else + { + if (carry == 1) sessionAsBinary[i]++; + carry = 0; + } + } + uint8_t* ret_sess = foleo_encode_hex(sessionAsBinary, 12); + uint8_t* ret_data = foleo_chacha20(authkeyAsBinary, sessionAsBinary, 0, resultL); + for (uint32_t i = 0; i < resultL; i++) ret_data[i] ^= result[i]; + uint8_t* ret_data_b64 = foleo_encode_base64(ret_data, resultL); + uint8_t* ret_mac = foleo_hmac(FOLEO_SHA256, authkeyAsBinary, 256 / 8, ret_data, resultL); + uint8_t* ret_mac_hex = foleo_encode_hex(ret_mac, 256 / 8); + + uint32_t finalL = snprintf(NULL, 0, "user=%s&sess=%s&dgst=%s&data=%s\n", user, ret_sess, ret_mac_hex, ret_data_b64); + uint8_t final[finalL + 1]; + sprintf(final, "user=%s&sess=%s&dgst=%s&data=%s\n", user, ret_sess, ret_mac_hex, ret_data_b64); + httpStringOut(session_fd, final); + + free(ret_sess); + free(ret_data); + free(ret_data_b64); + free(ret_mac); + free(ret_mac_hex); + } + free(result); + free(authkeyAsBinary); + free(sessionAsBinary); + + return; +} + +void *handleRequest(void *vargp) +{ + int session_fd; + memcpy(&session_fd, vargp, sizeof(int)); + free(vargp); + + char *buff; + char *info; + char *user; + char *data; + char *sess; + char *dgst; + int buff_len; + httpRequest(session_fd, &buff, &buff_len); + printf("-----Request-----\n"); + for (int32_t i = 0; i < buff_len; i++) + { + putchar(buff[i]); + } + printf("\n-----------------\n"); + if (buff != NULL) + { + info = httpParse("Method", buff, buff_len); + if (info == NULL) + { + httpError(session_fd, 400, "Bad Request (1)"); + } + else if ( strcmp(info, "POST") == 0 ) + { + free(info); + info = httpParse("Path", buff, buff_len); + uint8_t* isValidService = getDatabaseInfo(2, info + 1, "1", ""); + if (isValidService == NULL) + { + httpError(session_fd, 400, "Bad Request (2)"); + } + else + { + uint8_t service[strlen(info + 1) + 1]; + strcpy(service, info + 1); + free(isValidService); + free(info); + info = httpParse("Content-Length", buff, buff_len); + if (info == NULL) + { + httpError(session_fd, 400, "Bad Request (3)"); + } + else + { + uint32_t contentLength = atoi(info); + if (contentLength == 0) + { + httpError(session_fd, 400, "Bad Request (4)"); + } + else + { + free(info); + info = httpParse("Content", buff, buff_len); + if (info == NULL) + { + httpError(session_fd, 400, "Bad Request (5)"); + } + else + { + user = httpParsePost("user", info, contentLength); + data = httpParsePost("data", info, contentLength); + sess = httpParsePost("sess", info, contentLength); + dgst = httpParsePost("dgst", info, contentLength); + if (user != NULL && data != NULL && dgst != NULL) + { + processUserAndData(session_fd, user, data, sess, dgst, service); + } + else + { + httpError(session_fd, 400, "Bad Request (6)"); + } + if (user != NULL) free(user); + if (data != NULL) free(data); + if (sess != NULL) free(sess); + if (dgst != NULL) free(dgst); + } + } + } + } + } + else if ( strcmp(info, "GET") == 0 ) + { + free(info); + info = httpParse("Path", buff, buff_len); + if ( strcmp(info, "/") == 0 ) + { + uint8_t* frontend = malloc(__rcs_frontend_html_len + 1); + memcpy(frontend, __rcs_frontend_html, __rcs_frontend_html_len); + frontend[__rcs_frontend_html_len] = 0; + httpStringOut(session_fd, frontend); + free(frontend); + } + else if ( strcmp(info, "/apk") == 0 ) + { + httpFileOut(session_fd, "./EstoulsAPI.apk", 0); + } + else if ( strcmp(info, "/favicon.ico") == 0 ) + { + httpFileOut(session_fd, "./favicon.ico", 1); + } + else + { + httpError(session_fd, 400, "Bad Request (7)"); + } + } + else + { + httpError(session_fd, 400, "Bad Request (8)"); + } + free(info); + free(buff); + } + + if (session_fd == -1 && errno != EINTR) + { + printf("Failed to accept connection %i.\n", errno); + } + + //End session + httpEnd(session_fd); +} + +void get_hostname() +{ + for (uint8_t i = 0; i <= 1; i++) + { + FILE* proc; + if (i) proc = popen("hostname -I | awk '{print $1}'", "r"); + else proc = popen("hostname", "r"); + char* hostname = malloc(1); + hostname[0] = 0; + size_t hostname_len = 1; + if (proc == NULL) + { + fprintf(stderr, "Unknown error in get_hostname().\n"); + exit(1); + } + int c; + while ( (c = fgetc(proc)) != EOF ) + { + if (c == '\n' || c == '\r') continue; + hostname = realloc(hostname, ++hostname_len); + hostname[hostname_len - 2] = c; + hostname[hostname_len - 1] = 0; + } + if (strlen(hostname) >= 1023) + { + hostname[1023] = 0; + } + if (i) strcpy(HOSTNAME_I, hostname); + else strcpy(HOSTNAME, hostname); + free(hostname); + } +} + +void main() +{ + get_hostname(); + + MYSQL *conn; + MYSQL_RES *res; + MYSQL_ROW row; + + // Initialize the connection handler + conn = mysql_init(NULL); + + // Connect to the database + if (!mysql_real_connect(conn, "localhost", HOSTNAME, "PAAAAAAAAAAAA", "APIService", 0, NULL, 0)) { + fprintf(stderr, "%s\n", mysql_error(conn)); + return; + } + + if (mysql_query(conn, "select 1 from information_schema.tables where table_schema='APIService' and table_name='AuthInfo' limit 1;")) + { + fprintf(stderr, "%s\n", mysql_error(conn)); + return; + } + res = mysql_use_result(conn); + uint8_t createTable = ((row = mysql_fetch_row(res)) == NULL); + if (createTable) + { + if (mysql_query(conn, "create table AuthInfo ( id int auto_increment primary key, service text, username text, authkey text, timeout int );")) + { + fprintf(stderr, "%s\n", mysql_error(conn)); + return; + } + } + mysql_free_result(res); + + if (mysql_query(conn, "select 1 from information_schema.tables where table_schema='APIService' and table_name='ServiceInfo' limit 1;")) + { + fprintf(stderr, "%s\n", mysql_error(conn)); + return; + } + res = mysql_use_result(conn); + createTable = ((row = mysql_fetch_row(res)) == NULL); + if (createTable) + { + if (mysql_query(conn, "create table ServiceInfo ( id int auto_increment primary key, service text, path text, parameters text );")) + { + fprintf(stderr, "%s\n", mysql_error(conn)); + return; + } + } + + mysql_free_result(res); + mysql_close(conn); + + //Open the socket + int socket_fd = httpOpenSocket(HOSTNAME_I, "8080"); + + //Begin processing packets + for (;;) + //for (int i = 0; i < 3; i++) + { + int session_fd; + httpBegin(socket_fd, &session_fd); + char* arg = malloc(sizeof(int)); + memcpy(arg, &session_fd, sizeof(int)); + pthread_t thread_id; + pthread_create(&thread_id, NULL, handleRequest, arg); + //pthread_join(thread_id, NULL); + } + + mysql_library_end(); +}