✨ Ajoute le routeur et la page d'instanciation de la phrase de passe
This commit is contained in:
parent
c2b60b4b6a
commit
a8116aa5a2
29
.eslintrc.json
Normal file
29
.eslintrc.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"react",
|
||||
"@typescript-eslint",
|
||||
"react-hooks"
|
||||
],
|
||||
"rules": {
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "warn"
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ class UserController extends Controller
|
||||
$user = User::where('id', Auth::user()->getAuthIdentifier())->firstOrFail();
|
||||
$user->checkword = $validated['checkword'];
|
||||
$user->save();
|
||||
Auth::setUser($user);
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\CheckExistingPassphrase;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
@ -54,6 +55,7 @@ class Kernel extends HttpKernel
|
||||
* @var array<string, class-string|string>
|
||||
*/
|
||||
protected $routeMiddleware = [
|
||||
'auth.passphrase' => CheckExistingPassphrase::class,
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
|
30
app/Http/Middleware/CheckExistingPassphrase.php
Normal file
30
app/Http/Middleware/CheckExistingPassphrase.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class CheckExistingPassphrase
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!$request->routeIs('user.*') && empty(Auth::user()->checkword)) {
|
||||
return redirect(route('user.first'));
|
||||
}
|
||||
|
||||
if (!empty(Auth::user()->checkword) && $request->routeIs('user.first')) {
|
||||
return redirect(route('pages.index'));
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
2387
package-lock.json
generated
2387
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,10 +13,14 @@
|
||||
"@babel/preset-react": "^7.13.13",
|
||||
"@popperjs/core": "^2.10.2",
|
||||
"@tailwindcss/forms": "^0.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
||||
"@typescript-eslint/parser": "^5.12.1",
|
||||
"alpinejs": "^3.4.2",
|
||||
"autoprefixer": "^10.1.0",
|
||||
"axios": "^0.21.4",
|
||||
"bootstrap": "^5.1.3",
|
||||
"eslint": "^8.9.0",
|
||||
"eslint-plugin-react": "^7.29.0",
|
||||
"laravel-mix": "^6.0.6",
|
||||
"lodash": "^4.17.19",
|
||||
"postcss": "^8.2.1",
|
||||
@ -36,8 +40,10 @@
|
||||
"@mui/icons-material": "^5.4.1",
|
||||
"@mui/material": "^5.4.1",
|
||||
"@uiw/react-md-editor": "^3.9.4",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"react-crypt-gsm": "^1.0.4",
|
||||
"react-query": "^3.34.12",
|
||||
"react-router-dom": "^5.3.0",
|
||||
"storage-encryption": "^1.0.16"
|
||||
}
|
||||
}
|
||||
|
3421
public/js/app.js
vendored
3421
public/js/app.js
vendored
File diff suppressed because it is too large
Load Diff
@ -12,5 +12,5 @@ require('./bootstrap');
|
||||
* or customize the JavaScript scaffolding to fit your unique needs.
|
||||
*/
|
||||
|
||||
require('./components/pages/App');
|
||||
require('./components/pages/AppWrapper');
|
||||
require('./components/user/First');
|
||||
|
@ -1,11 +1,17 @@
|
||||
import ReactDOM from 'react-dom';
|
||||
import PageForm from "./Form";
|
||||
import Pages from "./List";
|
||||
import Prompt from "./Prompt";
|
||||
import {useState} from "react";
|
||||
import * as React from 'react';
|
||||
import {Divider, Paper} from "@mui/material";
|
||||
import {Alert, AlertTitle, Divider} from "@mui/material";
|
||||
import {EncryptStorage} from "storage-encryption";
|
||||
import {
|
||||
Switch,
|
||||
Route,
|
||||
Link,
|
||||
Redirect,
|
||||
withRouter,
|
||||
useHistory
|
||||
} from "react-router-dom";
|
||||
|
||||
interface List {
|
||||
id: string;
|
||||
@ -13,9 +19,9 @@ interface List {
|
||||
}
|
||||
|
||||
const app = document.getElementById('app');
|
||||
const word = "shikiryu";
|
||||
const word = "shikiryu"; // FIXME should be in db and ≠ between users
|
||||
|
||||
let sessionPassphrase = sessionStorage.getItem("key");
|
||||
const sessionPassphrase = sessionStorage.getItem("key");
|
||||
let pages: List[] = [];
|
||||
let getPageContentUrl,
|
||||
postUrl,
|
||||
@ -30,70 +36,153 @@ if (app) {
|
||||
removeUrl = "" + app.getAttribute('data-remove');
|
||||
csrf = "" + app.getAttribute('data-csrf');
|
||||
checkword = "" + app.getAttribute('data-checkword');
|
||||
ReactDOM.render(<App/>, app);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [listPages, setListPages] = useState(pages);
|
||||
const [passphrase, setPassphrase] = useState(sessionPassphrase);
|
||||
function App() {
|
||||
const [listPages, setListPages] = React.useState(pages);
|
||||
const [passphrase, setPassphrase] = React.useState(sessionPassphrase);
|
||||
const history = useHistory();
|
||||
const [user, setUser] = React.useState(false);
|
||||
const [error, isError] = React.useState(false);
|
||||
|
||||
const updatePassphrase = function(newPassphrase) {
|
||||
setPassphrase(newPassphrase);
|
||||
return result(checkPassphrase());
|
||||
const signin = cb => {
|
||||
const isAuthenticated = checkPassphrase();
|
||||
setUser(isAuthenticated);
|
||||
if (isAuthenticated) {
|
||||
isError(false);
|
||||
cb();
|
||||
} else {
|
||||
isError(true);
|
||||
}
|
||||
};
|
||||
|
||||
const checkPassphrase = function() {
|
||||
const signout = cb => {
|
||||
setUser(false);
|
||||
cb();
|
||||
};
|
||||
|
||||
function checkPassphrase() {
|
||||
if (checkword === "" || checkword === null || checkword === "null") {
|
||||
console.error("checkword is empty !");
|
||||
// return (<Redirect to="/first" />);
|
||||
return false; // TODO redirect to first
|
||||
return false;
|
||||
}
|
||||
localStorage.setItem("checkword", checkword);
|
||||
|
||||
const key = ""+sessionStorage.getItem("key");
|
||||
if (key === "" || key === null || key === "null") {
|
||||
console.error("key is empty 🤔 !");
|
||||
// return (<Redirect to="/first" />);
|
||||
return false; // TODO redirect to first ?
|
||||
return false;
|
||||
}
|
||||
let encryptStorage = new EncryptStorage(key);
|
||||
const encryptStorage = new EncryptStorage(key);
|
||||
const decrypted_word = encryptStorage.decrypt("checkword");
|
||||
|
||||
return decrypted_word === word;
|
||||
};
|
||||
}
|
||||
|
||||
const result = function(correct) {
|
||||
let content;
|
||||
if (correct === true) {
|
||||
content = <div className="col-md-8">
|
||||
<Pages
|
||||
pages={listPages}
|
||||
url={getPageContentUrl}
|
||||
passphrase={passphrase}
|
||||
setPassphrase={setPassphrase}
|
||||
csrf={csrf}
|
||||
removeUrl={removeUrl}/>
|
||||
<Divider/>
|
||||
<PageForm setListPages={setListPages} csrf={csrf} url={postUrl} passphrase={passphrase}/>
|
||||
</div>
|
||||
} else if (correct === false) {
|
||||
content = <div className="col-md-8">
|
||||
<Prompt open={true} setOpen={updatePassphrase}/>
|
||||
</div>;
|
||||
} else {
|
||||
return correct;
|
||||
const Error = function() {
|
||||
if (error) {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
<AlertTitle>Erreur</AlertTitle>
|
||||
La phrase de passe ne correspond pas.
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
return (<div></div>);
|
||||
}
|
||||
|
||||
const AuthButton = function() {
|
||||
const history = useHistory();
|
||||
|
||||
return user ? (
|
||||
<p>
|
||||
Welcome!{" "}
|
||||
<button
|
||||
onClick={() => {
|
||||
signout(() => history.push("/"));
|
||||
}}
|
||||
>
|
||||
Sign out
|
||||
</button>
|
||||
</p>
|
||||
) : (
|
||||
<p>You are not logged in.</p>
|
||||
);
|
||||
}
|
||||
|
||||
function updatePassphrase(newPassphrase) {
|
||||
setPassphrase(newPassphrase);
|
||||
if (checkPassphrase()) {
|
||||
isError(false);
|
||||
setUser(true);
|
||||
signin(() => {
|
||||
history.push({ pathname: "/diary/public/pages" });
|
||||
})
|
||||
} else {
|
||||
isError(true);
|
||||
}
|
||||
}
|
||||
|
||||
function PrivateRoute({ children, ...rest }) {
|
||||
return (
|
||||
<div>
|
||||
<div className="container">
|
||||
<div className="row justify-content-center">
|
||||
{ content }
|
||||
</div>
|
||||
</div>
|
||||
<Route
|
||||
{...rest}
|
||||
render={({ location }) =>
|
||||
user ? (
|
||||
children
|
||||
) : (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: "/diary/public/pass",
|
||||
state: { from: location }
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function PromptPage() {
|
||||
return (<Prompt open={true} setOpen={updatePassphrase}/>);
|
||||
}
|
||||
|
||||
function ListPage() {
|
||||
return (
|
||||
<div className="col-md-8">
|
||||
<Pages
|
||||
pages={listPages}
|
||||
url={getPageContentUrl}
|
||||
passphrase={passphrase}
|
||||
setPassphrase={setPassphrase}
|
||||
csrf={csrf}
|
||||
removeUrl={removeUrl}/>
|
||||
<Divider/>
|
||||
<PageForm setListPages={setListPages} csrf={csrf} url={postUrl} passphrase={passphrase}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return result(checkPassphrase());
|
||||
return (
|
||||
<div>
|
||||
<AuthButton />
|
||||
<Error/>
|
||||
<ul>
|
||||
<li>
|
||||
<Link to="/diary/public/pages">Voir vos pages</Link>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Switch>
|
||||
<Route path="/diary/public/pass">
|
||||
<PromptPage />
|
||||
</Route>
|
||||
<PrivateRoute path="/diary/public/pages">
|
||||
<ListPage />
|
||||
</PrivateRoute>
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withRouter(App);
|
||||
|
17
resources/js/components/pages/AppWrapper.tsx
Normal file
17
resources/js/components/pages/AppWrapper.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import * as React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { BrowserRouter as Router} from "react-router-dom";
|
||||
import App from "./App";
|
||||
|
||||
const app = document.getElementById('app');
|
||||
if (app) {
|
||||
ReactDOM.render(<AppWrapper/>, app);
|
||||
}
|
||||
|
||||
export default function AppWrapper() {
|
||||
return (
|
||||
<Router>
|
||||
<App />
|
||||
</Router>
|
||||
)
|
||||
}
|
@ -24,15 +24,19 @@ export default function FirstPage() {
|
||||
encryptStorage = new EncryptStorage(passphrase);
|
||||
encryptStorage.encrypt("checkword", word);
|
||||
let encryptedFormData = new FormData();
|
||||
encryptedFormData.append("checkword", ""+localStorage.getItem("key"));
|
||||
encryptedFormData.append("checkword", ""+localStorage.getItem("checkword"));
|
||||
encryptedFormData.append('_token', csrf);
|
||||
|
||||
let response = await fetch(url, {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: encryptedFormData
|
||||
});
|
||||
|
||||
const json = await response.json(); // TODO redirect if success
|
||||
|
||||
if (json.success) {
|
||||
location.href = "/diary/public/pages"
|
||||
}
|
||||
};
|
||||
|
||||
const updatePassphrase = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
@ -20,10 +20,10 @@ Route::get('/', function () {
|
||||
});
|
||||
|
||||
Route::resource('pages', PageController::class)
|
||||
->middleware(['auth']);
|
||||
->middleware(['auth', 'auth.passphrase']);
|
||||
|
||||
Route::get('/first', [UserController::class, 'first'])->name('user.first');
|
||||
Route::post('/first', [UserController::class, 'storeFirst'])->name('user.storeFirst');
|
||||
Route::get('/first', [UserController::class, 'first'])->middleware(['auth', 'auth.passphrase'])->name('user.first');
|
||||
Route::post('/first', [UserController::class, 'storeFirst'])->middleware(['auth', 'auth.passphrase'])->name('user.storeFirst');
|
||||
|
||||
Route::get('/dashboard', function () {
|
||||
return view('dashboard');
|
||||
|
Loading…
Reference in New Issue
Block a user