Signup and login now working! All new improved packet creation/parsing code - no more wasteful structures!

This commit is contained in:
Scott Duensing 2022-01-16 19:18:50 -06:00
parent ba1fe40938
commit 4cb64344be
10 changed files with 272 additions and 108 deletions

View file

@ -45,10 +45,12 @@ static ButtonT *_btnLogin = NULL;
static void btnCancelClick(WidgetT *widget);
static void btnSignUpClick(WidgetT *widget);
static void btnLoginClick(WidgetT *widget);
static void btnMsgBoxCancel(MsgBoxButtonT button);
static void btnMsgBoxContinue(MsgBoxButtonT button);
static void btnMsgBoxFinish(MsgBoxButtonT button);
static void setButtons(uint8_t enabled);
static void taskDisconnect(void *data);
static void taskLoginClick(void *data);
static void btnCancelClick(WidgetT *widget) {
@ -69,12 +71,6 @@ static void btnSignUpClick(WidgetT *widget) {
}
static void btnLoginClick(WidgetT *widget) {
(void)widget;
}
static void btnMsgBoxCancel(MsgBoxButtonT button) {
if (button == MSGBOX_BUTTON_ONE) {
@ -86,6 +82,13 @@ static void btnMsgBoxCancel(MsgBoxButtonT button) {
}
static void btnMsgBoxContinue(MsgBoxButtonT button) {
(void)button;
setButtons(1);
}
static void setButtons(uint8_t enabled) {
widgetEnableSet(W(_btnCancel), enabled);
widgetEnableSet(W(_btnSignUp), enabled);
@ -122,6 +125,8 @@ void taskLogin(void *data) {
(void)data;
// ***TODO*** We used to have a FORGOT PASSWORD button here, too.
TagItemT uiLogin[] = {
T_START,
T_WINDOW, O(_winLogin),
@ -156,7 +161,8 @@ void taskLogin(void *data) {
T_BUTTON, O(_btnLogin),
T_TITLE, P("Login"),
T_X, 199, T_Y, 85,
T_CLICK, P(btnLoginClick),
T_CLICK, P(taskProxy),
T_USER_DATA, P(taskLoginClick),
T_BUTTON, T_DONE,
T_WINDOW, T_DONE,
@ -165,3 +171,61 @@ void taskLogin(void *data) {
tagListRun(uiLogin);
}
static void taskLoginClick(void *data) {
char *packetData = NULL;
int8_t success = 0;
uint16_t length = 0;
int16_t timeout = 10;
PacketEncodeDataT encoded = { 0 };
PacketDecodeDataT *decoded = NULL;
(void)data;
// ***TODO*** This should disable the entire dialog instead of just the buttons. Need to finish the Enable GUI code first.
setButtons(0);
packetData = packetContentPack(&length, "ss", textboxValueGet(_txtUser), textboxValueGet(_txtPass));
// Send login request.
encoded.packetType = PACKET_TYPE_LOGIN;
encoded.control = PACKET_CONTROL_DAT;
encoded.channel = 0;
encoded.encrypt = 1;
packetEncode(__packetThreadData, &encoded, packetData, length);
packetSend(__packetThreadData, &encoded);
DEL(packetData);
// Wait for response.
do {
decoded = netGetPacket(0);
if (decoded) {
switch (decoded->packetType) {
case PACKET_TYPE_LOGIN_RESULT:
packetContentUnpack(decoded->data, "is", &success, &packetData);
logWrite("Login: %d %s\n", success, packetData);
if (success) {
// ***TODO*** Start Main Menu
guiDelete(D(_winLogin));
// taskCreate(taskLogin, NULL);
} else {
msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, packetData, "Okay", btnMsgBoxContinue);
}
DEL(packetData);
timeout = 0;
break;
default:
msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "Unexpected packet received.", "Okay", btnMsgBoxContinue);
timeout = 0;
break;
}
packetDecodeDataDestroy(&decoded);
}
taskYield();
if (__timerQuarterSecondTick) timeout--;
} while (!guiHasStopped() && timeout > 0);
}

View file

@ -175,9 +175,9 @@ void taskSignUp(void *data) {
static void taskSignUpClick(void *data) {
PacketEncodeDataT encoded = { 0 };
PacketDecodeDataT *decoded = NULL;
PacketTypeSignUpT signup = { 0 };
PacketTypeSignUpResultT *result = { 0 };
int16_t timeout = 5;
int16_t timeout = 10;
uint16_t length = 0;
char *packetData = NULL;
(void)data;
@ -185,23 +185,16 @@ static void taskSignUpClick(void *data) {
setButtons(0);
// Get the data.
memcpy(signup.email, textboxValueGet(_txtEmail), strlen(textboxValueGet(_txtEmail)));
memcpy(signup.first, textboxValueGet(_txtFirst), strlen(textboxValueGet(_txtFirst)));
memcpy(signup.last, textboxValueGet(_txtLast), strlen(textboxValueGet(_txtLast)));
memcpy(signup.pass, textboxValueGet(_txtPass1), strlen(textboxValueGet(_txtPass1)));
memcpy(signup.user, textboxValueGet(_txtUser), strlen(textboxValueGet(_txtUser)));
// Validate it. ***TODO*** These messages could be a lot better.
if (!validateEmail(signup.email)) {
if (!validateEmail(textboxValueGet(_txtEmail))) {
msgBoxOne("Invalid E-Mail", MSGBOX_ICON_ERROR, "Please enter a valid E-mail address.", "Okay", btnMsgBoxContinue);
return;
}
if (!validateName(signup.first)) {
if (!validateName(textboxValueGet(_txtFirst))) {
msgBoxOne("Invalid First Name", MSGBOX_ICON_ERROR, "Please enter a valid first name.", "Okay", btnMsgBoxContinue);
return;
}
if (!validateName(signup.last)) {
if (!validateName(textboxValueGet(_txtLast))) {
msgBoxOne("Invalid Last Name", MSGBOX_ICON_ERROR, "Please enter a valid last name.", "Okay", btnMsgBoxContinue);
return;
}
@ -209,40 +202,52 @@ static void taskSignUpClick(void *data) {
msgBoxOne("Invalid Password", MSGBOX_ICON_ERROR, "Passwords must match.", "Okay", btnMsgBoxContinue);
return;
}
if (!validatePassword(signup.pass)) {
if (!validatePassword(textboxValueGet(_txtPass1))) {
msgBoxOne("Invalid Password", MSGBOX_ICON_ERROR, "Please enter a valid password.", "Okay", btnMsgBoxContinue);
return;
}
if (!validateUser(signup.user)) {
if (!validateUser(textboxValueGet(_txtUser))) {
msgBoxOne("Invalid User Name", MSGBOX_ICON_ERROR, "Please enter a valid user name.", "Okay", btnMsgBoxContinue);
return;
}
packetData = packetContentPack(&length, "sssss",
textboxValueGet(_txtEmail),
textboxValueGet(_txtFirst),
textboxValueGet(_txtLast),
textboxValueGet(_txtPass1),
textboxValueGet(_txtUser)
);
// Send signup request.
encoded.packetType = PACKET_TYPE_SIGNUP;
encoded.control = PACKET_CONTROL_DAT;
encoded.channel = 0;
encoded.encrypt = 0;
packetEncode(__packetThreadData, &encoded, (char *)&signup, sizeof(PacketTypeSignUpT));
encoded.encrypt = 1;
packetEncode(__packetThreadData, &encoded, packetData, length);
packetSend(__packetThreadData, &encoded);
DEL(packetData);
// Wait for response.
do {
decoded = netGetPacket(0);
if (decoded) {
switch (decoded->packetType) {
case PACKET_TYPE_SIGNUP_RESULT:
result = (PacketTypeSignUpResultT *)decoded->data;
if (result->success) {
msgBoxOne("Success!", MSGBOX_ICON_INFORMATION, result->message, "Okay", btnMsgBoxFinish);
packetContentUnpack(decoded->data, "is", &length, &packetData);
if (length) {
msgBoxOne("Success!", MSGBOX_ICON_INFORMATION, packetData, "Okay", btnMsgBoxFinish);
} else {
msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, result->message, "Okay", btnMsgBoxContinue);
msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, packetData, "Okay", btnMsgBoxContinue);
}
DEL(packetData);
timeout = 0;
break;
default:
logWrite("Unexpected packet received: %d\n", decoded->packetType);
msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "Unexpected packet received.", "Okay", btnMsgBoxContinue);
timeout = 0;
break;
}
packetDecodeDataDestroy(&decoded);
@ -250,8 +255,6 @@ static void taskSignUpClick(void *data) {
taskYield();
if (__timerQuarterSecondTick) timeout--;
} while (!guiHasStopped() && timeout > 0);
setButtons(1);
}

View file

@ -179,7 +179,7 @@ static void taskConnectClick(void *data) {
break;
case PACKET_TYPE_VERSION:
__runtimeData.protocolVersion = *(uint32_t *)decoded->data;
packetContentUnpack(decoded->data, "i", &__runtimeData.protocolVersion);
// Do we need to update?
if (PACKET_PROTOCOL_VERSION == __runtimeData.protocolVersion) {
// Nope, we're good.

View file

@ -5,7 +5,6 @@ function kpApiUserCreate($first, $last, $username, $email, $password, &$response
// Check for duplicate username.
$user = kirby()->users()->filterBy('name', $username);
if ($user->first()) {
$response['result'] = 'false';
$response['reason'] = 'User name already exists.';
} else {
// Save Kirby attributes.
@ -41,7 +40,7 @@ function kpApiUserCreate($first, $last, $username, $email, $password, &$response
// Return result.
$response['result'] = 'true';
$response['reason'] = 'User created. Check your E-mail for activation instructions.';
$response['reason'] = 'Check your E-mail for activation instructions.';
}
} catch(Exception $e) {
if (strpos($e->getMessage(), "email")) {
@ -53,23 +52,23 @@ function kpApiUserCreate($first, $last, $username, $email, $password, &$response
}
function kpApiUserGet($email, &$response) {
function kpApiUserLogin($username, $pass, &$response) {
try {
$user = kirby()->users()->findByKey($email);
//$response['userraw'] = dump($user);
// Find user by name instead of email.
$user = kirby()->users()->filterBy('name', $username)->first();
if ($user) {
$response['name'] = $user->username();
$response['email'] = $user->email();
$response['password'] = $user->password();
$response['language'] = $user->language();
$response['role'] = $user->role()->id();
$response['result'] = 'true';
$response['reason'] = 'User found.';
// Attempt to sign them in.
kirby()->auth()->login($user->email(), $pass);
// They don't need an actual Kirby session, so log them off.
kirby()->auth()->logout();
// Report it.
$response['result'] = 'true';
$response['reason'] = 'User logged in.';
} else {
$response['reason'] = 'User not found.';
$response['reason'] = 'User name or password incorrect.';
}
} catch(Exception $e) {
$response['reason'] = $e->getMessage();
$response['reason'] = 'User name or password incorrect.';
}
}

View file

@ -43,8 +43,8 @@ return [
kpApiUserCreate(get('first'), get('last'), get('user'), get('email'), get('pass'), $response);
break;
case 'USER_GET':
kpApiUserGet(get('email'), $response);
case 'USER_LOGIN':
kpApiUserLogin(get('user'), get('pass'), $response);
break;
default:

View file

@ -67,16 +67,22 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
uint64_t i = 0;
uint64_t x = 0;
uint32_t y = 0;
uint64_t length = 0;
uint16_t length = 0;
char *buffer = NULL;
char *packetData = NULL;
char *user = NULL;
char *pass = NULL;
char *first = NULL;
char *last = NULL;
char *email = NULL;
PacketEncodeDataT encoded = { 0 };
json_object *response = NULL;
RestStringMapT *strings = NULL;
RestIntegerMapT *integers = NULL;
struct timespec timer = { 0 };
double d = 0;
PacketTypeSignUpT *signup = NULL;
PacketTypeSignUpResultT signupResult = { 0 };
uint8_t result = 0;
char *string = NULL;
switch (data->packetType) {
case PACKET_TYPE_CLIENT_SHUTDOWN:
@ -84,7 +90,34 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
break;
case PACKET_TYPE_LOGIN:
consoleMessageQueue("%ld: Channel %d %s %s\n", client->threadIndex, data->channel, ((PacketTypeLoginT *)data->data)->user, ((PacketTypeLoginT *)data->data)->pass);
packetContentUnpack(data->data, "ss", &user, &pass);
response = restRequest("USER_LOGIN", "ss",
"user", user,
"pass", pass
);
DEL(user);
DEL(pass);
if (response) {
string = (char *)json_object_get_string(json_object_object_get(response, "result"));
result = (string[0] == 't' || string[0] == 'T') ? 1 : 0;
buffer = (char *)json_object_get_string(json_object_object_get(response, "reason"));
} else {
// Something bad happened.
result = 0;
buffer = "Unknown error. Sorry.";
}
logWrite("Login: %d %s\r\n", result, buffer);
packetData = packetContentPack(&length, "is", result, buffer);
if (response) restRelease(response);
// Build packet.
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_LOGIN_RESULT;
encoded.channel = 0;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, packetData, length);
// Send it.
packetSend(client->packetThreadData, &encoded);
DEL(packetData);
break;
case PACKET_TYPE_PONG:
@ -111,32 +144,34 @@ static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data)
break;
case PACKET_TYPE_SIGNUP:
signup = (PacketTypeSignUpT *)data->data;
packetContentUnpack(data->data, "sssss", &email, &first, &last, &pass, &user);
response = restRequest("USER_CREATE", "sssss",
"first", signup->first,
"last", signup->last,
"user", signup->user,
"pass", signup->pass,
"email", signup->email
"first", first,
"last", last,
"user", user,
"pass", pass,
"email", email
);
if (response) {
signupResult.success = (json_object_get_boolean(json_object_object_get(response, "result")) == TRUE) ? 1 : 0;
string = (char *)json_object_get_string(json_object_object_get(response, "result"));
result = (string[0] == 't' || string[0] == 'T') ? 1 : 0;
buffer = (char *)json_object_get_string(json_object_object_get(response, "reason"));
} else {
// Something bad happened.
signupResult.success = 0;
result = 0;
buffer = "Unknown error. Sorry.";
}
memcpy(signupResult.message, buffer, strlen(buffer));
packetData = packetContentPack(&length, "is", result, buffer);
if (response) restRelease(response);
// Build packet.
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_SIGNUP_RESULT;
encoded.channel = 0;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, (char *)&signupResult, sizeof(PacketTypeSignUpResultT));
packetEncode(client->packetThreadData, &encoded, packetData, length);
// Send it.
packetSend(client->packetThreadData, &encoded);
DEL(packetData);
break;
case PACKET_TYPE_VERSION_BAD:
@ -269,11 +304,12 @@ void *clientThread(void *data) {
PacketEncodeDataT encoded = { 0 };
struct timespec remaining = { 0, 0 };
struct timespec sleepTime = { 0, 1000000000/100 }; // 1/100th second.
PacketTypeVersionT version = { 0 };
uint8_t versionSent = 0;
time_t ticks = { 0 };
time_t lastTicks = { 0 };
int8_t pingTimeout = 0;
char *packetData = NULL;
uint16_t length = 0;
// Process packets until we're done.
while (client->running) {
@ -282,14 +318,15 @@ void *clientThread(void *data) {
// Start communications with client as soon as encryption channel is ready.
if (!versionSent) {
if (packetEncryptionReady()) {
packetData = packetContentPack(&length, "i", PACKET_PROTOCOL_VERSION);
// Send required protocol version.
version.version = PACKET_PROTOCOL_VERSION;
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_VERSION;
encoded.channel = 0;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, (char *)&version, sizeof(PacketTypeVersionT));
packetEncode(client->packetThreadData, &encoded, packetData, length);
packetSend(client->packetThreadData, &encoded);
DEL(packetData);
versionSent = 1;
}
}
@ -305,7 +342,7 @@ void *clientThread(void *data) {
encoded.packetType = PACKET_TYPE_PING;
encoded.channel = 0;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, (char *)&version, sizeof(PacketTypeVersionT));
packetEncode(client->packetThreadData, &encoded, NULL, 0);
packetSend(client->packetThreadData, &encoded);
clock_gettime(CLOCK_MONOTONIC_RAW, &client->pingStart);
}

View file

@ -187,22 +187,26 @@ void restRelease(json_object *object) {
json_object *restRequest(char *command, char *format, ...) {
va_list args = { 0 };
json_object *request = json_object_new_object();
json_object *response = NULL;
va_list args = { 0 };
json_object *request = json_object_new_object();
json_object *response = NULL;
char *key = NULL;
char *string = NULL;
uint8_t result = 0;
json_object_object_add(request, "command", json_object_new_string(command));
va_start(args, format);
if (format) {
while (*format != 0) {
key = va_arg(args, char *);
switch (*format) {
case 's':
json_object_object_add(request, va_arg(args, char *), json_object_new_string(va_arg(args, char *)));
json_object_object_add(request, key, json_object_new_string(va_arg(args, char *)));
break;
case 'i':
json_object_object_add(request, va_arg(args, char *), json_object_new_int64(va_arg(args, int64_t)));
json_object_object_add(request, key, json_object_new_int64(va_arg(args, int64_t)));
break;
default:
@ -217,10 +221,12 @@ json_object *restRequest(char *command, char *format, ...) {
//logWrite("Request: %s\n", json_object_to_json_string_ext(request, JSON_C_TO_STRING_PRETTY));
response = restUrlPost(request);
json_object_put(request);
//logWrite("Response: %s\n", json_object_to_json_string_ext(response, JSON_C_TO_STRING_PRETTY));
logWrite("Response: %s\n", json_object_to_json_string_ext(response, JSON_C_TO_STRING_PRETTY));
if (response) {
if (json_object_get_boolean(json_object_object_get(response, "result")) != TRUE) {
string = (char *)json_object_get_string(json_object_object_get(response, "result"));
result = (string[0] == 't' || string[0] == 'T') ? 1 : 0;
if (result) {
logWrite("restRequest: %s\n", json_object_get_string(json_object_object_get(response, "reason")));
json_object_put(response);
}

View file

@ -41,6 +41,8 @@
*/
#include <stdarg.h>
#include "packet.h"
#include "primes.h"
@ -71,6 +73,89 @@ static void *packetAesContextCreate(uint8_t *key, uint8_t *iv) {
}
char *packetContentPack(uint16_t *length, char *format, ...) {
va_list args = { 0 };
static char work[PACKET_MAX] = { 0 };
char *result = NULL;
char *buffer = NULL;
int8_t value8 = 0;
int32_t value32 = 0;
*length = 0;
va_start(args, format);
if (format) {
while (*format != 0) {
switch (*format) {
case 'i':
// Copy integer as 32-bit integer.
value32 = va_arg(args, int32_t);
memcpy(&work[*length], &value32, sizeof(int32_t));
*length += sizeof(int32_t);
break;
case 's':
// Copy string including the terminating zero.
buffer = va_arg(args, char *);
memcpy(&work[*length], buffer, strlen(buffer) + 1);
*length += strlen(buffer) + 1;
break;
default:
utilDie("restRequest: Unknown format option '%c'.\n", *format);
break;
}
format++;
}
}
va_end(args);
// Copy working buffer to result to return.
if (*length > 0) {
result = (char *)malloc(*length);
memcpy(result, work, *length);
}
return result;
}
void packetContentUnpack(char *buffer, char *format, ...) {
va_list args = { 0 };
char **string = NULL;
int8_t *value8 = NULL;
int32_t *value32 = NULL;
uint16_t length = 0;
va_start(args, format);
if (format) {
while (*format != 0) {
switch (*format) {
case 'i':
// Copy integer as 32-bit integer.
value32 = va_arg(args, int32_t *);
memcpy(value32, &buffer[length], sizeof(int32_t));
length += sizeof(int32_t);
break;
case 's':
// Copy string including the terminating zero.
string = va_arg(args, char **);
*string = strdup(&buffer[length]);
length += strlen(*string) + 1;
break;
default:
utilDie("restRequest: Unknown format option '%c'.\n", *format);
break;
}
format++;
}
}
va_end(args);
}
static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt) {
uint16_t x = 0;

View file

@ -119,6 +119,8 @@ typedef struct PacketThreadDataS {
typedef void (*packetSender)(char *data, uint32_t length, void *userData);
char *packetContentPack(uint16_t *length, char *format, ...);
void packetContentUnpack(char *buffer, char *format, ...);
uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *decodeData, char *input, uint16_t inputLength);
void packetDecodeDataDestroy(PacketDecodeDataT **packet);
void packetDecodeDataStaticDestroy(PacketDecodeDataT *packet);

View file

@ -27,12 +27,6 @@
#define PACKET_PROTOCOL_VERSION 1
#define PACKET_MAX_USER 16 // These need to match the configuration in the database.
#define PACKET_MAX_PASS 16 // Or better, use the database values.
#define PACKET_MAX_NAME 32
#define PACKET_MAX_EMAIL 32
#define PACKET_MAX_MESSAGE 256
// This enum is treated as BYTES in the code. Do not go over 255 entries.
typedef enum PacketTypeE {
@ -49,38 +43,12 @@ typedef enum PacketTypeE {
PACKET_TYPE_STRING,
PACKET_TYPE_NUMBER,
PACKET_TYPE_PROCEED,
PACKET_TYPE_LOGIN,
PACKET_TYPE_SIGNUP,
PACKET_TYPE_SIGNUP_RESULT,
PACKET_TYPE_LOGIN,
PACKET_TYPE_LOGIN_RESULT,
PACKET_TYPE_COUNT
} PacketTypeT;
#pragma pack(push, 1)
typedef struct PacketTypeVersionS {
uint32_t version;
} PacketTypeVersionT;
typedef struct PacketTypeLoginS {
char user[PACKET_MAX_USER];
char pass[PACKET_MAX_PASS];
} PacketTypeLoginT;
typedef struct PacketTypeSignUpS {
char user[PACKET_MAX_USER];
char pass[PACKET_MAX_PASS];
char first[PACKET_MAX_NAME];
char last[PACKET_MAX_NAME];
char email[PACKET_MAX_EMAIL];
} PacketTypeSignUpT;
typedef struct PacketTypeSignUpResultS {
uint8_t success;
char message[PACKET_MAX_MESSAGE];
} PacketTypeSignUpResultT;
#pragma pack(pop)
#endif // PACKETS_H