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
{
// Die Exception neu definieren, damit die Mitteilung nicht optional ist
public function __construct($httpCode, $message, $code = 0, Exception $previous = null) {
// etwas Code
private $httpCode = 500;
// sicherstellen, dass alles korrekt zugewiesen wird
public function __construct($httpCode, $message, $code = 0, Exception $previous = null) {
$this->httpCode = $httpCode;
parent::__construct($message, $code, $previous);
}
// maßgeschneiderte Stringdarstellung des Objektes
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
public function getHttpStatusCode() {
return $this->httpCode;
}
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 Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
use TaGeSo\APIResponse\Response;
class Handler extends ExceptionHandler
{
@ -45,6 +46,26 @@ class Handler extends ExceptionHandler
*/
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);
}
}
}

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers\API;
use App\Exceptions\HTTPException;
use App\Exceptions\NoPermissionException;
use App\Exceptions\NotLoggedInException;
use App\Exceptions\ResourceNotFound;
@ -13,6 +14,7 @@ use TaGeSo\APIResponse\Response;
class AccountController extends BaseController
{
public function getUsers(Response $response) {
if(!Auth::check()) {
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() {
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() {
session_destroy();
return view('account/login', ["msg"=>"Logout successful", "user" => null]);
@ -153,13 +133,6 @@ class AccountController extends Controller
$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();
echo "E-Mail wurde validiert";
}

View file

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

View file

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

View file

@ -19,6 +19,11 @@ class View
{
view()->share('user', Auth::user());
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.*",
"vlucas/phpdotenv": "^3.3",
"phpmailer/phpmailer": "~6.0",
"tageso/api-response": "*"
"tageso/api-response": "*",
"google/recaptcha": "^1.2"
},
"require-dev": {
"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",
"This file is @generated automatically"
],
"content-hash": "265697a07793434d0d8ac306debafc74",
"content-hash": "0a69119706b0705d3100af89a96435b6",
"packages": [
{
"name": "doctrine/inflector",
@ -238,6 +238,53 @@
],
"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",
"version": "v5.8.14",
@ -2785,12 +2832,12 @@
"source": {
"type": "git",
"url": "https://github.com/tageso/apiResponse.git",
"reference": "510e4233d31506f5bd4e6d3456d55297d8c0376d"
"reference": "c545bc4cf7649d5d193e05f06d0328e3f4dc58e1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tageso/apiResponse/zipball/510e4233d31506f5bd4e6d3456d55297d8c0376d",
"reference": "510e4233d31506f5bd4e6d3456d55297d8c0376d",
"url": "https://api.github.com/repos/tageso/apiResponse/zipball/c545bc4cf7649d5d193e05f06d0328e3f4dc58e1",
"reference": "c545bc4cf7649d5d193e05f06d0328e3f4dc58e1",
"shasum": ""
},
"require": {
@ -2816,7 +2863,7 @@
"source": "https://github.com/tageso/apiResponse/tree/master",
"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",

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"); ?>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script><br>
<div class="row">
<div class="col-md-12">
<h3>Register</h3>
<?php if(!empty($msg)) { ?>
<div class="alert alert-warning" role="alert">
<?php echo $msg; ?>
</div>
<?php } ?>
<h3>Login</h3>
<form method="post" id="login">
<b>Username:</b> <span id="msg_username"></span>
<input name="username" placeholder="Username" class="form-control">
<b>Password:</b> <span id="msg_password"></span>
<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>
</div>
</div>
<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 () {
getCaptchaConfig();
console.log("READY");
$("#login").submit(function (e) {
e.preventDefault();
var form = $(this);
$.ajax({
type: "POST",
url: "/gui/login",
url: "/api/v1/user/login",
data: form.serialize(), // serializes the form's elements.
success: function (data) {
window.location.href = "/";
},
error: function (data) {
if(data.status == 422) {
$.each(data.responseJSON, function( key, value ) {
$.each(data.responseJSON.data, function( key, value ) {
$("#msg_"+key).html(value[0]);
});
} else {
swal(data.responseJSON.msg, '', "error")
}
if(data.status == 401) {
alert("Usernamme/Password falsch");
}
grecaptcha.reset();
}
});
});

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://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">
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
</head>
<body>
<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("/{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->get('/register', ['uses' => 'GUI\AccountController@registerView']);