This commit is contained in:
Kekskurse 2019-04-28 14:49:10 +02:00
parent 0d929748b7
commit 8d8cc32b9c
14 changed files with 262 additions and 58 deletions

View file

@ -3,20 +3,14 @@ namespace App\Exceptions;
class HTTPException extends \Exception class HTTPException extends \Exception
{ {
// Die Exception neu definieren, damit die Mitteilung nicht optional ist private $httpCode = 500;
public function __construct($httpCode, $message, $code = 0, Exception $previous = null) {
// etwas Code
// sicherstellen, dass alles korrekt zugewiesen wird public function __construct($httpCode, $message, $code = 0, Exception $previous = null) {
$this->httpCode = $httpCode;
parent::__construct($message, $code, $previous); parent::__construct($message, $code, $previous);
} }
public function getHttpStatusCode() {
// maßgeschneiderte Stringdarstellung des Objektes return $this->httpCode;
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
} }
public function customFunction() {
echo "Eine eigene Funktion dieses Exceptiontyps\n";
}
} }

View file

@ -8,6 +8,7 @@ use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler; use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpException;
use TaGeSo\APIResponse\Response;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
{ {
@ -45,6 +46,26 @@ class Handler extends ExceptionHandler
*/ */
public function render($request, Exception $exception) public function render($request, Exception $exception)
{ {
//Handle Excepions
try {
throw $exception;
} catch (\App\Exceptions\HTTPException $e) {
$res = new Response();
$res->setStatus(false);
$res->setMessage($e->getMessage());
$res->setStatusCode($e->getHttpStatusCode());
return $res;
} catch (ValidationException $e) {
$res = new Response();
$res->setStatus(false);
$res->setMessage($e->getMessage());
$res->setStatusCode(422);
$res->withData($e->errors());
return $res;
}
catch (Exception $e) {
return parent::render($request, $exception); return parent::render($request, $exception);
} }
}
} }

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers\API; namespace App\Http\Controllers\API;
use App\Exceptions\HTTPException;
use App\Exceptions\NoPermissionException; use App\Exceptions\NoPermissionException;
use App\Exceptions\NotLoggedInException; use App\Exceptions\NotLoggedInException;
use App\Exceptions\ResourceNotFound; use App\Exceptions\ResourceNotFound;
@ -13,6 +14,7 @@ use TaGeSo\APIResponse\Response;
class AccountController extends BaseController class AccountController extends BaseController
{ {
public function getUsers(Response $response) { public function getUsers(Response $response) {
if(!Auth::check()) { if(!Auth::check()) {
throw new NotLoggedInException(); throw new NotLoggedInException();
} }

View file

@ -0,0 +1,81 @@
<?php
namespace App\Http\Controllers\API;
use App\Exceptions\HTTPException;
use App\Exceptions\NoPermissionException;
use App\Exceptions\NotLoggedInException;
use App\Exceptions\ResourceNotFound;
use App\Http\Resources\oAuth\AccessToken;
use App\Models\App;
use App\Models\AppAccess;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Laravel\Lumen\Routing\Controller as BaseController;
use ReCaptcha\ReCaptcha;
use TaGeSo\APIResponse\Response;
class UserController extends BaseController
{
/*
* The Password login is just for the WebGUI
*/
public function passwordLogin(Request $request, Response $response)
{
//If Recptache is enabled check it at the beginning
if(Setting::getSettingValue("recaptcha_v2_login")) {
$reCaptcha = new ReCaptcha(Setting::getSettingValue("recaptcha_v2_secret"));
$response = $reCaptcha->verify($request->input("g-recaptcha-response"));
if(!$response->isSuccess()) {
throw new HTTPException(400, "Captcha validation failed");
}
}
//Validate Input
$this->validate($request, [
'username' => 'required',
'password' => 'required'
]);
//Get User
$user = User::query()->where("username", "=", $request->input("username"))->first();
//Check if a user is found
if($user == null) {
throw new HTTPException("400", "Username or Password wrong");
}
if(!password_verify($request->input("password"), $user->password)) {
throw new HTTPException("400", "Username or Password wrong");
}
//Create Access Permission for WebGUI
$access = AppAccess::getOrCreate($user->id, App::query()->where("name", "=", "PHP-GUI")->firstOrFail()->id);
$token = \App\Models\AccessToken::createToken($access);
//Save Token to Session
$_SESSION["token"] = $token->token;
return new AccessToken($token);
}
public function register(Request $request, Response $response) {
}
/*
* Return Captcha Settings used by the public webpage bevore the user is loggedin
*/
public function reCAPTCHA(Response $response) {
$data = [];
$data["key"] = Setting::getSettingValue("recaptcha_v2_key");
$data["login"] = (bool)Setting::getSettingValue("recaptcha_v2_login");
$data["register"] = (bool)Setting::getSettingValue("recaptcha_v2_register");
return $response->withData($data);
}
}

View file

@ -113,27 +113,7 @@ class AccountController extends Controller
public function loginView() { public function loginView() {
return view('account/login', ["msg"=>""]); return view('account/login', ["msg"=>""]);
} }
public function login(Request $request) {
$this->validate($request, [
'username' => 'required',
'password' => 'required'
]);
$user = User::query()->where("username", "=", $request->input("username"))->first();
if($user==null) {
abort(401, "Username or Password wrong");
}
if(!password_verify($request->input("password"), $user->password)) {
abort(401, "Username or Password wrong");
}
$access = AppAccess::getOrCreate($user->id, App::query()->where("name", "=", "PHP-GUI")->firstOrFail()->id);
$token = \App\Models\AccessToken::createToken($access);
$_SESSION["token"] = $token->token;
return new AccessToken($token);
}
public function logout() { public function logout() {
session_destroy(); session_destroy();
return view('account/login', ["msg"=>"Logout successful", "user" => null]); return view('account/login', ["msg"=>"Logout successful", "user" => null]);
@ -153,13 +133,6 @@ class AccountController extends Controller
$mail->primary = true; $mail->primary = true;
} }
//Dont set new Mails as primary
/*$mails = Mail::query()->where("user_id", "=", $mail->user_id)->where("primary", "=", true)->get("*");
foreach($mails as $m) {
$m->primary = false;
$m->saveOrFail();
}*/
$mail->saveOrFail(); $mail->saveOrFail();
echo "E-Mail wurde validiert"; echo "E-Mail wurde validiert";
} }

View file

@ -22,6 +22,9 @@ class AppController extends Controller
} }
public function appList() { public function appList() {
if(!Auth::check()) {
abort(401);
}
$apps = App::query()->where("user_id", "=", Auth::user()->id)->get(); $apps = App::query()->where("user_id", "=", Auth::user()->id)->get();
return view('app/list', ["msg"=>"", "apps" => $apps]); return view('app/list', ["msg"=>"", "apps" => $apps]);
} }

View file

@ -142,6 +142,7 @@ class oAuthController extends Controller
$data["sub"] = $user->username; $data["sub"] = $user->username;
$data["email"] = $user->getMail(); $data["email"] = $user->getMail();
$data["name"] = $user->username; $data["name"] = $user->username;
$data["displayName"] = $user->username; //Param for Nextcloud
$data["state"] = "active"; $data["state"] = "active";
$data["avatar_url"] = "https://www.alzforum.org/sites/default/files/member-default.jpg"; $data["avatar_url"] = "https://www.alzforum.org/sites/default/files/member-default.jpg";
#$data["web_url"] = "http://www.kekskurse.de"; #$data["web_url"] = "http://www.kekskurse.de";

View file

@ -19,6 +19,11 @@ class View
{ {
view()->share('user', Auth::user()); view()->share('user', Auth::user());
view()->share('settingsArray', Setting::getSettingsAsArray()); view()->share('settingsArray', Setting::getSettingsAsArray());
return $next($request); $response = $next($request);
if($response->status() == 401) {
return redirect('/gui/login');
}
return $response;
} }
} }

View file

@ -9,7 +9,8 @@
"laravel/lumen-framework": "5.8.*", "laravel/lumen-framework": "5.8.*",
"vlucas/phpdotenv": "^3.3", "vlucas/phpdotenv": "^3.3",
"phpmailer/phpmailer": "~6.0", "phpmailer/phpmailer": "~6.0",
"tageso/api-response": "*" "tageso/api-response": "*",
"google/recaptcha": "^1.2"
}, },
"require-dev": { "require-dev": {
"fzaninotto/faker": "^1.4", "fzaninotto/faker": "^1.4",

57
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": "265697a07793434d0d8ac306debafc74", "content-hash": "0a69119706b0705d3100af89a96435b6",
"packages": [ "packages": [
{ {
"name": "doctrine/inflector", "name": "doctrine/inflector",
@ -238,6 +238,53 @@
], ],
"time": "2018-12-04T22:38:24+00:00" "time": "2018-12-04T22:38:24+00:00"
}, },
{
"name": "google/recaptcha",
"version": "1.2.1",
"source": {
"type": "git",
"url": "https://github.com/google/recaptcha.git",
"reference": "e7add3be59211482ecdb942288f52da64a35f61a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/google/recaptcha/zipball/e7add3be59211482ecdb942288f52da64a35f61a",
"reference": "e7add3be59211482ecdb942288f52da64a35f61a",
"shasum": ""
},
"require": {
"php": ">=5.5"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.2.20|^2.12",
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"psr-4": {
"ReCaptcha\\": "src/ReCaptcha"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Client library for reCAPTCHA, a free service that protects websites from spam and abuse.",
"homepage": "https://www.google.com/recaptcha/",
"keywords": [
"Abuse",
"captcha",
"recaptcha",
"spam"
],
"time": "2018-08-05T09:31:53+00:00"
},
{ {
"name": "illuminate/auth", "name": "illuminate/auth",
"version": "v5.8.14", "version": "v5.8.14",
@ -2785,12 +2832,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/tageso/apiResponse.git", "url": "https://github.com/tageso/apiResponse.git",
"reference": "510e4233d31506f5bd4e6d3456d55297d8c0376d" "reference": "c545bc4cf7649d5d193e05f06d0328e3f4dc58e1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/tageso/apiResponse/zipball/510e4233d31506f5bd4e6d3456d55297d8c0376d", "url": "https://api.github.com/repos/tageso/apiResponse/zipball/c545bc4cf7649d5d193e05f06d0328e3f4dc58e1",
"reference": "510e4233d31506f5bd4e6d3456d55297d8c0376d", "reference": "c545bc4cf7649d5d193e05f06d0328e3f4dc58e1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2816,7 +2863,7 @@
"source": "https://github.com/tageso/apiResponse/tree/master", "source": "https://github.com/tageso/apiResponse/tree/master",
"issues": "https://github.com/tageso/apiResponse/issues" "issues": "https://github.com/tageso/apiResponse/issues"
}, },
"time": "2019-04-25T15:20:37+00:00" "time": "2019-04-26T14:12:17+00:00"
}, },
{ {
"name": "vlucas/phpdotenv", "name": "vlucas/phpdotenv",

View file

@ -0,0 +1,54 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class Recaptcha extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$setting = new \App\Models\Setting();
$setting->name = "recaptcha_v2_register";
$setting->description = "Enabled Recaptcha for Register Page";
$setting->typ = "checkbox";
$setting->value = 0;
$setting->saveOrFail();
$setting = new \App\Models\Setting();
$setting->name = "recaptcha_v2_login";
$setting->description = "Enabled Recaptcha for Login to Account-Service";
$setting->typ = "checkbox";
$setting->value = 0;
$setting->saveOrFail();
$setting = new \App\Models\Setting();
$setting->name = "recaptcha_v2_key";
$setting->description = "Recaptcha V2 Key";
$setting->typ = "textinput";
$setting->value = "";
$setting->saveOrFail();
$setting = new \App\Models\Setting();
$setting->name = "recaptcha_v2_secret";
$setting->description = "Recaptcha V2 Secret";
$setting->typ = "textinput";
$setting->value = "";
$setting->saveOrFail();
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
\App\Models\Setting::query()->where("name", "=", "recaptcha_v2_register")->delete();
\App\Models\Setting::query()->where("name", "=", "recaptcha_v2_login")->delete();
\App\Models\Setting::query()->where("name", "=", "recaptcha_v2_key")->delete();
\App\Models\Setting::query()->where("name", "=", "recaptcha_v2_secret")->delete();
}
}

View file

@ -1,43 +1,59 @@
<?php include(__DIR__."/../layout/top.php"); ?> <?php include(__DIR__."/../layout/top.php"); ?>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script><br>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h3>Register</h3> <h3>Login</h3>
<?php if(!empty($msg)) { ?>
<div class="alert alert-warning" role="alert">
<?php echo $msg; ?>
</div>
<?php } ?>
<form method="post" id="login"> <form method="post" id="login">
<b>Username:</b> <span id="msg_username"></span> <b>Username:</b> <span id="msg_username"></span>
<input name="username" placeholder="Username" class="form-control"> <input name="username" placeholder="Username" class="form-control">
<b>Password:</b> <span id="msg_password"></span> <b>Password:</b> <span id="msg_password"></span>
<input name="password" type="password" placeholder="Password" class="form-control"> <input name="password" type="password" placeholder="Password" class="form-control">
<input type="submit" class="btn btn-success" value="Login" style="margin-top: 10px;"> <div id="captcha" style="padding-top: 10px;">
</div>
<input type="submit" id="loginButton" disabled class="btn btn-success" value="Login" style="margin-top: 10px;">
</form> </form>
</div> </div>
</div> </div>
<script language="JavaScript"> <script language="JavaScript">
var captchaConfig = {};
function getCaptchaConfig() {
$.ajax({
type: "GET",
url: "/api/v1/user/captcha",
success: function (res) {
captchaConfig = res.data;
if(captchaConfig["login"]) {
grecaptcha.render('captcha', {
'sitekey' : captchaConfig["key"]
});
}
$("#loginButton").removeAttr('disabled');
}
});
}
$(document).ready(function () { $(document).ready(function () {
getCaptchaConfig();
console.log("READY"); console.log("READY");
$("#login").submit(function (e) { $("#login").submit(function (e) {
e.preventDefault(); e.preventDefault();
var form = $(this); var form = $(this);
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/gui/login", url: "/api/v1/user/login",
data: form.serialize(), // serializes the form's elements. data: form.serialize(), // serializes the form's elements.
success: function (data) { success: function (data) {
window.location.href = "/"; window.location.href = "/";
}, },
error: function (data) { error: function (data) {
if(data.status == 422) { if(data.status == 422) {
$.each(data.responseJSON, function( key, value ) { $.each(data.responseJSON.data, function( key, value ) {
$("#msg_"+key).html(value[0]); $("#msg_"+key).html(value[0]);
}); });
} else {
swal(data.responseJSON.msg, '', "error")
} }
if(data.status == 401) { grecaptcha.reset();
alert("Usernamme/Password falsch");
}
} }
}); });
}); });

View file

@ -7,6 +7,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
</head> </head>
<body> <body>
<div class="container" style="margin-top: 30px;min-height: calc(100vh - 100px);"> <div class="container" style="margin-top: 30px;min-height: calc(100vh - 100px);">

View file

@ -43,8 +43,13 @@ $router->group(['prefix' => 'api', 'middleware' => 'auth'], function () use ($ro
$router->get("/", ['uses' => 'API\AccountController@getUsers']); $router->get("/", ['uses' => 'API\AccountController@getUsers']);
$router->get("/{id}", ['uses' => 'API\AccountController@getUser']); $router->get("/{id}", ['uses' => 'API\AccountController@getUser']);
}); });
$router->group(['prefix' => 'user'], function () use ($router) {
});
}); });
}); });
$router->post("api/v1/user/login", ['uses' => 'API\UserController@passwordLogin']);
$router->get("api/v1/user/captcha", ['uses' => 'API\UserController@reCAPTCHA']);
$router->group(['prefix' => 'gui', 'middleware' => 'gui'], function () use ($router) { $router->group(['prefix' => 'gui', 'middleware' => 'gui'], function () use ($router) {
$router->get('/register', ['uses' => 'GUI\AccountController@registerView']); $router->get('/register', ['uses' => 'GUI\AccountController@registerView']);