Commit f1160afe authored by raphael.peim's avatar raphael.peim

From Bootstrap to BootstrapVue

parent 822c69cf
<ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.php">
<div class="sidebar-brand-icon rotate-n-15">
......
This diff is collapsed.
......@@ -8,9 +8,10 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"bcrypt": "^5.0.0",
"bootstrap": "^4.5.3",
"bootstrap-vue": "^2.19.0",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue": "^2.6.12",
"vue-router": "^3.2.0"
},
"devDependencies": {
......
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
div #app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
<?php
$rootDirectoryPath = realpath(dirname(__FILE__));
define ('__ROOT_DIR', $rootDirectoryPath );
require_once(__ROOT_DIR . "/config/config.php");
require_once(__ROOT_DIR . '/classes/AutoLoader.class.php');
$request = Request::getCurrentRequest();
Response::interceptEchos();
try {
$controller = Dispatcher::dispatch($request);
$response = $controller->execute();
} catch (Exception $e) {
$log = Response::getEchos();
$log .= " " . $e->getMessage();
$response = Response::errorResponse($log);
}
$response->send();
?>
\ No newline at end of file
<?php
class AutoLoader {
public function __construct() {
spl_autoload_register( array($this, 'load') );
// spl_autoload_register(array($this, 'loadComplete'));
}
// This method will be automatically executed by PHP whenever it encounters an unknown class name in the source code
private function load($className) {
$paths = array('/classes/', '/controller/', '/model/', '/sql/');
$fileToLoad = null;
$i = 0;
do {
$fileToLoad = __ROOT_DIR . $paths[$i] . ucfirst($className) . '.class.php';
$i++;
} while(!is_readable($fileToLoad) && $i < count($paths));
if (!is_readable($fileToLoad))
throw new Exception('Unknown class ' . $className);
require_once($fileToLoad);
if (strlen(strstr($fileToLoad, '/model/')) > 0) {
$fileToLoadSql = __ROOT_DIR . '/sql/' . ucfirst($className) . '.sql.php';
if (is_readable($fileToLoadSql)) {
require_once($fileToLoadSql);
}
}
}
}
$__LOADER = new AutoLoader();
?>
\ No newline at end of file
<?php
class DatabasePDO extends PDO {
protected static $singleton = NULL;
public static function singleton(){
if(is_null(static::$singleton))
static::$singleton = new static();
return static::$singleton;
}
public function __construct() {
$connectionString = "mysql:host=". DB_HOST;
if(defined('DB_PORT'))
$connectionString .= ";port=". DB_PORT;
$connectionString .= ";dbname=" . DB_DATABASE;
$connectionString .= ";charset=utf8";
parent::__construct($connectionString, DB_USERNAME, DB_PASSWORD);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
}
?>
\ No newline at end of file
<?php
/*
* Analyses a request, created the right Controller passing it the request
*/
class Dispatcher {
public static function dispatch($request) {
return static::dispatchToController($request->getControllerName(), $request);
}
public static function dispatchToController($controllerName, $request) {
$controllerClassName = ucfirst($controllerName) . 'Controller';
if (!class_exists($controllerName))
throw new Exception("$controllerName does not exist");
return new $controllerClassName($controllerName, $request);
}
}
?>
\ No newline at end of file
<?php
class Request {
protected $controllerName;
protected $uriParameters;
protected static $singleton = NULL;
public function __construct() {
$this->jsonReceived = null;
$this->initBaseURI();
$this->initControllerAndParametersFromURI();
}
public static function getCurrentRequest() {
if (is_null(static::$singleton))
static::$singleton = new static();
return static::$singleton;
}
public function jsonContent() {
if(is_null($this->jsonReceived))
$this->jsonReceived = json_decode(file_get_contents("php://input"));
return $this->jsonReceived;
}
protected function initBaseURI() {
$this->baseURI = explode('/api.php', $_SERVER['SCRIPT_NAME'])[0];
}
protected function initControllerAndParametersFromURI(){
$url = trim($_SERVER['PATH_INFO'], '/');
$urlSegments = explode('/', $url);
$scheme = ['controller', 'params'];
$route = [];
foreach ($urlSegments as $index => $segment){
if ($scheme[$index] == 'params'){
$route['params'] = array_slice($urlSegments, $index);
break;
} else {
$route[$scheme[$index]] = $segment;
}
}
$this->controllerName = $route['controller'] != "" ? $route['controller'] : "default";
$this->uriParameters = isset($route['params']) ? $route['params'] : [];
}
// ==============
// Public API
// ==============
public function getControllerName() {
return $this->controllerName;
}
public function getHttpMethod() {
return $_SERVER["REQUEST_METHOD"];
}
public function getUriParameters() {
return $this->uriParameters;
}
public function getJwtToken() {
$headers = getallheaders();
$autorization = $headers['Authorization'];
$arr = explode(" ", $autorization);
if (count($arr) < 2)
throw new Exception("Missing JWT token");
$jwt_token = $arr[1];
return $jwt_token;
}
}
?>
\ No newline at end of file
<?php
class Response {
protected $code;
protected $body;
public function __construct($code = 404, $msg = "") {
$this->code = $code;
$this->body = $msg;
}
public static function okResponse($message = "")
{
return new Response(200, $message);
}
public static function errorResponse($message = "") {
return new Response(400, $message);
}
public static function errorInParametersResponse($message = "")
{
return new Response(400, $message);
}
public static function unauthorizedResponse($message = "")
{
return new Response(401, $message);
}
public static function notFoundResponse($message = "")
{
return new Response(404, $message);
}
public static function serverErrorResponse($message = "")
{
return new Response(500, $message);
}
public static function interceptEchos() {
ob_start();
}
public static function getEchos() {
return ob_get_clean();
}
public function send() {
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
header("Access-Control-Allow-Methods: GET,POST,PUT,DELETE");
header("Access-Control-Max-Age: 3600"); // Maximum number of seconds the results can be cached.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
http_response_code($this->code);
echo $this->body;
exit; // do we keep that?
}
}
?>
\ No newline at end of file
<?php
// DB
define('DB_HOST', 'localhost');
define('DB_PORT', 8888);
define('DB_DATABASE', 'dbtest');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'root');
// JWT
define( 'JWT_BACKEND_KEY', '6d8HbcZndVGNAbo4Ih1TGaKcuA1y2BKs-I5CmP' );
define( 'JWT_ISSUER', $_SERVER['HTTP_HOST'] . $_SERVER['CONTEXT_PREFIX']);
// define('__DEBUG', false);
define('__DEBUG', true);
// ================================================================================
// Debug utilities
// ================================================================================
if(__DEBUG) {
error_reporting(E_ALL);
ini_set("display_errors", E_ALL);
} else {
error_reporting(0);
ini_set("display_errors", 0);
}
function myLog($msg) {
if(__DEBUG) {
echo $msg;
}
}
function myDump($var) {
if(__DEBUG) {
var_dump($var);
}
}
?>
\ No newline at end of file
<?php
/*
* A Controller is dedicated to process a request
* its responsabilities are:
* - analyses the action to be done
* - analyses the parameters
* - act on the model objects to perform the action
* - process the data
* - call the view and passes it the data
* - return the response
*/
abstract class Controller {
protected $name;
protected $request;
public function __construct($name, $request) {
$this->name = $name;
$this->request = $request;
}
public abstract function processRequest();
public function execute() {
$response = $this->processRequest();
if(empty($response)) {
// $response = Response::serverErrorResponse("error processing request in ". self::class); // Oh my PHP!
$response = Response::serverErrorResponse("error processing request in ". static::class);
}
return $response;
}
}
?>
\ No newline at end of file
<?php
class DefaultController extends Controller {
public function __construct($name, $request) {
parent::__construct($name, $request);
}
// ==============
// Actions
// ==============
public function processRequest() {
return Response::errorResponse('{ "message" : "Unsupported endpoint"}' );
}
}
?>
\ No newline at end of file
<?php
include_once __ROOT_DIR . '/libs/php-jwt/src/BeforeValidException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/ExpiredException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/SignatureInvalidException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/JWT.php';
use \Firebase\JWT\JWT;
class LoginController extends Controller {
public function __construct($name, $request) {
parent::__construct($name, $request);
}
public function processRequest() {
if($this->request->getHttpMethod() !== 'POST')
return Response::errorResponse('{ "message" : "Unsupported endpoint" }' );
$json = $this->request->jsonContent();
if(!isset($json->login) || !isset($json->pwd)) {
$r = new Response(422,"login and pwd fields are mandatory");
$r->send();
}
$user = User::getWithLogin($json->login);
// var_dump($user);
if(empty($user) || !hash_equals($json->pwd, $user->password)) {
$r = new Response(422,"wrong credentials");
$r->sendWithLog();
}
// generate json web token
$issued_at = time();
$expiration_time = $issued_at + (60 * 60); // valid for 1 hour
$token = array(
"iat" => $issued_at,
"exp" => $expiration_time,
"iss" => JWT_ISSUER,
"data" => array(
"id" => $user->id,
"firstname" => $user->firstname,
"lastname" => $user->lastname,
"email" => $user->email
)
);
$jwt = JWT::encode( $token, JWT_BACKEND_KEY );
$jsonResult = json_encode(array("jwt_token" => $jwt));
return Response::okResponse($jsonResult);
}
}
?>
\ No newline at end of file
<?php
include_once __ROOT_DIR . '/libs/php-jwt/src/BeforeValidException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/ExpiredException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/SignatureInvalidException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/JWT.php';
use \Firebase\JWT\JWT;
class UserController extends Controller {
public function __construct($name, $request) {
parent::__construct($name, $request);
}
// ==============
// Actions
// ==============
public function processRequest() {
switch ($this->request->getHttpMethod()) {
case 'POST':
$post = json_decode(file_get_contents("php://input"));
return $this->createUser($post);
break;
case 'GET':
if (empty($this->request->getUriParameters()))
return $this->getAllUsers();
else
return $this->getUserById($this->request->getUriParameters()[0]);
break;
case 'PUT':
$put = json_decode(file_get_contents("php://input"));
$id = $this->request->getUriParameters()[0];
return $this->updateUser($put, $id);
break;
case 'DELETE':
$id = $this->request->getUriParameters()[0];
return $this->deleteUser($id);
break;
}
return Response::errorResponse("unsupported parameters or method in users");
}
protected function createUser($post) {
if (isset($post->firstname)
&& isset($post->lastname)
&& isset($post->login)
&& isset($post->email)
&& isset($post->password)
&& isset($post->role)) {
User::create($post);
$response = Response::okResponse("Utilisateur ajouté");
}
else {
// $response = Response::notFoundResponse("Aucun utilisateur ajouté");
$response = Response::notFoundResponse(var_dump($post));
}
return $response;
}
protected function getAllUsers() {
$users = User::getList();
if (!empty($users))
$response = Response::okResponse(json_encode($users));
else
$response = Response::notFoundResponse("Aucune réponse");
return $response;
}
protected function getUserById($id) {
$user = User::getWithId($id);
if (!empty($user))
$response = Response::okResponse(json_encode($user));
else
$response = Response::notFoundResponse("Aucune réponse");
return $response;
}
protected function updateUser($put, $id) {
$user = User::getWithId($id);
if (!empty($put) && !empty($user)) {
$jwt_token = $this->request->getJwtToken();
$jwt = JWT::decode($jwt_token, JWT_BACKEND_KEY, array('HS256'));
if ($jwt->data->id == $id) {
User::update($put, $id);
$response = Response::okResponse("Utilisateur modifié");
return $response;
}
else {
return Response::unauthorizedResponse("Modification non autorisée");
}
}
else {
return Response::notFoundResponse("Aucun utilisateur modifié");
}
}
protected function deleteUser($id) {
$user = User::getWithId($id);
if (!empty($user)) {
User::delete($id);
$response = Response::okResponse("Utilisateur supprimé");
}
else {
$response = Response::notFoundResponse("Aucun utilisateur supprimé");
}
return $response;
}
}
?>
\ No newline at end of file
<?php
include_once __ROOT_DIR . '/libs/php-jwt/src/BeforeValidException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/ExpiredException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/SignatureInvalidException.php';
include_once __ROOT_DIR . '/libs/php-jwt/src/JWT.php';
use \Firebase\JWT\JWT;
class ValidatetokenController extends Controller {
public function __construct($name, $request) {
parent::__construct($name, $request);
}
public function processRequest() {
try {
$jwt_token = $this->request->getJwtToken();
// echo "jwt = $jwt_token";
$decodedJWT = JWT::decode($jwt_token, JWT_BACKEND_KEY, array('HS256'));
$jsonResult = json_encode(array(
"message" => "Access granted.",
"data" => $decodedJWT
));
}
catch (Exception $e){
header('WWW-Authenticate: Bearer realm="' . JWT_ISSUER . '"');
$jsonResult = json_encode(array(
"message" => "Access denied.",
"error" => $e->getMessage()
));
return Response::unauthorizedResponse($jsonResult);
}
$response = Response::okResponse($jsonResult);
return $response;
}
}
?>
\ No newline at end of file
<?php
phpinfo();
?>
\ No newline at end of file
Copyright (c) 2011, Neuman Vong
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Neuman Vong nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[![Build Status](https://travis-ci.org/firebase/php-jwt.png?branch=master)](https://travis-ci.org/firebase/php-jwt)
[![Latest Stable Version](https://poser.pugx.org/firebase/php-jwt/v/stable)](https://packagist.org/packages/firebase/php-jwt)
[![Total Downloads](https://poser.pugx.org/firebase/php-jwt/downloads)](https://packagist.org/packages/firebase/php-jwt)
[![License](https://poser.pugx.org/firebase/php-jwt/license)](https://packagist.org/packages/firebase/php-jwt)
PHP-JWT
=======
A simple library to encode and decode JSON Web Tokens (JWT) in PHP, conforming to [RFC 7519](https://tools.ietf.org/html/rfc7519).
Installation
------------
Use composer to manage your dependencies and download PHP-JWT:
```bash
composer require firebase/php-jwt
```
Example
-------
```php
<?php
use \Firebase\JWT\JWT;
$key = "example_key";
$payload = array(
"iss" => "http://example.org",
"aud" => "http://example.com",
"iat" => 1356999524,
"nbf" => 1357000000
);
/**
* IMPORTANT:
* You must specify supported algorithms for your application. See
* https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40
* for a list of spec-compliant algorithms.
*/
$jwt = JWT::encode($payload, $key);
$decoded = JWT::decode($jwt, $key, array('HS256'));
print_r($decoded);
/*
NOTE: This will now be an object instead of an associative array. To get
an associative array, you will need to cast it as such:
*/
$decoded_array = (array) $decoded;
/**
* You can add a leeway to account for when there is a clock skew times between
* the signing and verifying servers. It is recommended that this leeway should
* not be bigger than a few minutes.
*
* Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef
*/
JWT::$leeway = 60; // $leeway in seconds
$decoded = JWT::decode($jwt, $key, array('HS256'));
?>
```
Example with RS256 (openssl)
----------------------------
```php
<?php
use \Firebase\JWT\JWT;
$privateKey = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC8kGa1pSjbSYZVebtTRBLxBz5H4i2p/llLCrEeQhta5kaQu/Rn
vuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t0tyazyZ8JXw+KgXTxldMPEL9
5+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4ehde/zUxo6UvS7UrBQIDAQAB
AoGAb/MXV46XxCFRxNuB8LyAtmLDgi/xRnTAlMHjSACddwkyKem8//8eZtw9fzxz
bWZ/1/doQOuHBGYZU8aDzzj59FZ78dyzNFoF91hbvZKkg+6wGyd/LrGVEB+Xre0J
Nil0GReM2AHDNZUYRv+HYJPIOrB0CRczLQsgFJ8K6aAD6F0CQQDzbpjYdx10qgK1
cP59UHiHjPZYC0loEsk7s+hUmT3QHerAQJMZWC11Qrn2N+ybwwNblDKv+s5qgMQ5
5tNoQ9IfAkEAxkyffU6ythpg/H0Ixe1I2rd0GbF05biIzO/i77Det3n4YsJVlDck
ZkcvY3SK2iRIL4c9yY6hlIhs+K9wXTtGWwJBAO9Dskl48mO7woPR9uD22jDpNSwe
k90OMepTjzSvlhjbfuPN1IdhqvSJTDychRwn1kIJ7LQZgQ8fVz9OCFZ/6qMCQGOb
qaGwHmUK6xzpUbbacnYrIM6nLSkXgOAwv7XXCojvY614ILTK3iXiLBOxPu5Eu13k
eUz9sHyD6vkgZzjtxXECQAkp4Xerf5TGfQXGXhxIX52yH+N2LtujCdkQZjXAsGdm
B2zNzvrlgRmgBrklMTrMYgm1NPcW+bRLGcwgW2PTvNM=
-----END RSA PRIVATE KEY-----
EOD;
$publicKey = <<<EOD
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8kGa1pSjbSYZVebtTRBLxBz5H
4i2p/llLCrEeQhta5kaQu/RnvuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t
0tyazyZ8JXw+KgXTxldMPEL95+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4
ehde/zUxo6UvS7UrBQIDAQAB
-----END PUBLIC KEY-----
EOD;
$payload = array(
"iss" => "example.org",
"aud" => "example.com",
"iat" => 1356999524,
"nbf" => 1357000000
);
$jwt = JWT::encode($payload, $privateKey, 'RS256');
echo "Encode:\n" . print_r($jwt, true) . "\n";
$decoded = JWT::decode($jwt, $publicKey, array('RS256'));
/*
NOTE: This will now be an object instead of an associative array. To get
an associative array, you will need to cast it as such:
*/
$decoded_array = (array) $decoded;
echo "Decode:\n" . print_r($decoded_array, true) . "\n";
?>
```
Using JWKs
----------
```php
// Set of keys. The "keys" key is required. For example, the JSON response to
// this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk
$jwks = ['keys' => []];
// JWK::parseKeySet($jwks) returns an associative array of **kid** to private
// key. Pass this as the second parameter to JWT::decode.
JWT::decode($payload, JWK::parseKeySet($jwks), $supportedAlgorithm);
```
Changelog
---------
#### 5.0.0 / 2017-06-26
- Support RS384 and RS512.
See [#117](https://github.com/firebase/php-jwt/pull/117). Thanks [@joostfaassen](https://github.com/joostfaassen)!
- Add an example for RS256 openssl.
See [#125](https://github.com/firebase/php-jwt/pull/125). Thanks [@akeeman](https://github.com/akeeman)!
- Detect invalid Base64 encoding in signature.
See [#162](https://github.com/firebase/php-jwt/pull/162). Thanks [@psignoret](https://github.com/psignoret)!
- Update `JWT::verify` to handle OpenSSL errors.
See [#159](https://github.com/firebase/php-jwt/pull/159). Thanks [@bshaffer](https://github.com/bshaffer)!
- Add `array` type hinting to `decode` method
See [#101](https://github.com/firebase/php-jwt/pull/101). Thanks [@hywak](https://github.com/hywak)!
- Add all JSON error types.
See [#110](https://github.com/firebase/php-jwt/pull/110). Thanks [@gbalduzzi](https://github.com/gbalduzzi)!
- Bugfix 'kid' not in given key list.
See [#129](https://github.com/firebase/php-jwt/pull/129). Thanks [@stampycode](https://github.com/stampycode)!
- Miscellaneous cleanup, documentation and test fixes.
See [#107](https://github.com/firebase/php-jwt/pull/107), [#115](https://github.com/firebase/php-jwt/pull/115),
[#160](https://github.com/firebase/php-jwt/pull/160), [#161](https://github.com/firebase/php-jwt/pull/161), and
[#165](https://github.com/firebase/php-jwt/pull/165). Thanks [@akeeman](https://github.com/akeeman),
[@chinedufn](https://github.com/chinedufn), and [@bshaffer](https://github.com/bshaffer)!
#### 4.0.0 / 2016-07-17
- Add support for late static binding. See [#88](https://github.com/firebase/php-jwt/pull/88) for details. Thanks to [@chappy84](https://github.com/chappy84)!
- Use static `$timestamp` instead of `time()` to improve unit testing. See [#93](https://github.com/firebase/php-jwt/pull/93) for details. Thanks to [@josephmcdermott](https://github.com/josephmcdermott)!
- Fixes to exceptions classes. See [#81](https://github.com/firebase/php-jwt/pull/81) for details. Thanks to [@Maks3w](https://github.com/Maks3w)!
- Fixes to PHPDoc. See [#76](https://github.com/firebase/php-jwt/pull/76) for details. Thanks to [@akeeman](https://github.com/akeeman)!
#### 3.0.0 / 2015-07-22
- Minimum PHP version updated from `5.2.0` to `5.3.0`.
- Add `\Firebase\JWT` namespace. See
[#59](https://github.com/firebase/php-jwt/pull/59) for details. Thanks to
[@Dashron](https://github.com/Dashron)!
- Require a non-empty key to decode and verify a JWT. See
[#60](https://github.com/firebase/php-jwt/pull/60) for details. Thanks to
[@sjones608](https://github.com/sjones608)!
- Cleaner documentation blocks in the code. See
[#62](https://github.com/firebase/php-jwt/pull/62) for details. Thanks to
[@johanderuijter](https://github.com/johanderuijter)!
#### 2.2.0 / 2015-06-22
- Add support for adding custom, optional JWT headers to `JWT::encode()`. See
[#53](https://github.com/firebase/php-jwt/pull/53/files) for details. Thanks to
[@mcocaro](https://github.com/mcocaro)!
#### 2.1.0 / 2015-05-20
- Add support for adding a leeway to `JWT:decode()` that accounts for clock skew
between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)!
- Add support for passing an object implementing the `ArrayAccess` interface for
`$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)!
#### 2.0.0 / 2015-04-01
- **Note**: It is strongly recommended that you update to > v2.0.0 to address
known security vulnerabilities in prior versions when both symmetric and
asymmetric keys are used together.
- Update signature for `JWT::decode(...)` to require an array of supported
algorithms to use when verifying token signatures.
Tests
-----
Run the tests using phpunit:
```bash
$ pear install PHPUnit
$ phpunit --configuration phpunit.xml.dist
PHPUnit 3.7.10 by Sebastian Bergmann.
.....
Time: 0 seconds, Memory: 2.50Mb
OK (5 tests, 5 assertions)
```
New Lines in private keys
-----
If your private key contains `\n` characters, be sure to wrap it in double quotes `""`
and not single quotes `''` in order to properly interpret the escaped characters.
License
-------
[3-Clause BSD](http://opensource.org/licenses/BSD-3-Clause).
{
"name": "firebase/php-jwt",
"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": [
"php",
"jwt"
],
"authors": [
{
"name": "Neuman Vong",
"email": "neuman+pear@twilio.com",
"role": "Developer"
},
{
"name": "Anant Narayanan",
"email": "anant@php.net",
"role": "Developer"
}
],
"license": "BSD-3-Clause",
"require": {
"php": ">=5.3.0"
},
"autoload": {
"psr-4": {
"Firebase\\JWT\\": "src"
}
},
"require-dev": {
"phpunit/phpunit": ">=4.8 <=9"
}
}
<?php
namespace Firebase\JWT;
class BeforeValidException extends \UnexpectedValueException
{
}
<?php
namespace Firebase\JWT;
class ExpiredException extends \UnexpectedValueException
{
}
<?php
namespace Firebase\JWT;
use DomainException;
use UnexpectedValueException;
/**
* JSON Web Key implementation, based on this spec:
* https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
*
* PHP version 5
*
* @category Authentication
* @package Authentication_JWT
* @author Bui Sy Nguyen <nguyenbs@gmail.com>
* @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
* @link https://github.com/firebase/php-jwt
*/
class JWK
{
/**
* Parse a set of JWK keys
*
* @param array $jwks The JSON Web Key Set as an associative array
*
* @return array An associative array that represents the set of keys
*
* @throws InvalidArgumentException Provided JWK Set is empty
* @throws UnexpectedValueException Provided JWK Set was invalid
* @throws DomainException OpenSSL failure
*
* @uses parseKey
*/
public static function parseKeySet(array $jwks)
{
$keys = array();
if (!isset($jwks['keys'])) {
throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
}
if (empty($jwks['keys'])) {
throw new InvalidArgumentException('JWK Set did not contain any keys');
}
foreach ($jwks['keys'] as $k => $v) {
$kid = isset($v['kid']) ? $v['kid'] : $k;
if ($key = self::parseKey($v)) {
$keys[$kid] = $key;
}
}
if (0 === \count($keys)) {
throw new UnexpectedValueException('No supported algorithms found in JWK Set');
}
return $keys;
}
/**
* Parse a JWK key
*
* @param array $jwk An individual JWK
*
* @return resource|array An associative array that represents the key
*
* @throws InvalidArgumentException Provided JWK is empty
* @throws UnexpectedValueException Provided JWK was invalid
* @throws DomainException OpenSSL failure
*
* @uses createPemFromModulusAndExponent
*/
private static function parseKey(array $jwk)
{
if (empty($jwk)) {
throw new InvalidArgumentException('JWK must not be empty');
}
if (!isset($jwk['kty'])) {
throw new UnexpectedValueException('JWK must contain a "kty" parameter');
}
switch ($jwk['kty']) {
case 'RSA':
if (\array_key_exists('d', $jwk)) {
throw new UnexpectedValueException('RSA private keys are not supported');
}
if (!isset($jwk['n']) || !isset($jwk['e'])) {
throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
}
$pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
$publicKey = \openssl_pkey_get_public($pem);
if (false === $publicKey) {
throw new DomainException(
'OpenSSL error: ' . \openssl_error_string()
);
}
return $publicKey;
default:
// Currently only RSA is supported
break;
}
}
/**
* Create a public key represented in PEM format from RSA modulus and exponent information
*
* @param string $n The RSA modulus encoded in Base64
* @param string $e The RSA exponent encoded in Base64
*
* @return string The RSA public key represented in PEM format
*
* @uses encodeLength
*/
private static function createPemFromModulusAndExponent($n, $e)
{
$modulus = JWT::urlsafeB64Decode($n);
$publicExponent = JWT::urlsafeB64Decode($e);
$components = array(
'modulus' => \pack('Ca*a*', 2, self::encodeLength(\strlen($modulus)), $modulus),
'publicExponent' => \pack('Ca*a*', 2, self::encodeLength(\strlen($publicExponent)), $publicExponent)
);
$rsaPublicKey = \pack(
'Ca*a*a*',
48,
self::encodeLength(\strlen($components['modulus']) + \strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
);
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
$rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$rsaPublicKey = \chr(0) . $rsaPublicKey;
$rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
$rsaPublicKey = \pack(
'Ca*a*',
48,
self::encodeLength(\strlen($rsaOID . $rsaPublicKey)),
$rsaOID . $rsaPublicKey
);
$rsaPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
\chunk_split(\base64_encode($rsaPublicKey), 64) .
'-----END PUBLIC KEY-----';
return $rsaPublicKey;
}
/**
* DER-encode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @param int $length
* @return string
*/
private static function encodeLength($length)
{
if ($length <= 0x7F) {
return \chr($length);
}
$temp = \ltrim(\pack('N', $length), \chr(0));
return \pack('Ca*', 0x80 | \strlen($temp), $temp);
}
}
This diff is collapsed.
<?php
namespace Firebase\JWT;
class SignatureInvalidException extends \UnexpectedValueException
{
}
<?php
class Login extends Model {
}
?>
\ No newline at end of file
<?php
class Model {
protected static function db(){
return DatabasePDO::singleton();
}
// *** Queries in sql/model.sql.php ****
protected static $requests = array();
public static function addSqlQuery($key, $sql){
static::$requests[$key] = $sql;
}
public static function sqlQueryNamed($key){
return static::$requests[$key];
}
protected static function query($sql){
$st = static::db()->query($sql) or die("sql query error ! request : " . $sql);
$st->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, get_called_class());
return $st;
}
protected static function exec($sqlKey, $values=array()){
$sth = static::db()->prepare(static::sqlQueryNamed($sqlKey));
$sth->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, get_called_class());
$sth->execute($values);
return $sth;
}
}
?>
\ No newline at end of file
<?php
class User extends Model {
// ===========
// = Statics =
// ===========
public static function tryLogin($login) {
return new static();
}
protected static $table_name = 'USER';
public static function create($post) {
parent::exec('USER_CREATE', [':firstname' => $post->firstname,
':lastname' => $post->lastname,
':login' => $post->login,
':email' => $post->email,
':password' => password_hash($post->password, PASSWORD_BCRYPT),
':role' => $post->role]);
}
public static function getList() {
$stm = parent::exec('USER_GET_LIST');
return $stm->fetchAll();
}
public static function getWithId($id) {
$stm = parent::exec('USER_GET_WITH_ID', [':id' => $id]);
return $stm->fetch();
}
public static function getWithLogin($login) {
$stm = parent::exec('USER_GET_WITH_LOGIN', [':login' => $login]);
return $stm->fetch();
}
public static function update($put, $id) {
parent::exec('USER_UPDATE', [':email' => $put->email, ':id' => $id]);
}
public static function delete($id) {
parent::exec('USER_DELETE', [':id' => $id]);
}
}
?>
\ No newline at end of file
<?php
class Validatetoken extends Model {
}
?>
\ No newline at end of file
<?php
User::addSqlQuery('USER_CREATE',
'INSERT INTO `users` VALUES (NULL, :firstname, :lastname, :login, :email, :password, :role)');
User::addSqlQuery('USER_GET_LIST',
'SELECT * FROM `users` ORDER BY `id` ');
User::addSqlQuery('USER_GET_WITH_ID',
'SELECT * FROM `users` WHERE `id` = :id');
User::addSqlQuery('USER_GET_WITH_LOGIN',
'SELECT * FROM `users` WHERE `login` = :login');
User::addSqlQuery('USER_UPDATE',
'UPDATE `users` SET `email` = :email WHERE `id` = :id');
User::addSqlQuery('USER_DELETE',
'DELETE FROM `users` WHERE `id` = :id');
?>
\ No newline at end of file
div #body {
display: flex;
flex-direction: column;
}
div #navbar {
padding-bottom: 50px;
}
div #center {
display: flex;
justify-content: center;
}
\ No newline at end of file
<template>
<div id="navbar">
<!-- primary, success, info, warning, danger, dark, or light -->
<b-navbar toggleable="lg" type="dark" variant="primary">
<router-link to="/"><b-navbar-brand>Mahjong</b-navbar-brand></router-link>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav class="ml-auto">
<b-navbar-nav>
<b-nav-item href="/">Accueil</b-nav-item>
</b-navbar-nav>
<b-nav-item-dropdown text="Jeu" right>
<b-dropdown-item><router-link to="/gameCreate">Créer une partie</router-link></b-dropdown-item>
<b-dropdown-item><router-link to="/gameJoin">Rejoindre une partie</router-link></b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item-dropdown text="Statistiques" right>
<b-dropdown-item>Mes statistiques</b-dropdown-item>
<b-dropdown-item>Meilleurs scores</b-dropdown-item>
<b-dropdown-item>Classement</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item-dropdown text="Utilisateur" right>
<b-dropdown-item>Profil</b-dropdown-item>
<b-dropdown-item @click="onClick">Déconnexion</b-dropdown-item>
</b-nav-item-dropdown>
</b-navbar-nav>
</b-collapse>
</b-navbar>
</div>
</template>
<script>
export default {
name: 'Navbar',
components: {},
methods: {
onClick() {
const href = window.location.href;
const url = href.substring(0, href.lastIndexOf('/')) + '/'
if (confirm("Etes-vous sür de vouloir vous déconnecter ?"))
window.location.href = url
}
}
};
</script>
\ No newline at end of file
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import BootstrapVue from 'bootstrap-vue'
import '@/assets/style.css'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.config.productionTip = false
Vue.use(BootstrapVue)
new Vue({
router,
......
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Index from '../views/Index.vue'
import Rules from '../views/Rules.vue'
import Login from '../views/Login.vue'
import Signup from '../views/Signup.vue'
import GameCreate from '../views/GameCreate.vue'
import GameJoin from '../views/GameJoin.vue'
import Game from '../views/Game.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
name: 'Index',
component: Index
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
path: '/rules',
name: 'Rules',
component: Rules
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/signup',
name: 'Signup',
component: Signup
},
{
path: '/gameCreate',
name: 'GameCreate',
component: GameCreate
},
{
path: '/gameJoin',
name: 'GameJoin',
component: GameJoin
},
{
path: '/game',
name: 'Game',
component: Game
}
]
......
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<template>
<div id="body">
<Navbar/>
<div id="center">
<img src="../assets/img/game.png" class="img-fluid" alt="Responsive image">
</div>
</div>
</template>
<script>
import Navbar from '@/components/Navbar.vue'
export default {
name: 'Game',
components: {
Navbar
}
}
</script>
\ No newline at end of file
<template>
<div id="body">
<Navbar/>
<div class="container-fluid" style="display: flex; justify-content: space-around;">
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Créer une partie</h6>
</div>
<div class="card-body" style="width : 500px;">
<router-link to="/game">
<a class="btn btn-primary btn-user btn-block">
Commencer
</a>
</router-link>
</div>
</div>
</div>
</div>
</template>
<script>
import Navbar from '@/components/Navbar.vue'
export default {
name: 'GameCreate',
components: {
Navbar
}
}
</script>
\ No newline at end of file
<template>
<div id="body">
<Navbar/>
<div class="container-fluid" style="display: flex; justify-content: space-around;">
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Rejoindre une partie</h6>
</div>
<div class="card-body" style="width : 500px;">
<form class="user" method="post">
<h5>Avec un identifiant :</h5>
<div class="form-group">
<input type="text" class="form-control form-control-user" id="id" placeholder="ID">
</div>
<router-link to="/game">
<a class="btn btn-primary btn-user btn-block">
Commencer
</a>
</router-link>
</form>
<form class="user" method="post" style="margin-top: 100px;">
<h5>Sans identifiant :</h5>
<router-link to="/game">
<a class="btn btn-primary btn-user btn-block">
Trouver une partie
</a>
</router-link>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import Navbar from '@/components/Navbar.vue'
export default {
name: 'GameJoin',
components: {
Navbar
}
}
</script>
\ No newline at end of file
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'Home',
components: {
HelloWorld
}
}
</script>
<template>
<div id="body">
<Navbar/>
<div id="buttons">
<router-link to="/Rules"><b-button variant="primary">Découvrir le mahjong</b-button></router-link>
<router-link to="/Login"><b-button variant="primary">Commercer à jouer</b-button></router-link>
</div>
</div>
</template>
<script>
import Navbar from '@/components/Navbar.vue'
export default {
name: 'Index',
components: {
Navbar
}
}
</script>
<style>
div #buttons {
display: flex;
justify-content: space-around;
}
b-button {
display: flex;
}
</style>
\ No newline at end of file
<template>
<div id="body">
<div class="container">
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<div class="row">
<div class="col-lg-6 d-none d-lg-block bg-login-image">
<img src="../assets/img/log.png" class="img-fluid" alt="Responsive image">
</div>
<div class="col-lg-6">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">Connectez-vous !</h1>
</div>
<form class="user" @submit="onSubmit">
<div v-for="row in rows" :key="row.id" class="form-group">
<input
:type="row.text"
class="form-control form-control-user"
:id="row.id"
:placeholder="row.placeholder">
</div>
<button type="submit" class="btn btn-primary btn-user btn-block">Connexion</button>
</form>
<hr>
<div class="text-center">
<router-link to="/Signup">
<a class="small">Créer un compte</a>
</router-link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
rows: [
{ type: 'text', id: 'login', placeholder: 'Login'},
{ type: 'password', id: 'password', placeholder: 'Mot de passe'}
]
}
},
methods: {
async onSubmit(evt) {
evt.preventDefault()
// const href = window.location.href;
// const url = href.substring(0, href.lastIndexOf('/')) + "/api/api.php/user";
// const url = "http://localhost:8080/api/api.php/user";
// const url = require("@/api/api.php/user");
// fetch(url, {
// method: 'GET'
// })
// .then(response => {
// return response.json();
// })
// .then(data => {
// console.log(data);
// })
// fetch(url, {
// method: 'GET'
// })
// .then(response => {
// if (response.status === 200) {
// return response.json();
// } else {
// throw new Error('Something went wrong on api server!');
// }
// })
// .then(data => {
// // const index = data.findIndex((e) => e.login == form.elements.login.value);
// console.log(data);
// }).catch(error => {
// console.error(error);
// });
}
}
}
</script>
\ No newline at end of file
<template>
<div id="body">
<Navbar/>
<div id="center">
<h1>Les règles</h1>
</div>
</div>
</template>
<script>
import Navbar from '@/components/Navbar.vue'
export default {
name: 'Rules',
components: {
Navbar
}
}
</script>
\ No newline at end of file
<template>
<div id="body">
<div class="container">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<div class="row">
<div class="col-lg-6 d-none d-lg-block bg-login-image">
<img src="../assets/img/log.png" class="img-fluid" alt="Responsive image">
</div>
<div class="col-lg-6">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">Créez un compte !</h1>
</div>
<form class="user" @submit="onSubmit">
<div class="form-group row">
<div class="col-sm-6 mb-3 mb-sm-0">
<input type="text" class="form-control form-control-user" id="firstname" placeholder="Prénom">
</div>
<div class="col-sm-6">
<input type="text" class="form-control form-control-user" id="lastname" placeholder="Nom">
</div>
</div>
<div class="form-group">
<input type="text" class="form-control form-control-user" id="login" placeholder="Login">
</div>
<div class="form-group">
<input type="email" class="form-control form-control-user" id="email" placeholder="Email">
</div>
<div class="form-group row">
<div class="col-sm-6 mb-3 mb-sm-0">
<input type="password" class="form-control form-control-user" id="password" placeholder="Mot de passe">
</div>
<div class="col-sm-6">
<input type="password" class="form-control form-control-user" id="repeatPassword" placeholder="Confirmation">
</div>
</div>
<button type="submit" class="btn btn-primary btn-user btn-block">Inscription</button>
</form>
<hr>
<div class="text-center">
<router-link to="/login">
<a class="small" href="login.php">Déjà inscrit ? Connectez-vous !</a>
</router-link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Signup',
data() {
return {
rows: [
{ type: 'text', id: 'login', placeholder: 'Login'},
{ type: 'password', id: 'password', placeholder: 'Mot de passe'}
]
}
},
methods: {
onSubmit(evt) {
evt.preventDefault()
// const href = window.location.href;
// const url = href.substring(0, href.lastIndexOf('/')) + "/api/api.php/user";
// const form = document.forms[0];
// let body = { 'role': 0 };
// Object.entries(form.elements).forEach((key) => {
// if (key[1].id != "repeatPassword")
// body[key[1].id] = key[1].value;
// })
// fetch(url, {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(body)
// })
// .then(response => {
// if (response.status === 200) {
// window.location.href = href.substring(0, href.lastIndexOf('/')) + "/login.php";
// } else {
// throw new Error('Something went wrong on api server!');
// }
// }).catch(error => {
// console.error(error);
// });
}
}
}
</script>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment