Skip to content

Commit

Permalink
Refresh Turnstile and the CSRF token after a message is sent (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
Spencer14420 authored Nov 29, 2024
1 parent b490f50 commit ee8d432
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 9 deletions.
4 changes: 4 additions & 0 deletions api.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
case "sendMessage":
require_once __DIR__ . "/dist/php/email-handler.php";
break;

case "getCSRFToken":
require_once __DIR__ . "/dist/php/token-handler.php";
break;

default:
http_response_code(400);
Expand Down
3 changes: 1 addition & 2 deletions dist/php/email-handler.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?php
require_once __DIR__ . "/../../vendor/autoload.php";
require_once __DIR__ . "/token-handler.php";

use spencer14420\PhpEmailHandler\EmailHandler;

Expand All @@ -9,5 +8,5 @@
$emailHandler = new EmailHandler(__DIR__ . "/email-config.php");
$emailHandler->handleRequest();
} catch(Exception $e) {
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
3 changes: 2 additions & 1 deletion dist/php/token-handler.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php
require_once __DIR__ . "/../../vendor/autoload.php";
use spencer14420\SpAntiCsrf\AntiCsrf;
$tokenHandler = new AntiCsrf();
$tokenHandler = new AntiCsrf();
echo json_encode(['token' => $tokenHandler->generateToken()]);
7 changes: 1 addition & 6 deletions index.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
<?php
session_start();
require_once __DIR__ . "/dist/php/token-handler.php";
$token = $tokenHandler->generateToken();
?>
<!DOCTYPE html>
<html lang="en">

Expand Down Expand Up @@ -266,7 +261,7 @@
<textarea class="form-control" id="message" name="message" rows="5"></textarea>
</div>
<div style="text-align: center;" id="turnstile-container"></div>
<input type="hidden" id="SpCsrfToken" name="SpCsrfToken" value="<?php echo $token ?>">
<input type="hidden" id="SpCsrfToken" name="SpCsrfToken" value="">
<div id="message-alert" class="alert alert-danger" role="alert"></div>
</div>
<div class="modal-footer">
Expand Down
5 changes: 5 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ import { Modal } from "sp14420-modal";
import { Utils } from "./utils/utils";

document.addEventListener("DOMContentLoaded", () => {
//Sets the CSRF token in the contact form input field
Utils.setCsrfToken();

// Initialize the contact form
const contactForm = new ContactForm(
"api.php?action=sendMessage",
"SpCsrfToken",
Utils.refreshContactForm(),
);
});

Expand Down
57 changes: 57 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,63 @@ export class Utils {
});
}

// Gets and a CSRF token from the server
static async getCsrfToken(): Promise<string | null> {
const apiEndpoint = "./api.php?action=getCSRFToken";

try {
const response = await fetch(apiEndpoint);

if (!response.ok) {
console.error(`Error, status: ${response.status}`);
return null;
}

const data = await response.json();

if (data && data.token) {
return data.token;
} else {
console.error("Token not found in the response.");
return null;
}
} catch (error) {
console.error("Error fetching the CSRF token:", error);
return null;
}
}

// Sets the CSRF token in the contact form input field
static async setCsrfToken(): Promise<void> {
const csrfTokenInput = document.getElementById(
"SpCsrfToken",
) as HTMLInputElement;
if (!csrfTokenInput) {
console.error('Input element with id "SpCsrfToken" not found.');
return;
}

try {
const token = await Utils.getCsrfToken();
if (!token) {
console.error("Failed to fetch a valid CSRF token.");
return;
}

csrfTokenInput.value = token;
} catch (error) {
console.error("Error setting the CSRF token:", error);
}
}

//Reloads turnstile and regenerates the CSRF token for the contact form
static refreshContactForm(): (responseData: Record<string, any>) => void {
return (responseData: Record<string, any>) => {
this.updateTurnstileWidget();
this.setCsrfToken();
};
}

static debounce<T extends (...args: any[]) => any>(
func: T,
delay: number,
Expand Down

0 comments on commit ee8d432

Please sign in to comment.