Created JWT Authentication #25

Merged
rodude123 merged 5 commits from jwt-auth into master 2022-10-09 03:07:10 +01:00
13 changed files with 726 additions and 83 deletions

View File

@ -11,6 +11,8 @@
"laminas/laminas-httphandlerrunner": "^2.0", "laminas/laminas-httphandlerrunner": "^2.0",
"selective/samesite-cookie": "^0.3.0", "selective/samesite-cookie": "^0.3.0",
"ext-json": "*", "ext-json": "*",
"slim/slim": "^4.10" "slim/slim": "^4.10",
"rbdwllr/psr-jwt": "^2.0",
"tuupola/slim-jwt-auth": "^3.6"
} }
} }

388
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "bbd0a827a6d61bc9032697dbd94a5045", "content-hash": "79f27ef0ad8fb8ffff7e6726df8c1f79",
"packages": [ "packages": [
{ {
"name": "fig/http-message-util", "name": "fig/http-message-util",
@ -62,6 +62,63 @@
}, },
"time": "2020-11-24T22:02:12+00:00" "time": "2020-11-24T22:02:12+00:00"
}, },
{
"name": "firebase/php-jwt",
"version": "v5.5.1",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
"reference": "83b609028194aa042ea33b5af2d41a7427de80e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/83b609028194aa042ea33b5af2d41a7427de80e6",
"reference": "83b609028194aa042ea33b5af2d41a7427de80e6",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": ">=4.8 <=9"
},
"suggest": {
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
},
"type": "library",
"autoload": {
"psr-4": {
"Firebase\\JWT\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Neuman Vong",
"email": "neuman+pear@twilio.com",
"role": "Developer"
},
{
"name": "Anant Narayanan",
"email": "anant@php.net",
"role": "Developer"
}
],
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
"homepage": "https://github.com/firebase/php-jwt",
"keywords": [
"jwt",
"php"
],
"support": {
"issues": "https://github.com/firebase/php-jwt/issues",
"source": "https://github.com/firebase/php-jwt/tree/v5.5.1"
},
"time": "2021-11-08T20:18:51+00:00"
},
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.4.0", "version": "2.4.0",
@ -1346,6 +1403,130 @@
}, },
"time": "2019-03-08T08:55:37+00:00" "time": "2019-03-08T08:55:37+00:00"
}, },
{
"name": "rbdwllr/psr-jwt",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/RobDWaller/psr-jwt.git",
"reference": "c32c7ee4c86fe30a7f38ba4763ef8793ad60b1bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/RobDWaller/psr-jwt/zipball/c32c7ee4c86fe30a7f38ba4763ef8793ad60b1bb",
"reference": "c32c7ee4c86fe30a7f38ba4763ef8793ad60b1bb",
"shasum": ""
},
"require": {
"nyholm/psr7": "^1.5",
"php": ">=7.4.0",
"psr/http-message": "^1.0",
"psr/http-server-middleware": "^1.0",
"rbdwllr/reallysimplejwt": "^4.0"
},
"require-dev": {
"infection/infection": "^0.20",
"mockery/mockery": "^1.5",
"phploc/phploc": "^7.0",
"phpmd/phpmd": "^2.12",
"phpstan/phpstan": "^1.5",
"phpstan/phpstan-mockery": "^1.0",
"phpunit/phpunit": "^9.0",
"sebastian/phpcpd": "^6.0",
"squizlabs/php_codesniffer": "^3.6"
},
"type": "library",
"autoload": {
"psr-4": {
"Tests\\": "tests/",
"PsrJwt\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Waller",
"email": "rdwaller1984@googlemail.com"
}
],
"description": "A PSR 7 compliant JSON Web Token Middleware Library.",
"keywords": [
"Authentication",
"authorisation",
"json",
"json web tokens",
"jwt",
"php",
"psr-7",
"tokens"
],
"support": {
"issues": "https://github.com/RobDWaller/psr-jwt/issues",
"source": "https://github.com/RobDWaller/psr-jwt/tree/2.0.1"
},
"time": "2022-06-11T13:28:17+00:00"
},
{
"name": "rbdwllr/reallysimplejwt",
"version": "4.0.3",
"source": {
"type": "git",
"url": "https://github.com/RobDWaller/ReallySimpleJWT.git",
"reference": "2b92aba98c71cfc4046dea895659450bfce530ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/RobDWaller/ReallySimpleJWT/zipball/2b92aba98c71cfc4046dea895659450bfce530ed",
"reference": "2b92aba98c71cfc4046dea895659450bfce530ed",
"shasum": ""
},
"require": {
"php": ">=7.4.0"
},
"require-dev": {
"infection/infection": "^0.20",
"phpbench/phpbench": "^1.0",
"phploc/phploc": "^7.0",
"phpmd/phpmd": "^2.9",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^9.5",
"sebastian/phpcpd": "^6.0",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"autoload": {
"psr-4": {
"ReallySimpleJWT\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Waller",
"email": "rdwaller1984@gmail.com"
}
],
"description": "A really simple library to generate user authentication JSON Web Tokens.",
"keywords": [
"Authentication",
"json",
"json web tokens",
"jwt",
"php",
"tokens"
],
"support": {
"issues": "https://github.com/RobDWaller/ReallySimpleJWT/issues",
"source": "https://github.com/RobDWaller/ReallySimpleJWT/tree/4.0.3"
},
"time": "2021-07-12T10:12:22+00:00"
},
{ {
"name": "selective/samesite-cookie", "name": "selective/samesite-cookie",
"version": "0.3.0", "version": "0.3.0",
@ -1744,6 +1925,211 @@
} }
], ],
"time": "2022-05-10T07:21:04+00:00" "time": "2022-05-10T07:21:04+00:00"
},
{
"name": "tuupola/callable-handler",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/tuupola/callable-handler.git",
"reference": "0bc7b88630ca753de9aba8f411046856f5ca6f8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tuupola/callable-handler/zipball/0bc7b88630ca753de9aba8f411046856f5ca6f8c",
"reference": "0bc7b88630ca753de9aba8f411046856f5ca6f8c",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0",
"psr/http-server-middleware": "^1.0"
},
"require-dev": {
"overtrue/phplint": "^1.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0",
"squizlabs/php_codesniffer": "^3.2",
"tuupola/http-factory": "^0.4.0|^1.0",
"zendframework/zend-diactoros": "^1.6.0|^2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Tuupola\\Middleware\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mika Tuupola",
"email": "tuupola@appelsiini.net",
"homepage": "https://appelsiini.net/",
"role": "Developer"
}
],
"description": "Compatibility layer for PSR-7 double pass and PSR-15 middlewares.",
"homepage": "https://github.com/tuupola/callable-handler",
"keywords": [
"middleware",
"psr-15",
"psr-7"
],
"support": {
"issues": "https://github.com/tuupola/callable-handler/issues",
"source": "https://github.com/tuupola/callable-handler/tree/1.1.0"
},
"funding": [
{
"url": "https://github.com/tuupola",
"type": "github"
}
],
"time": "2020-09-09T08:31:54+00:00"
},
{
"name": "tuupola/http-factory",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/tuupola/http-factory.git",
"reference": "ae3f8fbdd31cf2f1bbe920b38963c5e4d1e9c454"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tuupola/http-factory/zipball/ae3f8fbdd31cf2f1bbe920b38963c5e4d1e9c454",
"reference": "ae3f8fbdd31cf2f1bbe920b38963c5e4d1e9c454",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0",
"psr/http-factory": "^1.0"
},
"conflict": {
"nyholm/psr7": "<1.0"
},
"provide": {
"psr/http-factory-implementation": "^1.0"
},
"require-dev": {
"http-interop/http-factory-tests": "^0.9.0",
"overtrue/phplint": "^3.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0",
"squizlabs/php_codesniffer": "^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Tuupola\\Http\\Factory\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mika Tuupola",
"email": "tuupola@appelsiini.net",
"homepage": "https://appelsiini.net/",
"role": "Developer"
}
],
"description": "Lightweight autodiscovering PSR-17 HTTP factories",
"homepage": "https://github.com/tuupola/http-factory",
"keywords": [
"http",
"psr-17",
"psr-7"
],
"support": {
"issues": "https://github.com/tuupola/http-factory/issues",
"source": "https://github.com/tuupola/http-factory/tree/1.4.0"
},
"funding": [
{
"url": "https://github.com/tuupola",
"type": "github"
}
],
"time": "2021-09-14T12:46:25+00:00"
},
{
"name": "tuupola/slim-jwt-auth",
"version": "3.6.0",
"source": {
"type": "git",
"url": "https://github.com/tuupola/slim-jwt-auth.git",
"reference": "d9ed8bca77a0ef2a95ab48e65ddc26073b99c5ff"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tuupola/slim-jwt-auth/zipball/d9ed8bca77a0ef2a95ab48e65ddc26073b99c5ff",
"reference": "d9ed8bca77a0ef2a95ab48e65ddc26073b99c5ff",
"shasum": ""
},
"require": {
"firebase/php-jwt": "^3.0|^4.0|^5.0",
"php": "^7.1|^8.0",
"psr/http-message": "^1.0",
"psr/http-server-middleware": "^1.0",
"psr/log": "^1.0|^2.0|^3.0",
"tuupola/callable-handler": "^0.3.0|^0.4.0|^1.0",
"tuupola/http-factory": "^0.4.0|^1.0.2"
},
"require-dev": {
"equip/dispatch": "^2.0",
"laminas/laminas-diactoros": "^2.0",
"overtrue/phplint": "^1.0",
"phpstan/phpstan": "^0.12.43",
"phpunit/phpunit": "^7.0|^8.0|^9.0",
"squizlabs/php_codesniffer": "^3.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-3.x": "3.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Tuupola\\Middleware\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mika Tuupola",
"email": "tuupola@appelsiini.net",
"homepage": "https://appelsiini.net/",
"role": "Developer"
}
],
"description": "PSR-7 and PSR-15 JWT Authentication Middleware",
"homepage": "https://github.com/tuupola/slim-jwt-auth",
"keywords": [
"auth",
"json",
"jwt",
"middleware",
"psr-15",
"psr-7"
],
"support": {
"issues": "https://github.com/tuupola/slim-jwt-auth/issues",
"source": "https://github.com/tuupola/slim-jwt-auth/tree/3.6.0"
},
"funding": [
{
"url": "https://github.com/tuupola",
"type": "github"
}
],
"time": "2022-01-12T11:15:02+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],

21
dist/api/config.php vendored
View File

@ -1,21 +0,0 @@
<?php
//////////// Config file /////////////////////
/// Used for storing important information ///
/// such as passwords, usernames etc. ///
//////////////////////////////////////////////
function dbConn(): PDO|string
{
$host = "localhost";
$dbName = "u987021215_cms";
$username = "u987021215_rodude123";
$password = "pFHS5qKhkyaDumgf";
try
{
return new PDO("mysql:host=$host;dbname=$dbName", $username, $password);
}
catch (PDOException $e)
{
return "Connection failed: " . $e->getMessage();
}
}

42
dist/api/index.php vendored
View File

@ -1,4 +1,4 @@
<?php <?php /** @noinspection PhpIncludeInspection */
session_start(); session_start();
////////////////// Index file ////////////// ////////////////// Index file //////////////
@ -7,40 +7,30 @@ session_start();
//////////////////////////////////////////// ////////////////////////////////////////////
//require “routes.php”; //require “routes.php”;
require "../vendor/autoload.php"; require "../vendor/autoload.php";
include "middleware.php";
include "timelineData.php"; include "timelineData.php";
include "projectData.php"; include "projectData.php";
include "user.php"; include "user.php";
use api\middleware;
use api\projectData; use api\projectData;
use api\timelineData; use api\timelineData;
use api\user; use api\user;
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use Selective\SameSiteCookie\SameSiteCookieConfiguration; use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Slim\Factory\AppFactory;
use Selective\SameSiteCookie\SameSiteCookieMiddleware; use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Slim\Handlers\Strategies\RequestHandler; use Slim\Factory\AppFactory;
use Tuupola\Middleware\JwtAuthentication;
// Start slim // Start slim
$app = AppFactory::create(); $app = AppFactory::create();
// create middleware
$app->addRoutingMiddleware();
$ssConfig = new SameSiteCookieConfiguration(["same_site" => "strict"]);
// add in same site cookie stuff
$app->add(new SameSiteCookieMiddleware($ssConfig));
// for error checking
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
// set base path for all routes // set base path for all routes
$app->setBasePath("/api"); $app->setBasePath("/api");
// return all responses as JSON // Add middleware
/*$app->add(function($request, $handler) { new middleware($app);
$response = $handler->handle($request);
return $response->withHeader("Content-Type", "application/json");
});*/
$timelineData = new timelineData(); $timelineData = new timelineData();
$projectData = new projectData(); $projectData = new projectData();
@ -277,8 +267,9 @@ $app->post("/user/login", function (Request $request, Response $response)
if ($user->checkUser($data["username"], $data["password"])) if ($user->checkUser($data["username"], $data["password"]))
{ {
// yay, user is logged in // yay, user is logged in
$_SESSION["token"] = $user->createToken(); $_SESSION["token"] = $user->createToken($data["username"]);
$_SESSION["username"] = $data["username"]; $_SESSION["username"] = $data["username"];
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
return $response; return $response;
} }
return $response->withStatus(401); return $response->withStatus(401);
@ -297,7 +288,7 @@ $app->get("/user/isLoggedIn", function (Request $request, Response $response)
if (empty($_SESSION["token"])) if (empty($_SESSION["token"]))
{ {
// user is logged in but no token was created // user is logged in but no token was created
$_SESSION["token"] = $user->createToken(); $_SESSION["token"] = $user->createToken($_SESSION["username"]);
return $response; return $response;
} }
@ -319,8 +310,7 @@ $app->get("/user/checkResetEmail/{email}", function (Request $request, Response
if ($user->checkEmail($args["email"])) if ($user->checkEmail($args["email"]))
{ {
// yay email does exist // yay email does exist
$token = $user->sendResetEmail($args["email"]); $_SESSION["resetToken"] = $user->sendResetEmail($args["email"]);
$_SESSION["resetToken"] = $token;
$_SESSION["resetEmail"] = $args["email"]; $_SESSION["resetEmail"] = $args["email"];
return $response; return $response;
} }
@ -335,7 +325,7 @@ $app->get("/user/resendEmail", function (Request $request, Response $response)
return $response->withStatus(401); return $response->withStatus(401);
} }
global $user; global $user;
$user->sendResetEmail($_SESSION["resetEmail"]); $_SESSION["resetToken"] = $user->sendResetEmail($_SESSION["resetEmail"]);
return $response; return $response;
}); });
@ -383,4 +373,10 @@ $app->post("/user/changePassword", function (Request $request, Response $respons
return $response->withStatus(500); return $response->withStatus(500);
}); });
$app->post("/projectData", function (Request $request, Response $response)
{
$response->getBody()->write(json_encode(array("test" => "test")));
return $response;
});
$app->run(); $app->run();

91
dist/api/middleware.php vendored Normal file
View File

@ -0,0 +1,91 @@
<?php
// middleware
namespace api;
use Slim\App;
use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Tuupola\Middleware\JwtAuthentication;
use Tuupola\Middleware\JwtAuthentication\RequestMethodRule;
use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
/**
* Middleware
* Define all middleware functions
*/
class middleware
{
/**
* Constructor for middleware
* @param App $app - Slim App
*/
function __construct(App $app)
{
$this->baseMiddleware($app);
$this->sameSiteConfig($app);
$this->jwtAuth($app);
$this->returnAsJSON($app);
}
/**
* Base middleware
* @param App $app - Slim App
*/
function baseMiddleware(App $app): void
{
$app->addRoutingMiddleware();
}
/**
* SameSite Cookie Configuration
* @param App $app - Slim App
*/
function sameSiteConfig(App $app): void
{
$ssConfig = new SameSiteCookieConfiguration(["same_site" => "strict"]);
$app->add(new SameSiteCookieMiddleware($ssConfig));
}
/**
* Return all responses as JSON
* @param App $app - Slim App
*/
function returnAsJSON(App $app): void
{
$app->add(function ($request, $handler)
{
$response = $handler->handle($request);
return $response->withHeader("Content-Type", "application/json");
});
}
/**
* JWT Authentication
* @param App $app - Slim App
*/
function jwtAuth(App $app): void
{
$jwtSecret = getSecretKey();
$app->add(new JwtAuthentication([
"rules" => [
new RequestPathRule([
"path" => ["/api/projectData", "/api/timeline/[a-z]*", "/api/user/testMethod"],
"ignore" => ["/api/contact", "/api/user/login", "/api/user/changePassword"]
]),
new RequestMethodRule([
"ignore" => ["OPTIONS", "GET"]
])
],
"secret" => $jwtSecret,
"error" => function ($response)
{
session_destroy();
$response->getBody()->write(json_encode(array("status" => "401", "message" =>
"Unauthorized, please provide a valid token")));
return $response->withStatus(401);
}
]));
$app->addErrorMiddleware(true, true, true);
}
}

View File

@ -10,6 +10,10 @@ require_once "./config.php";
*/ */
class projectData class projectData
{ {
/**
* Get all project data
* @return array - Array of all project data or error message
*/
function getProjectData(): array function getProjectData(): array
{ {
$conn = dbConn(); $conn = dbConn();

View File

@ -10,6 +10,10 @@ require_once "./config.php";
*/ */
class timelineData class timelineData
{ {
/**
* Get all education data
* @return array - Array of all education data or error message
*/
function getEduData(): array function getEduData(): array
{ {
$conn = dbConn(); $conn = dbConn();
@ -26,6 +30,10 @@ class timelineData
return array("errorMessage" => "Error, edu data not found"); return array("errorMessage" => "Error, edu data not found");
} }
/**
* Get all work data
* @return array - Array of all work data or error message
*/
function getWorkData(): array function getWorkData(): array
{ {
$conn = dbConn(); $conn = dbConn();

53
dist/api/user.php vendored
View File

@ -1,5 +1,6 @@
<?php <?php
namespace api; namespace api;
use Firebase\JWT\JWT;
use PDO; use PDO;
require_once "./config.php"; require_once "./config.php";
@ -10,7 +11,13 @@ require_once "./config.php";
*/ */
class user class user
{ {
function checkUser($username, $password): bool /**
* Check if user exists and can be logged in
* @param $username string - Username
* @param $password string - Password
* @return bool - True if logged in, false if not
*/
function checkUser(string $username, string $password): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username"); $stmt = $conn->prepare("SELECT * FROM users WHERE username = :username");
@ -31,12 +38,31 @@ class user
return false; return false;
} }
function createToken(): string /**
* Create a JWT token
* @param $username string - Username
* @return string - JWT token
*/
function createToken(string $username): string
{ {
return uniqid("rpe-"); $now = time();
$future = strtotime('+6 hour',$now);
$secretKey = getSecretKey();
$payload = [
"jti"=>$username,
"iat"=>$now,
"exp"=>$future
];
return JWT::encode($payload,$secretKey,"HS256");
} }
function checkEmail($email): bool /**
* Check if email is already in use
* @param string $email - Email to check
* @return bool - True if email exists, false if not
*/
function checkEmail(string $email): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE email = :email"); $stmt = $conn->prepare("SELECT * FROM users WHERE email = :email");
@ -52,11 +78,16 @@ class user
} }
return false; return false;
} }
/**
* Send a verification email to the user
* @param $email - email address of the user
* @return string - verification code
*/
function sendResetEmail($email): string function sendResetEmail($email): string
{ {
//generate a random token and email the address //generate a random token and email the address
$token = $this->createToken(); $token = uniqid("rpe-");
$headers1 = "From: noreply@rohitpai.co.uk\r\n"; $headers1 = "From: noreply@rohitpai.co.uk\r\n";
$headers1 .= "MIME-Version: 1.0\r\n"; $headers1 .= "MIME-Version: 1.0\r\n";
$headers1 .= "Content-Type: text/html; charset=UTF-8\r\n"; $headers1 .= "Content-Type: text/html; charset=UTF-8\r\n";
@ -82,7 +113,13 @@ class user
return $token; return $token;
} }
function changePassword($email, $password): bool /**
* Change password for an email with new password
* @param $email string Email
* @param $password string Password
* @return bool - true if the password was changed, false if not
*/
function changePassword(string $email, string $password): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email"); $stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email");
@ -96,4 +133,6 @@ class user
} }
return false; return false;
} }
} }

View File

@ -1,4 +1,4 @@
<?php <?php /** @noinspection PhpIncludeInspection */
session_start(); session_start();
////////////////// Index file ////////////// ////////////////// Index file //////////////
@ -7,40 +7,30 @@ session_start();
//////////////////////////////////////////// ////////////////////////////////////////////
//require “routes.php”; //require “routes.php”;
require "../vendor/autoload.php"; require "../vendor/autoload.php";
include "middleware.php";
include "timelineData.php"; include "timelineData.php";
include "projectData.php"; include "projectData.php";
include "user.php"; include "user.php";
use api\middleware;
use api\projectData; use api\projectData;
use api\timelineData; use api\timelineData;
use api\user; use api\user;
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use Selective\SameSiteCookie\SameSiteCookieConfiguration; use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Slim\Factory\AppFactory;
use Selective\SameSiteCookie\SameSiteCookieMiddleware; use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Slim\Handlers\Strategies\RequestHandler; use Slim\Factory\AppFactory;
use Tuupola\Middleware\JwtAuthentication;
// Start slim // Start slim
$app = AppFactory::create(); $app = AppFactory::create();
// create middleware
$app->addRoutingMiddleware();
$ssConfig = new SameSiteCookieConfiguration(["same_site" => "strict"]);
// add in same site cookie stuff
$app->add(new SameSiteCookieMiddleware($ssConfig));
// for error checking
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
// set base path for all routes // set base path for all routes
$app->setBasePath("/api"); $app->setBasePath("/api");
// return all responses as JSON // Add middleware
/*$app->add(function($request, $handler) { new middleware($app);
$response = $handler->handle($request);
return $response->withHeader("Content-Type", "application/json");
});*/
$timelineData = new timelineData(); $timelineData = new timelineData();
$projectData = new projectData(); $projectData = new projectData();
@ -277,8 +267,9 @@ $app->post("/user/login", function (Request $request, Response $response)
if ($user->checkUser($data["username"], $data["password"])) if ($user->checkUser($data["username"], $data["password"]))
{ {
// yay, user is logged in // yay, user is logged in
$_SESSION["token"] = $user->createToken(); $_SESSION["token"] = $user->createToken($data["username"]);
$_SESSION["username"] = $data["username"]; $_SESSION["username"] = $data["username"];
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
return $response; return $response;
} }
return $response->withStatus(401); return $response->withStatus(401);
@ -297,7 +288,7 @@ $app->get("/user/isLoggedIn", function (Request $request, Response $response)
if (empty($_SESSION["token"])) if (empty($_SESSION["token"]))
{ {
// user is logged in but no token was created // user is logged in but no token was created
$_SESSION["token"] = $user->createToken(); $_SESSION["token"] = $user->createToken($_SESSION["username"]);
return $response; return $response;
} }
@ -319,8 +310,7 @@ $app->get("/user/checkResetEmail/{email}", function (Request $request, Response
if ($user->checkEmail($args["email"])) if ($user->checkEmail($args["email"]))
{ {
// yay email does exist // yay email does exist
$token = $user->sendResetEmail($args["email"]); $_SESSION["resetToken"] = $user->sendResetEmail($args["email"]);
$_SESSION["resetToken"] = $token;
$_SESSION["resetEmail"] = $args["email"]; $_SESSION["resetEmail"] = $args["email"];
return $response; return $response;
} }
@ -335,7 +325,7 @@ $app->get("/user/resendEmail", function (Request $request, Response $response)
return $response->withStatus(401); return $response->withStatus(401);
} }
global $user; global $user;
$user->sendResetEmail($_SESSION["resetEmail"]); $_SESSION["resetToken"] = $user->sendResetEmail($_SESSION["resetEmail"]);
return $response; return $response;
}); });
@ -383,4 +373,10 @@ $app->post("/user/changePassword", function (Request $request, Response $respons
return $response->withStatus(500); return $response->withStatus(500);
}); });
$app->post("/projectData", function (Request $request, Response $response)
{
$response->getBody()->write(json_encode(array("test" => "test")));
return $response;
});
$app->run(); $app->run();

91
src/api/middleware.php Normal file
View File

@ -0,0 +1,91 @@
<?php
// middleware
namespace api;
use Slim\App;
use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Tuupola\Middleware\JwtAuthentication;
use Tuupola\Middleware\JwtAuthentication\RequestMethodRule;
use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
/**
* Middleware
* Define all middleware functions
*/
class middleware
{
/**
* Constructor for middleware
* @param App $app - Slim App
*/
function __construct(App $app)
{
$this->baseMiddleware($app);
$this->sameSiteConfig($app);
$this->jwtAuth($app);
$this->returnAsJSON($app);
}
/**
* Base middleware
* @param App $app - Slim App
*/
function baseMiddleware(App $app): void
{
$app->addRoutingMiddleware();
}
/**
* SameSite Cookie Configuration
* @param App $app - Slim App
*/
function sameSiteConfig(App $app): void
{
$ssConfig = new SameSiteCookieConfiguration(["same_site" => "strict"]);
$app->add(new SameSiteCookieMiddleware($ssConfig));
}
/**
* Return all responses as JSON
* @param App $app - Slim App
*/
function returnAsJSON(App $app): void
{
$app->add(function ($request, $handler)
{
$response = $handler->handle($request);
return $response->withHeader("Content-Type", "application/json");
});
}
/**
* JWT Authentication
* @param App $app - Slim App
*/
function jwtAuth(App $app): void
{
$jwtSecret = getSecretKey();
$app->add(new JwtAuthentication([
"rules" => [
new RequestPathRule([
"path" => ["/api/projectData", "/api/timeline/[a-z]*", "/api/user/testMethod"],
"ignore" => ["/api/contact", "/api/user/login", "/api/user/changePassword"]
]),
new RequestMethodRule([
"ignore" => ["OPTIONS", "GET"]
])
],
"secret" => $jwtSecret,
"error" => function ($response)
{
session_destroy();
$response->getBody()->write(json_encode(array("status" => "401", "message" =>
"Unauthorized, please provide a valid token")));
return $response->withStatus(401);
}
]));
$app->addErrorMiddleware(true, true, true);
}
}

View File

@ -10,6 +10,10 @@ require_once "./config.php";
*/ */
class projectData class projectData
{ {
/**
* Get all project data
* @return array - Array of all project data or error message
*/
function getProjectData(): array function getProjectData(): array
{ {
$conn = dbConn(); $conn = dbConn();

View File

@ -10,6 +10,10 @@ require_once "./config.php";
*/ */
class timelineData class timelineData
{ {
/**
* Get all education data
* @return array - Array of all education data or error message
*/
function getEduData(): array function getEduData(): array
{ {
$conn = dbConn(); $conn = dbConn();
@ -26,6 +30,10 @@ class timelineData
return array("errorMessage" => "Error, edu data not found"); return array("errorMessage" => "Error, edu data not found");
} }
/**
* Get all work data
* @return array - Array of all work data or error message
*/
function getWorkData(): array function getWorkData(): array
{ {
$conn = dbConn(); $conn = dbConn();

View File

@ -1,5 +1,6 @@
<?php <?php
namespace api; namespace api;
use Firebase\JWT\JWT;
use PDO; use PDO;
require_once "./config.php"; require_once "./config.php";
@ -10,7 +11,13 @@ require_once "./config.php";
*/ */
class user class user
{ {
function checkUser($username, $password): bool /**
* Check if user exists and can be logged in
* @param $username string - Username
* @param $password string - Password
* @return bool - True if logged in, false if not
*/
function checkUser(string $username, string $password): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username"); $stmt = $conn->prepare("SELECT * FROM users WHERE username = :username");
@ -31,12 +38,31 @@ class user
return false; return false;
} }
function createToken(): string /**
* Create a JWT token
* @param $username string - Username
* @return string - JWT token
*/
function createToken(string $username): string
{ {
return uniqid("rpe-"); $now = time();
$future = strtotime('+6 hour',$now);
$secretKey = getSecretKey();
$payload = [
"jti"=>$username,
"iat"=>$now,
"exp"=>$future
];
return JWT::encode($payload,$secretKey,"HS256");
} }
function checkEmail($email): bool /**
* Check if email is already in use
* @param string $email - Email to check
* @return bool - True if email exists, false if not
*/
function checkEmail(string $email): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM users WHERE email = :email"); $stmt = $conn->prepare("SELECT * FROM users WHERE email = :email");
@ -52,11 +78,16 @@ class user
} }
return false; return false;
} }
/**
* Send a verification email to the user
* @param $email - email address of the user
* @return string - verification code
*/
function sendResetEmail($email): string function sendResetEmail($email): string
{ {
//generate a random token and email the address //generate a random token and email the address
$token = $this->createToken(); $token = uniqid("rpe-");
$headers1 = "From: noreply@rohitpai.co.uk\r\n"; $headers1 = "From: noreply@rohitpai.co.uk\r\n";
$headers1 .= "MIME-Version: 1.0\r\n"; $headers1 .= "MIME-Version: 1.0\r\n";
$headers1 .= "Content-Type: text/html; charset=UTF-8\r\n"; $headers1 .= "Content-Type: text/html; charset=UTF-8\r\n";
@ -82,7 +113,13 @@ class user
return $token; return $token;
} }
function changePassword($email, $password): bool /**
* Change password for an email with new password
* @param $email string Email
* @param $password string Password
* @return bool - true if the password was changed, false if not
*/
function changePassword(string $email, string $password): bool
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email"); $stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email");
@ -96,4 +133,6 @@ class user
} }
return false; return false;
} }
} }