Browse Source

captcha on login now

master
Cerys 4 weeks ago
parent
commit
82e48acfa1
  1. 1
      .gitignore
  2. 1
      App/Enumerators/SessionElement.php
  3. 89
      App/Wrappers/CAPTCHAWrapper.php
  4. 11
      App/Wrappers/SessionWrapper.php
  5. 2
      App/Wrappers/TwigWrapper.php
  6. 5
      Configuration/Configuration.yaml
  7. 4
      Localisation/en-GB.yaml
  8. 12
      Pages/logout.php
  9. 6
      Public/FormHandling/Login.php
  10. 50
      Templates/Pages/login.html.twig
  11. 2
      Templates/Pages/profile.html.twig
  12. 4
      composer.json
  13. 1079
      composer.lock

1
.gitignore

@ -4,3 +4,4 @@ vendor/
composer.phar
Configuration/Secrets.yaml
Configuration/GCCServiceAccountCreds.json

1
App/Enumerators/SessionElement.php

@ -7,4 +7,5 @@ enum SessionElement: string
case IS_LOGGED_IN = "IS_LOGGED_IN";
case USER_ID = "USER_ID";
case USERNAME = "USERNAME";
case LAST_ASSESSMENT_RESULT = "LAST_ASSESSMENT_RESULT";
}

89
App/Wrappers/CAPTCHAWrapper.php

@ -0,0 +1,89 @@
<?php
namespace App\Wrappers;
require_once __DIR__ . "/../../vendor/autoload.php";
// Include Google Cloud dependencies using Composer
use App\Configuration;
use App\Enumerators\SessionElement;
use Google\Cloud\RecaptchaEnterprise\V1\Assessment;
use Google\Cloud\RecaptchaEnterprise\V1\Event;
use Google\Cloud\RecaptchaEnterprise\V1\Key;
use Google\Cloud\RecaptchaEnterprise\V1\RecaptchaEnterpriseServiceClient;
use Google\Cloud\RecaptchaEnterprise\V1\TokenProperties\InvalidReason;
use Google\Cloud\RecaptchaEnterprise\V1\WebKeySettings;
use Google\Cloud\RecaptchaEnterprise\V1\WebKeySettings\IntegrationType;
use Grpc\Gcp\Config;
class CAPTCHAWrapper
{
public static function CreateAssessment(
string $token,
string $action
): ?float
{
$credFilePath = __DIR__ . "/../../Configuration/GCCServiceAccountCreds.json";
putenv("GOOGLE_APPLICATION_CREDENTIALS=$credFilePath");
// Create the reCAPTCHA client.
// TODO: Cache the client generation code (recommended) or call client.close() before exiting the method.
$client = new RecaptchaEnterpriseServiceClient();
$project = Configuration::GetConfig("reCAPTCHA", "ProjectID");
$projectName = $client->projectName($project);
// Set the properties of the event to be tracked.
$event = (new Event())
->setSiteKey(Configuration::GetConfig("reCAPTCHA", "KeyID"))
->setToken($token);
// Build the assessment request.
$assessment = (new Assessment())->setEvent($event);
$response = $client->createAssessment(
$projectName,
$assessment
);
// Check if the token is valid.
if ($response->getTokenProperties()->getValid() == false) {
// printf('The CreateAssessment() call failed because the token was invalid for the following reason: ');
// printf(InvalidReason::name($response->getTokenProperties()->getInvalidReason()));
return floatval(-1);
}
// Check if the expected action was executed.
if ($response->getTokenProperties()->getAction() == $action) {
// Get the risk score and the reason(s).
// For more information on interpreting the assessment, see:
// https://cloud.google.com/recaptcha-enterprise/docs/interpret-assessment
// printf('The score for the protection action is:');
return $response->getRiskAnalysis()->getScore();
} else {
// printf('The action attribute in your reCAPTCHA tag does not match the action you are expecting to score');
}
return null;
}
public static function HandleCaptchaResponse(string $captchaResponse): void
{
$assessmentResponse = CAPTCHAWrapper::CreateAssessment(
token: $captchaResponse,
action: 'submit'
);
if ($assessmentResponse == null)
{
die("captcha assessment is null");
}
if ($assessmentResponse <= floatval(Configuration::GetConfig("reCAPTCHA", "AcceptableLowerBoundsForLogin")))
{
die("go away robot!");
}
SessionWrapper::Set(SessionElement::LAST_ASSESSMENT_RESULT, $assessmentResponse);
}
}

11
App/Wrappers/SessionWrapper.php

@ -8,12 +8,13 @@ class SessionWrapper
{
public static function Start(): void
{
if (session_status() == PHP_SESSION_NONE) {
if (session_status() == PHP_SESSION_NONE)
{
session_start();
}
}
public static function Get(SessionElement $target)
public static function Get(SessionElement $target): mixed
{
self::Start();
if(array_key_exists(key: $target->value, array: $_SESSION))
@ -22,4 +23,10 @@ class SessionWrapper
}
die();
}
public static function Set(SessionElement $target, mixed $newValue): void
{
self::Start();
$_SESSION[$target->value] = $newValue;
}
}

2
App/Wrappers/TwigWrapper.php

@ -43,6 +43,8 @@ class TwigWrapper
$this->twig->addGlobal('_CURRENT_URI_', urlencode("http://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"));
$this->twig->addGlobal('_USER_TIMEZONE_OFFSET_', 60);
$this->twig->addGlobal('_CAPTCHA_KEY_ID_', Configuration::GetConfig('reCAPTCHA', 'KeyID'));
$this->twig->addExtension(new FiltersExtension());
$this->twig->addExtension(new FunctionExtensions($this->twig));

5
Configuration/Configuration.yaml

@ -16,3 +16,8 @@ MariaDB:
Username: ;MARIADB__USERNAME
Password: ;MARIADB__PASSWORD
Database: FolkTuneFinder_Live
reCAPTCHA:
KeyID: ;RECAPTCHA_ENTERPRISE_KEY_ID
ProjectID: ;RECAPTCHA_ENTERPRISE_PROJECT_ID
AcceptableLowerBoundsForLogin: 0.5

4
Localisation/en-GB.yaml

@ -3,6 +3,7 @@
# A
##################################################
ABC Notation: ABC Notation
Account Login: Account Login
Audio: Audio
@ -17,7 +18,9 @@ Bars: Bars
##################################################
# C
##################################################
Confirm Password: Confirm Password
Copyright: Copyright
Create an Account: Create an Account
@ -77,6 +80,7 @@ Key Signature: Key Signature
# L
##################################################
Log in to vote: Log in to vote
Logout: Logout

12
Pages/logout.php

@ -0,0 +1,12 @@
<?php
use App\Wrappers\SessionWrapper;
require_once __DIR__ . "/../vendor/autoload.php";
SessionWrapper::Start();
$_SESSION = [];
header("Location: /");
die();

6
Public/FormHandling/Login.php

@ -1,11 +1,17 @@
<?php
use App\Enumerators\SessionElement;
use App\Wrappers\CAPTCHAWrapper;
use App\Wrappers\DatabaseInteractions;
use App\Wrappers\SQLQueryBuilderWrapper;
require_once __DIR__ . "/../../vendor/autoload.php";
$captchaResponse = $_POST['g-recaptcha-response'];
CAPTCHAWrapper::HandleCaptchaResponse($captchaResponse);
$username = $_POST['Username'];
$password = $_POST['Password'];

50
Templates/Pages/login.html.twig

@ -1,9 +1,22 @@
{% extends "/Bases/StandardWebPage.html.twig" %}
{% block content %}
<script src="https://www.google.com/recaptcha/enterprise.js?render={{ _CAPTCHA_KEY_ID_ }}"></script>
<script>
function onSubmitLoginForm(token) {
document.getElementById("LoginForm").submit();
}
function onSubmitCreateAccountForm(token) {
document.getElementById("CreateAccountForm").submit();
}
</script>
<div class="InnerContent">
<h1>Ceilidh Kit Login</h1>
<h1>{{ "Account Login"|translate }}</h1>
<form
id="LoginForm"
action="/FormHandling/Login.php"
method="POST"
>
@ -19,7 +32,40 @@
<br>
<input type="submit">
<button class="g-recaptcha"
data-sitekey="{{ _CAPTCHA_KEY_ID_ }}"
data-callback='onSubmitLoginForm'
data-action='submit'>{{ "Login"|translate }}</button>
</form>
<h1>{{ "Create an Account"|translate }}</h1>
<form
id="CreateAccountForm"
action="/FormHandling/CreateAccount.php"
method="POST"
>
<label for="Username">{{ "Username"|translate }}</label>
<br>
<input id="Username" name="Username" type="text">
<br>
<label for="Password1">{{ "Password"|translate }}</label>
<br>
<input id="Password1" name="Password1" type="password">
<br>
<label for="Password2">{{ "Confirm Password"|translate }}</label>
<br>
<input id="Password2" name="Password2" type="password">
<br>
<button class="g-recaptcha"
data-sitekey="{{ _CAPTCHA_KEY_ID_ }}"
data-callback='onSubmitCreateAccountForm'
data-action='submit'>{{ "Create Account"|translate }}</button>
</form>
</div>
{% endblock %}

2
Templates/Pages/profile.html.twig

@ -4,6 +4,8 @@
<div class="InnerContent">
<h1>{{ "Your Profile"|translate }}</h1>
<a href="/logout">{{ "Logout"|translate }}</a>
<div class="DLContainer">
<h2>{{ "Summary"|translate }}</h2>
<dl>

4
composer.json

@ -27,6 +27,8 @@
"algolia/algoliasearch-client-php": "*",
"ext-pdo": "*",
"aura/sqlquery": "2.8.1"
"aura/sqlquery": "2.8.1",
"google/cloud-recaptcha-enterprise": "v1.7.0"
}
}

1079
composer.lock

File diff suppressed because it is too large
Loading…
Cancel
Save