Merge pull request 'jwt tokens + user gateway' (#1) from api_skeletton into master

Reviewed-on: #1
pull/4/head
remrem 1 year ago
commit 799a39b678

@ -0,0 +1,29 @@
<?php
namespace Config;
use PDO;
use PDOStatement;
class Connection extends PDO{
private PDOStatement $stmt;
public function __construct(string $dsn, string $username, string $password)
{
parent::__construct($dsn, $username, $password);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function executeQuery(string $query, array $parameters = []): bool
{
$this->stmt = parent::prepare($query);
foreach ($parameters as $name => $value) {
$this->stmt->bindValue($name, $value[0], $value[1]);
}
return $this->stmt->execute();
}
public function getResults(): array
{
return $this->stmt->fetchAll();
}
}

@ -0,0 +1,28 @@
<?php
namespace Config;
use PDOException;
require_once __DIR__ ."/connection.php";
class DatabaseCon{
private string $dsn;
private string $login;
private string $password;
function __construct(){
if (getenv("SMDB_HOST") == null || getenv("SMDB_DATABASE") == null || getenv("SMDB_USER") == null || getenv("SMDB_PASSWORD") == null){
throw new PDOException("ENV variables not found");
}
$this->dsn = "mysql:host=".getenv("SMDB_HOST").";dbname=".getenv("SMDB_DATABASE").";charset=UTF8";
$this->login = getenv("SMDB_USER");
$this->password = getenv("SMDB_PASSWORD");
}
function connect(): int|Connection {
try {
$connection = new Connection($this->dsn,$this->login,$this->password);
} catch (PDOException $e){
throw new PDOException($e->getMessage(), $e->getCode(), $e);
}
return $connection;
}
}

@ -0,0 +1,84 @@
<?php
namespace Gateway;
use Config\DatabaseCon;
use Config\Connection;
use PDOException;
use PDO;
use Config\Token;
class UserGateway {
private Connection $con;
private Token $token;
public function __construct() {
$this->token = new Token;
try {
$this->con = (new DatabaseCon)->connect();
} catch(PDOException $e) {
throw new PDOException($e->getMessage(), $e->getCode(), $e);
}
}
public function createUser(string $mail, string $hash, string $username) {
$query = "INSERT INTO user VALUES(UUID(), :mail, :hash, :username, CURDATE());";
$this->con->executeQuery($query, array(
':mail' => array($mail, PDO::PARAM_STR),
':hash' => array($hash, PDO::PARAM_STR),
':username' => array($username, PDO::PARAM_STR)
));
$query = "SELECT id FROM user WHERE email=:mail;";
$this->con->executeQuery($query, array(
':mail' => array($mail, PDO::PARAM_STR)
));
$results = $this->con->getResults();
return $this->token->getNewJsonToken($results[0]['id']);
}
// Delete User: (1:OK, 2:Unauthorize, 3:No User)
public function deleteUser(string $uuid) : int {
$query = "DELETE FROM user WHERE id=:uuid;";
$this->con->executeQuery($query, array(
':uuid' => array($uuid, PDO::PARAM_STR)
));
return 0;
}
// Login User (get token)
public function login(string $mail, string $hash) {
$query = "SELECT hash, id FROM user WHERE email=:mail;";
$this->con->executeQuery($query, array(
':mail' => array($mail, PDO::PARAM_STR)
));
$results = $this->con->getResults();
if(empty($results)) {
// Not Found
return 404;
}
if($hash !== (string) $results[0]['hash']) {
// Unauthorized
return 401;
}
return json_encode($this->token->getNewJsonToken($results[0]['id']));
}
public function updateMail(string $uuid, string $new_mail) {
$query = "UPDATE user SET email=:new_mail WHERE id=:uuid;";
$this->con->executeQuery($query, array(
':new_mail' => array($new_mail, PDO::PARAM_STR),
':uuid' => array($uuid, PDO::PARAM_STR)
));
}
public function updateUsername(string $uuid, string $new_username) {
$query = "UPDATE user SET username=:new_username WHERE id=:uuid;";
$this->con->executeQuery($query, array(
':new_username' => array($new_username, PDO::PARAM_STR),
':uuid' => array($uuid, PDO::PARAM_STR)
));
}
}

@ -1,10 +1,14 @@
<?php
declare(strict_types=1);
require "gateway/user_gateway.php";
require "database_con.php";
require "token.php";
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App;
use gateway\UserGateway;
use Config\Token;
return function (App $app) {
@ -16,43 +20,66 @@ return function (App $app) {
#### ACCOUNT ####
// Create User
$app->post('/user', function (Request $req, Response $res) {
$res->getBody()->write('/user');
$req_body = $req->getParsedBody();
$res->getBody()->write(json_encode((new UserGateway)->createUser($req_body['mail'], $req_body['password'], $req_body['user'])));
return $res;
});
// Delete User
$app->delete('/user', function (Request $req, Response $res) {
$token = $req->getHeader('Authorization')[0];
$res->getBody()->write('/user/' . $token);
return $res;
$uuid = (new Token)->getUuidFromToken($token);
$code = (new UserGateway)->deleteUser($uuid);
switch($code) {
case 0:
return $res->withStatus(200);
case -1:
return $res->withStatus(401);
case -2:
return $res->withStatus(404);
}
return $res->withStatus(500);
});
// Get Token
$app->get('/user/{uuid}/{hash}/token', function (Request $req, Response $res, $args) {
$uuid = $args['uuid'];
$app->get('/user/login/{mail}/{hash}', function (Request $req, Response $res, $args) {
$mail = $args['mail'];
$hash = $args['hash'];
$res->getBody()->write('/user/' . $uuid . '/' . $hash);
$value = (new UserGateway)->login($mail, $hash);
// If error statusCode else token
if($value instanceOf int) {
return $res->withStatus($value);
}
$res->getBody()->write($value);
return $res;
});
// Update Mail
$app->put('/user/mail', function(Request $req, Response $res) {
$token = $req->getHeader('Authorization')[0];
$mail = $req->getParsedBody()['mail'];
$res->getBody()->write('/user/mail mail:'.$mail.' Auth:'.$token);
return $res;
$new_mail = $req->getParsedBody()['mail'];
if(!(new Token)->verifyToken($token)) {
return $res->withStatus(401);
}
$uuid = (new Token)->getUuidFromToken($token);
(new UserGateway)->updateMail($uuid, $new_mail);
return $res->withStatus(200);
});
// Update Username
$app->put('/user/username', function(Request $req, Response $res) {
$token = $req->getHeader('Authorization')[0];
$username = $req->getParsedBody()['username'];
$res->getBody()->write('/user/username username:'.$username.' Auth:'.$token);
return $res;
$new_username = $req->getParsedBody()['username'];
if(!(new Token)->verifyToken($token)) {
return $res->withStatus(401);
}
$uuid = (new Token)->getUuidFromToken($token);
(new UserGateway)->updateUsername($uuid, $new_username);
return $res->withStatus(200);
});
#### FILES ####
@ -89,5 +116,4 @@ return function (App $app) {
$res->getBody()->write('/user/files'.' Auth:'.$token);
return $res;
});
};

@ -0,0 +1,46 @@
<?php
namespace Config;
use Exception;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class Token {
private string $key = 'passwd';
// Need to be in a config file
private string $path_to_key="../sym_keyfile.key";
function __construct()
{
#$file = fopen($this->path_to_key, 'r');
#$this->key = fread($file, filesize($this->path_to_key));
#fclose($file);
}
// Return json containing JWT with uuid and exp
function getNewJsonToken(string $uuid) :array {
$payload = [
'uuid' => $uuid,
'exp' => strtotime("+2month", time())
];
return ["token" => JWT::encode($payload, $this->key, 'HS256')];
}
// Verify the JWT authenticity
function verifyToken(string $jwt) :bool {
try {
JWT::decode($jwt, new Key($this->key, 'HS256'));
} catch (Exception $e) {
return false;
}
return true;
}
// Get uuid from JWT
// Missing error handling on bad JWT
function getUuidFromToken(string $jwt) :string {
$decoded = (array) JWT::decode($jwt, new Key($this->key, 'HS256'));
return $decoded['uuid'];
}
}

@ -24,6 +24,7 @@
"require": {
"php": "^7.4 || ^8.0",
"ext-json": "*",
"firebase/php-jwt": "^6.9",
"monolog/monolog": "^2.8",
"php-di/php-di": "^6.4",
"slim/psr7": "^1.5",

65
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "62d60de4b802ec31b840b9197e947981",
"content-hash": "3fbd2a92a15c13f23e25e12b030b51e6",
"packages": [
{
"name": "fig/http-message-util",
@ -62,6 +62,69 @@
},
"time": "2020-11-24T22:02:12+00:00"
},
{
"name": "firebase/php-jwt",
"version": "v6.9.0",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
"reference": "f03270e63eaccf3019ef0f32849c497385774e11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/f03270e63eaccf3019ef0f32849c497385774e11",
"reference": "f03270e63eaccf3019ef0f32849c497385774e11",
"shasum": ""
},
"require": {
"php": "^7.4||^8.0"
},
"require-dev": {
"guzzlehttp/guzzle": "^6.5||^7.4",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"psr/cache": "^1.0||^2.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0"
},
"suggest": {
"ext-sodium": "Support EdDSA (Ed25519) signatures",
"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/v6.9.0"
},
"time": "2023-10-05T00:24:42+00:00"
},
{
"name": "laravel/serializable-closure",
"version": "v1.3.2",

Loading…
Cancel
Save