keksAccount/app/Http/Controllers/API/UserController.php

313 lines
9.5 KiB
PHP

<?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\Jobs\Mails\ValidateMailAddressJob;
use App\Models\App;
use App\Models\AppAccess;
use App\Models\Invite;
use App\Models\Mail;
use App\Models\Setting;
use App\Models\User;
use Domnikl\Statsd\Client;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
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, Client $statsd)
{
$statsd->count("login.try", 1);
//If Recptache is enabled check it at the beginning
if(Setting::getSettingValue("recaptcha_v2_login")) {
$reCaptcha = new ReCaptcha(Setting::getSettingValue("recaptcha_v2_secret"));
$reresponse = $reCaptcha->verify($request->input("g-recaptcha-response"));
if(!$reresponse->isSuccess()) {
$statsd->count("login.wrongcaptcha", 1);
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) {
$statsd->count("login.wronguser", 1);
throw new HTTPException("400", "Username or Password wrong");
}
if(!password_verify($request->input("password"), $user->password)) {
$statsd->count("login.wrongpassword", 1);
throw new HTTPException("400", "Username or Password wrong");
}
$app = App::query()->where("name", "=", "PHP-GUI")->firstOrFail()->id;
//Create Access Permission for WebGUI
$access = AppAccess::getOrCreate($user->id, $app);
$token = \App\Models\AccessToken::createToken($access);
//Save Token to Session
if(getenv("SAVE_TOKEN_TO_SESSION")) {
$_SESSION["token"] = $token->token;
}
$statsd->count("login.success", 1);
return $response->withData(new AccessToken($token));
}
public function checkPassword(Request $request, Response $response) {
//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");
}
$response->setMessage("Account ok");
return $response;
}
public function me(Response $response) {
if(!Auth::check()) {
throw new NotLoggedInException();
}
return $response->withData(new \App\Http\Resources\API\User(Auth::user()));
}
public function register(Request $request, Response $response) {
//If Recptache is enabled check it at the beginning
if(Setting::getSettingValue("recaptcha_v2_register")) {
$reCaptcha = new ReCaptcha(Setting::getSettingValue("recaptcha_v2_secret"));
$captchaResponse = $reCaptcha->verify($request->input("g-recaptcha-response"));
if(!$captchaResponse->isSuccess()) {
throw new HTTPException(400, "Captcha validation failed");
}
}
$invite = Invite::query()->where("code", "=", $request->input("invite"))->first();
if($invite != null) {
if($invite->status != "active") {
throw new HTTPException(400, "Invite code invalide");
}
if(!empty($invite->username) && $request->input("username") != $invite->username) {
throw new HTTPException(400, "Invalide username for invite");
}
} else {
$setting = Setting::query()->where("name", "=", "registration_possible")->firstOrFail();
if(!$setting->value) {
throw new HTTPException("400", "Registration disabled");
}
}
$this->validate($request, [
'username' => 'required|max:255|min:5|regex:@^[a-z0-9]*$@|unique:users',
'password' => 'required|min:8',
'mail' => 'required|email|unique:mails'
]);
DB::beginTransaction();
$user = new User();
$user->username = $request->input("username");
$user->password = password_hash($request->input("password"), PASSWORD_BCRYPT);
if($invite != null) {
$user->inviteCode = $invite->code;
}
//Make first user an admin
$count = User::query()->count("*");
if($count == 1) {
$user->admin = 1;
$user->developer = 1;
}
$user->saveOrFail();
$mail = new Mail();
$mail->createValidationToken();
$mail->mail = $request->input("mail");
$mail->primary = false;
$mail->status = "waiting";
$mail->user_id = $user->id;
$mail->saveOrFail();
$this->dispatch(new ValidateMailAddressJob($mail));
if($invite != null) {
$invite->status = "used";
$invite->saveOrFail();
}
DB::commit();
return $response->withData(new \App\Http\Resources\API\User($user));
}
/*
* 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);
}
public function getInviteCodeInfo(Request $request, Response $response) {
$data = [];
$invite = Invite::query()->where("code", "=", $request->input("code"))->first();
if($invite == null) {
throw new ResourceNotFound();
}
$usable = false;
if($invite->status == "active") {
$usable = true;
}
$data["usable"] = $usable;
#$data["status"] = $invite->status;
$data["username"] = $invite->username;
return $response->withData($data);
}
public function listMails(Response $response) {
if(!Auth::check()) {
throw new NotLoggedInException();
}
$mails = Mail::query()->where("user_id", "=", Auth::id())->get();
return $response->withData(\App\Http\Resources\API\Mail::collection(collect($mails)));
}
public function addMail(Request $request, Response $response) {
if(!Auth::check()) {
throw new NotLoggedInException();
}
$this->validate($request, [
'mail' => 'required|email|unique:mails'
]);
$mail = new Mail();
$mail->createValidationToken();
$mail->mail = $request->input("mail");
$mail->primary = false;
$mail->status = "waiting";
$mail->user_id = Auth::user()->id;
$mail->saveOrFail();
$this->dispatch(new ValidateMailAddressJob($mail));
return $response;
}
public function removeMail(Request $request, Response $response, $id) {
if(!Auth::check()) {
abort(401);
}
$mail = Mail::query()->where("id", "=", $id)->firstOrFail();
if($mail->user_id != Auth::user()->id) {
abort(401);
}
if($mail->primary) {
throw new HTTPException(400, "You can't delete your primary mail");
}
$mail->delete();
$response->setMessage("Mail address deleted");
return $response;
}
public function changePrimaryMail(Request $request, Response $response, $id) {
if(!Auth::check()) {
abort(401);
}
$mail = Mail::query()->where("id", "=", $id)->firstOrFail();
if($mail->user_id != Auth::user()->id) {
abort(401);
}
if($mail->status != "valide") {
throw new HTTPException("Mail not validated, click the link in the mail first");
}
$mails = Mail::query()->where("user_id", "=", Auth::user()->id)->get();
foreach($mails as $m) {
$m->primary = false;
$m->saveOrFail();
}
$mail->primary = true;
$mail->saveOrFail();
$response->setMessage("Primary mail changed");
return $response;
}
public function changePassword(Request $request, Response $response) {
if(!Auth::check()) {
abort(401);
}
$this->validate($request, [
'password' => 'required|min:8'
]);
$user = Auth::user();
$user->password = password_hash($request->input("password"), PASSWORD_BCRYPT);
$user->saveOrFail();
$response->setMessage("Password changed");
return $response;
}
}