2019-04-28 12:49:10 +00:00
|
|
|
<?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;
|
2019-04-28 15:04:22 +00:00
|
|
|
use App\Jobs\Mails\ValidateMailAddressJob;
|
2019-04-28 12:49:10 +00:00
|
|
|
use App\Models\App;
|
|
|
|
use App\Models\AppAccess;
|
2019-04-28 15:04:22 +00:00
|
|
|
use App\Models\Invite;
|
|
|
|
use App\Models\Mail;
|
2019-04-28 12:49:10 +00:00
|
|
|
use App\Models\Setting;
|
|
|
|
use App\Models\User;
|
2019-12-25 17:49:20 +00:00
|
|
|
use Domnikl\Statsd\Client;
|
2019-04-28 12:49:10 +00:00
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
use Illuminate\Http\Request;
|
2019-04-28 15:04:22 +00:00
|
|
|
use Illuminate\Support\Facades\DB;
|
2019-04-28 12:49:10 +00:00
|
|
|
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
|
|
|
|
*/
|
2019-12-25 17:49:20 +00:00
|
|
|
public function passwordLogin(Request $request, Response $response, Client $statsd)
|
2019-04-28 12:49:10 +00:00
|
|
|
{
|
2019-12-25 17:49:20 +00:00
|
|
|
$statsd->count("login.try", 1);
|
2019-04-28 12:49:10 +00:00
|
|
|
//If Recptache is enabled check it at the beginning
|
|
|
|
if(Setting::getSettingValue("recaptcha_v2_login")) {
|
|
|
|
$reCaptcha = new ReCaptcha(Setting::getSettingValue("recaptcha_v2_secret"));
|
2019-09-24 15:24:21 +00:00
|
|
|
$reresponse = $reCaptcha->verify($request->input("g-recaptcha-response"));
|
2019-04-28 12:49:10 +00:00
|
|
|
|
2019-09-24 15:24:21 +00:00
|
|
|
if(!$reresponse->isSuccess()) {
|
2019-12-25 17:49:20 +00:00
|
|
|
$statsd->count("login.wrongcaptcha", 1);
|
2019-04-28 12:49:10 +00:00
|
|
|
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) {
|
2019-12-25 17:49:20 +00:00
|
|
|
$statsd->count("login.wronguser", 1);
|
2019-04-28 12:49:10 +00:00
|
|
|
throw new HTTPException("400", "Username or Password wrong");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!password_verify($request->input("password"), $user->password)) {
|
2019-12-25 17:49:20 +00:00
|
|
|
$statsd->count("login.wrongpassword", 1);
|
2019-04-28 12:49:10 +00:00
|
|
|
throw new HTTPException("400", "Username or Password wrong");
|
|
|
|
}
|
|
|
|
|
2019-06-20 14:46:50 +00:00
|
|
|
$app = App::query()->where("name", "=", "PHP-GUI")->firstOrFail()->id;
|
|
|
|
|
2019-04-28 12:49:10 +00:00
|
|
|
//Create Access Permission for WebGUI
|
2019-06-20 14:46:50 +00:00
|
|
|
$access = AppAccess::getOrCreate($user->id, $app);
|
2019-04-28 12:49:10 +00:00
|
|
|
$token = \App\Models\AccessToken::createToken($access);
|
|
|
|
|
|
|
|
//Save Token to Session
|
2019-06-20 14:46:50 +00:00
|
|
|
if(getenv("SAVE_TOKEN_TO_SESSION")) {
|
|
|
|
$_SESSION["token"] = $token->token;
|
|
|
|
}
|
2019-04-28 12:49:10 +00:00
|
|
|
|
2019-12-25 17:49:20 +00:00
|
|
|
$statsd->count("login.success", 1);
|
|
|
|
|
2019-07-17 14:28:34 +00:00
|
|
|
return $response->withData(new AccessToken($token));
|
2019-04-28 12:49:10 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 17:41:55 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-06-06 13:44:45 +00:00
|
|
|
public function me(Response $response) {
|
|
|
|
if(!Auth::check()) {
|
|
|
|
throw new NotLoggedInException();
|
|
|
|
}
|
|
|
|
|
|
|
|
return $response->withData(new \App\Http\Resources\API\User(Auth::user()));
|
|
|
|
}
|
|
|
|
|
2019-04-28 12:49:10 +00:00
|
|
|
public function register(Request $request, Response $response) {
|
2019-04-28 15:04:22 +00:00
|
|
|
//If Recptache is enabled check it at the beginning
|
|
|
|
if(Setting::getSettingValue("recaptcha_v2_register")) {
|
|
|
|
$reCaptcha = new ReCaptcha(Setting::getSettingValue("recaptcha_v2_secret"));
|
2019-04-28 15:55:38 +00:00
|
|
|
$captchaResponse = $reCaptcha->verify($request->input("g-recaptcha-response"));
|
2019-04-28 15:04:22 +00:00
|
|
|
|
2019-04-28 15:55:38 +00:00
|
|
|
if(!$captchaResponse->isSuccess()) {
|
2019-04-28 15:04:22 +00:00
|
|
|
throw new HTTPException(400, "Captcha validation failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-28 15:55:38 +00:00
|
|
|
$invite = Invite::query()->where("code", "=", $request->input("invite"))->first();
|
|
|
|
if($invite != null) {
|
|
|
|
if($invite->status != "active") {
|
2019-09-25 07:56:36 +00:00
|
|
|
throw new HTTPException(400, "Invite code invalide");
|
2019-04-28 15:55:38 +00:00
|
|
|
}
|
|
|
|
if(!empty($invite->username) && $request->input("username") != $invite->username) {
|
2019-09-25 07:56:36 +00:00
|
|
|
throw new HTTPException(400, "Invalide username for invite");
|
2019-04-28 15:55:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$setting = Setting::query()->where("name", "=", "registration_possible")->firstOrFail();
|
|
|
|
if(!$setting->value) {
|
|
|
|
throw new HTTPException("400", "Registration disabled");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-28 15:04:22 +00:00
|
|
|
$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));
|
2019-04-28 12:49:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
}
|
2019-04-28 15:04:22 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2019-08-11 20:08:56 +00:00
|
|
|
|
|
|
|
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)));
|
|
|
|
}
|
2019-11-19 17:41:55 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-22 15:13:42 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2019-04-28 12:49:10 +00:00
|
|
|
}
|