Add Account creation

Add Aliases support
This commit is contained in:
Timothée Jaussoin 2020-04-21 17:34:18 +02:00
parent f3ba51682f
commit 641feb9a2e
16 changed files with 228 additions and 7 deletions

View file

@ -3,6 +3,7 @@ APP_ENV=local
APP_KEY= APP_KEY=
APP_DEBUG=false APP_DEBUG=false
APP_URL=http://localhost APP_URL=http://localhost
APP_SIP_DOMAIN=
LOG_CHANNEL=stack LOG_CHANNEL=stack

View file

@ -26,12 +26,18 @@ class Account extends Authenticatable
{ {
protected $connection = 'external'; protected $connection = 'external';
protected $with = ['passwords']; protected $with = ['passwords'];
protected $dates = ['creation_time'];
public function passwords() public function passwords()
{ {
return $this->hasMany('App\Password'); return $this->hasMany('App\Password');
} }
public function alias()
{
return $this->hasOne('App\Alias');
}
public function nonces() public function nonces()
{ {
return $this->hasMany('App\DigestNonce'); return $this->hasMany('App\DigestNonce');

17
flexiapi/app/Alias.php Normal file
View file

@ -0,0 +1,17 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Alias extends Model
{
protected $table = 'aliases';
protected $connection = 'external';
public $timestamps = false;
public function account()
{
return $this->belongsTo('App\Account');
}
}

View file

@ -47,4 +47,9 @@ class Utils
return hash($algos[$algorithm], $username.':'.$domain.':'.$password); return hash($algos[$algorithm], $username.':'.$domain.':'.$password);
} }
public static function generatePin()
{
return mt_rand(1000, 9999);
}
} }

View file

@ -6,12 +6,15 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use Carbon\Carbon;
use App\Account; use App\Account;
use App\Alias;
use App\Rules\SIP; use App\Rules\SIP;
use App\Helpers\Utils; use App\Helpers\Utils;
use App\Libraries\OvhSMS; use App\Libraries\OvhSMS;
use App\Mail\PasswordAuthentication; use App\Mail\PasswordAuthentication;
use App\Mail\RegisterConfirmation;
class AccountController extends Controller class AccountController extends Controller
{ {
@ -29,6 +32,57 @@ class AccountController extends Controller
return view('account.login'); return view('account.login');
} }
public function register(Request $request)
{
return view('account.register');
}
public function store(Request $request)
{
$request->validate([
'username' => 'required|unique:external.accounts,username|min:6',
'phone' => 'required_without:email|nullable|unique:external.aliases,alias|unique:external.accounts,username|starts_with:+|phone:AUTO',
'email' => 'required_without:phone|nullable|email|confirmed'
]);
$account = new Account;
$account->username = $request->get('username');
$account->email = $request->get('email');
$account->activated = false;
$account->domain = config('app.sip_domain');
$account->ip_address = $request->ip();
$account->creation_time = Carbon::now();
$account->user_agent = config('app.name');
$account->save();
if ($request->filled('phone')) {
$alias = new Alias;
$alias->alias = $request->get('phone');
$alias->domain = config('app.sip_domain');
$alias->account_id = $account->id;
$alias->save();
$account->confirmation_key = Utils::generatePin();
$account->save();
$ovhSMS = new OvhSMS;
$ovhSMS->send($request->get('phone'), 'Your '.config('app.name').' validation code is '.$account->confirmation_key);
return view('account.authenticate_phone', [
'account' => $account
]);
}
$account->confirmation_key = Str::random($this->emailCodeSize);
$account->save();
Mail::to($account)->send(new RegisterConfirmation($account));
return view('account.authenticate_email', [
'account' => $account
]);
}
public function delete(Request $request) public function delete(Request $request)
{ {
return view('account.delete', [ return view('account.delete', [
@ -103,6 +157,12 @@ class AccountController extends Controller
$account->save(); $account->save();
Auth::login($account); Auth::login($account);
// Ask the user to set a password
if (!$account->activated) {
return redirect()->route('account.password');
}
return redirect()->route('account.index'); return redirect()->route('account.index');
} }
@ -117,7 +177,14 @@ class AccountController extends Controller
$account = Account::where('username', $request->get('phone'))->first(); $account = Account::where('username', $request->get('phone'))->first();
// TODO add alias // Try alias
if (!$account) {
$alias = Alias::where('alias', $request->get('phone'))->first();
if ($alias) {
$account = $alias->account;
}
}
if (!$account) { if (!$account) {
return view('account.login_phone')->withErrors([ return view('account.login_phone')->withErrors([
@ -125,11 +192,16 @@ class AccountController extends Controller
]); ]);
} }
$account->confirmation_key = mt_rand(1000, 9999); $account->confirmation_key = Utils::generatePin();
$account->save(); $account->save();
$ovhSMS = new OvhSMS; $ovhSMS = new OvhSMS;
$ovhSMS->send($request->get('phone'), 'Your Linphone validation code is '.$account->confirmation_key); $ovhSMS->send($request->get('phone'), 'Your '.config('app.name').' validation code is '.$account->confirmation_key);
// Ask the user to set a password
if (!$account->activated) {
return redirect()->route('account.password');
}
return view('account.authenticate_phone', [ return view('account.authenticate_phone', [
'account' => $account 'account' => $account

View file

@ -24,6 +24,9 @@ class AccountPasswordController extends Controller
]); ]);
$account = $request->user(); $account = $request->user();
$account->activated = true;
$account->save();
$algorithm = $request->has('password_sha256') ? 'SHA-256' : 'MD5'; $algorithm = $request->has('password_sha256') ? 'SHA-256' : 'MD5';
if ($account->passwords()->count() > 0) { if ($account->passwords()->count() > 0) {

View file

@ -0,0 +1,31 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use App\Account;
class RegisterConfirmation extends Mailable
{
use Queueable, SerializesModels;
private $_account;
public function __construct(Account $account)
{
$this->_account = $account;
}
public function build()
{
return $this->view('mails.register_confirmation')
->text('mails.register_confirmation_text')
->with([
'link' => route('account.authenticate_email_confirm', [$this->_account->confirmation_key])
]);
}
}

View file

@ -14,6 +14,7 @@ return [
*/ */
'name' => env('APP_NAME', 'Laravel'), 'name' => env('APP_NAME', 'Laravel'),
'sip_domain' => env('APP_SIP_DOMAIN', 'sip.domain.com'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View file

@ -4,6 +4,10 @@
@if (Auth::check()) @if (Auth::check())
@include('parts.already_auth') @include('parts.already_auth')
@else @else
<p>A unique authentication link was sent by email to {{ $account->email }}</p> @if ($account->activated)
<p>A unique authentication link was sent by email to <b>{{ $account->email }}</b></p>
@else
<p>To finish your registration process and set a password please follow the link sent on your email addres <b>{{ $account->email }}</b></p>
@endif
@endif @endif
@endsection @endsection

View file

@ -15,10 +15,22 @@
{!! Form::label('password', 'Password') !!} {!! Form::label('password', 'Password') !!}
{!! Form::password('password', ['class' => 'form-control', 'placeholder' => 'myPassword', 'required']) !!} {!! Form::password('password', ['class' => 'form-control', 'placeholder' => 'myPassword', 'required']) !!}
</div> </div>
{!! Form::submit('Authenticate', ['class' => 'btn btn-primary']) !!}
<div class="form-row">
<div class="form-group col-md-6">
{!! Form::submit('Authenticate', ['class' => 'btn btn-primary']) !!}
</div>
<div class="form-group col-md-6">
<p class="mb-1 text-right">
No account yet?
<a class="btn btn-secondary ml-2" href="{{ route('account.register') }}">Register
</a>
</p>
</div>
</div>
{!! Form::close() !!} {!! Form::close() !!}
<br />
<p>You can also authenticate using your <a href="{{ route('account.login_email') }}">Email address</a> or your <a href="{{ route('account.login_phone') }}">Phone number</a></p> <p>You can also authenticate using your <a href="{{ route('account.login_email') }}">Email address</a> or your <a href="{{ route('account.login_phone') }}">Phone number</a></p>
</div> </div>
</div> </div>

View file

@ -0,0 +1,38 @@
@extends('layouts.account')
@section('content')
<h2>Register a new account</h2>
{!! Form::open(['route' => 'account.store']) !!}
<p>Fill a username and an email address OR phone number, you will then be able to set a password to finish the registration process.</p>
<div class="form-group">
{!! Form::label('username', 'Username') !!}
{!! Form::text('username', old('username'), ['class' => 'form-control', 'placeholder' => 'username', 'required']) !!}
</div>
<hr />
<div class="form-row">
<div class="form-group col-md-6">
{!! Form::label('email', 'New email') !!}
{!! Form::email('email', old('email'), ['class' => 'form-control', 'placeholder' => 'username@server.com']) !!}
</div>
<div class="form-group col-md-6">
{!! Form::label('email_confirmation', 'Email confirmation') !!}
{!! Form::email('email_confirmation', old('email_confirm'), ['class' => 'form-control', 'placeholder' => 'username@server.com']) !!}
</div>
</div>
<h2 class="text-center mb-0">OR</h2>
<div class="form-group">
{!! Form::label('phone', 'Phone number') !!}
{!! Form::text('phone', old('phone'), ['class' => 'form-control', 'placeholder' => '+123456789']) !!}
</div>
{!! Form::submit('Register', ['class' => 'btn btn-primary float-right']) !!}
{!! Form::close() !!}
@endsection

View file

@ -0,0 +1,19 @@
<html>
<head>
<title>Register on {{ config('app.name') }}</title>
</head>
<body>
<p>Hello,</p>
<p>
You just created an account on {{ config('app.name') }} using your email account.<br />
Please follow the unique link bellow to finish the registration process.
</p>
<p>
<a href="{{ $link }}">{{ $link }}</a>
</p>
<p>
Regards,<br />
The Linphone team.
</p>
</body>
</html>

View file

@ -0,0 +1,9 @@
Hello,
You just created an account on {{ config('app.name') }} using your email account.
Please follow the unique link bellow to finish the registration process.
{{ $link }}
Regards,
The Linphone team.

View file

@ -1,6 +1,6 @@
@if (isset($errors) && $errors->any()) @if (isset($errors) && $errors->any())
<div class="alert alert-danger"> <div class="alert alert-danger">
<ul class="mb-0"> <ul class="mb-0 pl-2">
@foreach ($errors->all() as $error) @foreach ($errors->all() as $error)
<li>{{ $error }}</li> <li>{{ $error }}</li>
@endforeach @endforeach

View file

@ -30,6 +30,9 @@ Route::get('login/phone', 'AccountController@loginPhone')->name('account.login_p
Route::post('authenticate/phone', 'AccountController@authenticatePhone')->name('account.authenticate_phone'); Route::post('authenticate/phone', 'AccountController@authenticatePhone')->name('account.authenticate_phone');
Route::post('authenticate/phone/confirm', 'AccountController@authenticatePhoneConfirm')->name('account.authenticate_phone_confirm'); Route::post('authenticate/phone/confirm', 'AccountController@authenticatePhoneConfirm')->name('account.authenticate_phone_confirm');
Route::get('register', 'AccountController@register')->name('account.register');
Route::post('register', 'AccountController@store')->name('account.store');
Route::group(['middleware' => 'auth'], function () { Route::group(['middleware' => 'auth'], function () {
Route::get('/', 'AccountController@index')->name('account.index'); Route::get('/', 'AccountController@index')->name('account.index');
Route::get('logout', 'AccountController@logout')->name('account.logout'); Route::get('logout', 'AccountController@logout')->name('account.logout');