728 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			728 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace App\Http\Controllers;
 | 
						|
 | 
						|
use Illuminate\Support\Facades\Auth;
 | 
						|
use Illuminate\Support\Facades\Storage;
 | 
						|
use Illuminate\Http\Request;
 | 
						|
 | 
						|
use App\Account;
 | 
						|
use App\Alias;
 | 
						|
use App\Domain;
 | 
						|
use App\DomainUser;
 | 
						|
use App\TlsPolicy;
 | 
						|
use App\User;
 | 
						|
use App\DovecotPw;
 | 
						|
use App\Entropy;
 | 
						|
 | 
						|
use Illuminate\Validation\ValidationException;
 | 
						|
use Illuminate\Database\Eloquent\ModelNotFoundException;
 | 
						|
use App\Exceptions\PermissionException;
 | 
						|
use App\Exceptions\ErrorException;
 | 
						|
use Illuminate\Validation\Rule;
 | 
						|
 | 
						|
 | 
						|
class VMailController extends Controller
 | 
						|
{
 | 
						|
    const MinimumEntropy = 50;
 | 
						|
    /**
 | 
						|
     * Create a new controller instance.
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public function __construct()
 | 
						|
    {
 | 
						|
        $this->middleware('auth');
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Show the application dashboard.
 | 
						|
     *
 | 
						|
     * @return \Illuminate\Contracts\Support\Renderable
 | 
						|
     */
 | 
						|
    public function index()
 | 
						|
    {
 | 
						|
        if(Auth::user()->hasRole('admin'))
 | 
						|
        {
 | 
						|
            $domains = Domain::all();
 | 
						|
            return view('layouts/vmail',['domains' => $domains]);
 | 
						|
        }
 | 
						|
        elseif(Auth::user()->hasRole('user'))
 | 
						|
        {
 | 
						|
            $domains = Auth::user()->cards;
 | 
						|
            return view('layouts/vmail',['domains' => $domains]);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            return view('layouts/unverified',);
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        return view('layouts/vmail',['domains' => $domains]);
 | 
						|
    }
 | 
						|
 | 
						|
    public function domainsAjax(Request $request)
 | 
						|
    {
 | 
						|
        $action = $request->input('action');
 | 
						|
        try
 | 
						|
        {
 | 
						|
            // block unverified users
 | 
						|
            if(!(Auth::user()->hasRole('admin') || Auth::user()->hasRole('user'))){
 | 
						|
                throw PermissionException('Not Authorized');
 | 
						|
            }
 | 
						|
 | 
						|
            if($action == 'create')
 | 
						|
            {
 | 
						|
                if(!(Auth::user()->hasRole('admin'))) { throw PermissionException('Not Authorized');}
 | 
						|
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string', 'unique:App\Domain,domain'],
 | 
						|
                ]);
 | 
						|
                $domain = new Domain();
 | 
						|
                $domain->domain = $validatedData['domain'];
 | 
						|
                $domain->save();
 | 
						|
                $domain->users()->attach(Auth::user()->id,['role' => 'own']);
 | 
						|
 | 
						|
                return [$domain];
 | 
						|
            }
 | 
						|
            elseif($action == 'rename')
 | 
						|
            {
 | 
						|
                if(!(Auth::user()->hasRole('admin'))) { throw PermissionException('Not Authorized');}
 | 
						|
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string', 'exists:App\Domain,domain'],
 | 
						|
                    'newname' => ['required', 'string', 'unique:App\Domain,domain'],
 | 
						|
                ]);
 | 
						|
 | 
						|
                $domain = Domain::where('domain',$validatedData['domain'])->first();
 | 
						|
 | 
						|
                $accounts = $domain->accounts;
 | 
						|
                $aliases = $domain->aliases;
 | 
						|
                $users = $domain->users;
 | 
						|
 | 
						|
                foreach($users as $u)
 | 
						|
                {
 | 
						|
                    $domain->users()->detach($u->id);
 | 
						|
                }
 | 
						|
 | 
						|
                $domain->domain = $validatedData['newname'];
 | 
						|
                $domain->save();
 | 
						|
 | 
						|
                foreach($accounts as $a)
 | 
						|
                {
 | 
						|
                    $a->domain()->associate($domain);
 | 
						|
                    $a->save();
 | 
						|
                }
 | 
						|
 | 
						|
                foreach($aliases as $a)
 | 
						|
                {
 | 
						|
                    $a->source_domain()->associate($domain);
 | 
						|
                    $a->save();
 | 
						|
                }
 | 
						|
 | 
						|
                foreach($users as $u)
 | 
						|
                {
 | 
						|
                    $domain->users()->attach($u->id);
 | 
						|
                }
 | 
						|
                $domain->save();
 | 
						|
 | 
						|
                return [$domain];
 | 
						|
            }
 | 
						|
            elseif($action == 'drop')
 | 
						|
            {
 | 
						|
                if(!(Auth::user()->hasRole('admin'))) { throw PermissionException('Not Authorized');}
 | 
						|
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string', 'exists:App\Domain,domain'],
 | 
						|
                ]);
 | 
						|
                $domain = Domain::where('domain',$validatedData['domain'])->first();
 | 
						|
 | 
						|
                // remove all aliases and accounts related to this domain
 | 
						|
                $domain->delete();
 | 
						|
                foreach(Account::where('domain',$validatedData['domain'])->get() as $a){
 | 
						|
                    $a->delete();
 | 
						|
                }
 | 
						|
                foreach(Alias::where('source_domain',$validatedData['domain'])->get() as $a){
 | 
						|
                    $a->delete();
 | 
						|
                }
 | 
						|
 | 
						|
                return true;
 | 
						|
            }            
 | 
						|
            elseif($action == 'listadmins')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string', 'exists:App\Domain,domain'],
 | 
						|
                ]);
 | 
						|
                $domain = Domain::where('domain',$validatedData['domain'])->first();
 | 
						|
                if(!Auth::user()->hasRole('admin')){
 | 
						|
                    // if not an admin, check if edit roles are enabled for this domain
 | 
						|
                    $domain->needRole('edit'); // throws exception if curren user does not have this role
 | 
						|
                }
 | 
						|
                return $domain->users;
 | 
						|
 | 
						|
            }
 | 
						|
            elseif($action == 'setadmin')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string', 'exists:App\Domain,domain'],
 | 
						|
                    'userid' => ['required', 'int', 'exists:App\User,id'],
 | 
						|
                    'role' => ['required', 'string','in:own,edit,view'],
 | 
						|
                ]);
 | 
						|
                $domain = Domain::where('domain',$validatedData['domain'])->first();
 | 
						|
                if(!Auth::user()->hasRole('admin')){
 | 
						|
                    // if not an admin, check if edit roles are enabled for this domain
 | 
						|
                    $domain->needRole('own'); // throws exception if curren user does not have this role
 | 
						|
                
 | 
						|
                    if($validatedData['userid'] == Auth::user()->id)
 | 
						|
                    {
 | 
						|
                        throw ValidationException('Cannot edit own ownership');
 | 
						|
                    } 
 | 
						|
                }
 | 
						|
 | 
						|
                $domain->users()->attach($validatedData['userid'],['role' => $validatedData['userid']]);
 | 
						|
                $domain->save();
 | 
						|
 | 
						|
                return true;
 | 
						|
 | 
						|
            }
 | 
						|
            elseif($action == 'deladmin')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string', 'exists:App\Domain,domain'],
 | 
						|
                    'userid' => ['required', 'int', 'exists:App\User,id'],
 | 
						|
                ]);
 | 
						|
                $domain = Domain::where('domain',$validatedData['domain'])->first();
 | 
						|
                if(!Auth::user()->hasRole('admin')){
 | 
						|
                    // if not an admin, check if edit roles are enabled for this domain
 | 
						|
                    $domain->needRole('own'); // throws exception if curren user does not have this role
 | 
						|
 | 
						|
                    if($validatedData['userid'] == Auth::user()->id)
 | 
						|
                    {
 | 
						|
                        throw ValidationException('Cannot remove own ownership');
 | 
						|
                    } 
 | 
						|
                }
 | 
						|
                $domain->users()->detach($validatedData['userid']);
 | 
						|
                $domain->save();
 | 
						|
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
 | 
						|
            elseif($action == 'listusers')
 | 
						|
            {
 | 
						|
                $users = User::all();
 | 
						|
                return $users;
 | 
						|
            }               
 | 
						|
            elseif($action == 'list')
 | 
						|
            {
 | 
						|
                if(Auth::user()->hasRole('admin'))
 | 
						|
                {
 | 
						|
                    $domains = Domain::all();
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    $domains = Auth::user()->cards;
 | 
						|
                }
 | 
						|
                return $domains;
 | 
						|
            }   
 | 
						|
            else
 | 
						|
            {
 | 
						|
                return response(['fail' => 'action', 'errors' => ['Action unknown: '. $action]],400);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        catch(ValidationException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'validation', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
        catch(PermissionException $x)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'role', 'errors' => ['Action requires role '. $x->role()]],403);
 | 
						|
        }
 | 
						|
        catch(ErrorException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'errors', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function tlsAjax(Request $request)
 | 
						|
    {
 | 
						|
        $action = $request->input('action');
 | 
						|
        try
 | 
						|
        {
 | 
						|
            // allow only admin
 | 
						|
            if(!(Auth::user()->hasRole('admin'))) { throw PermissionException('Not Authorized');}        
 | 
						|
 | 
						|
 | 
						|
            if($action == 'list')
 | 
						|
            {
 | 
						|
                $policies = TlsPolicy::all();
 | 
						|
                return $policies;
 | 
						|
            }   
 | 
						|
            elseif($action == 'getpolicy')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string',],
 | 
						|
                ]);
 | 
						|
                $domain = Domain::where('domain',$validatedData['domain'])->first();
 | 
						|
                $tlspolicy = $domain->tlspolicy;
 | 
						|
                if(empty($tlspolicy)) {
 | 
						|
                    return ['policy' => 'null', 'params' => ''];
 | 
						|
                } else {
 | 
						|
                    return $tlspolicy;
 | 
						|
                }
 | 
						|
                return response(['fail' => 'action', 'errors' => ["Unauthorized for domain '{$validatedData['domain']}'"]],403);
 | 
						|
            }       
 | 
						|
            elseif($action == 'setpolicy')
 | 
						|
            {
 | 
						|
                 $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string', ],
 | 
						|
                    'policy' => ['required', 'string','in:null,none,may,encrypt,dane,dane-only,fingerprint,verify,secure'],
 | 
						|
                    'params' => ['nullable','string'],
 | 
						|
                ]);
 | 
						|
            
 | 
						|
                $tlspolicy = TlsPolicy::where('domain',$validatedData['domain'])->first();
 | 
						|
                if($tlspolicy == null){
 | 
						|
                    $tlspolicy = new TlsPolicy(['domain' => $validatedData['domain'],
 | 
						|
                                            'policy' => $validatedData['policy'],
 | 
						|
                                            'params' => $validatedData['params'] ]);
 | 
						|
                    $tlspolicy->save();
 | 
						|
                }
 | 
						|
                else {
 | 
						|
 | 
						|
                    $tlspolicy->policy = $validatedData['policy'];
 | 
						|
                    $tlspolicy->params = $validatedData['params'];
 | 
						|
                    $tlspolicy->save();
 | 
						|
                }
 | 
						|
                return $tlspolicy;
 | 
						|
            }                                
 | 
						|
            elseif($action == 'delpolicy')
 | 
						|
            {
 | 
						|
                 $validatedData = $request->validate([
 | 
						|
                    'domain' => ['required', 'string', 'exists:App\TlsPolicy,domain' ],
 | 
						|
                ]);
 | 
						|
            
 | 
						|
                $tlspolicy = TlsPolicy::where('domain',$validatedData['domain'])->first();
 | 
						|
                $tlspolicy->delete();
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                return response(['fail' => 'action', 'errors' => ['Action unknown: '. $action]],400);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        catch(ValidationException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'validation', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
        catch(PermissionException $x)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'role', 'errors' => ['Action requires role '. $x->role()]],403);
 | 
						|
        }
 | 
						|
        catch(ErrorException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'errors', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function accountsAjax(Request $request)
 | 
						|
    {
 | 
						|
        $action = $request->input('action');
 | 
						|
        try
 | 
						|
        {
 | 
						|
            // block unverified users
 | 
						|
            if(!(Auth::user()->hasRole('admin') || Auth::user()->hasRole('user'))){
 | 
						|
                throw PermissionException('Not Authorized');
 | 
						|
            }
 | 
						|
 | 
						|
            $firstValidatedData = $request->validate([
 | 
						|
                'domain' => ['required', 'string', 'exists:App\Domain,domain'],
 | 
						|
            ]);
 | 
						|
            $domain = Domain::where('domain',$firstValidatedData['domain'])->first();
 | 
						|
            if(!Auth::user()->hasRole('admin')){
 | 
						|
                // if not an admin, check if edit roles are enabled for this domain
 | 
						|
                $domain->needRole('edit'); // throws exception if curren user does not have this role
 | 
						|
            }
 | 
						|
            if($action == 'create')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'username' => ['required', 'string',],
 | 
						|
                    'enabled' => ['required', 'boolean',],
 | 
						|
                    'sendonly' => ['required', 'boolean',],
 | 
						|
                    'quota' => ['required', 'integer',],
 | 
						|
                    'password' => ['required', 'string',],
 | 
						|
                ]);
 | 
						|
                
 | 
						|
                if(Account::where('username',$validatedData['username'])->where('domain', $firstValidatedData['domain'])->count() > 0){
 | 
						|
                    throw new  ValidationException('Account already exists');
 | 
						|
                }
 | 
						|
 | 
						|
                // encode password
 | 
						|
                if(Entropy::Calculate($validatedData['password']) < static::MinimumEntropy) {
 | 
						|
                    throw new  ValidationException('Password is not complex enough');
 | 
						|
                }                
 | 
						|
                $hash = DovecotPw::Encrypt($validatedData['password']);
 | 
						|
 | 
						|
                $account = Account::Create([
 | 
						|
                    'username' => $validatedData['username'],
 | 
						|
                    'domain' => $firstValidatedData['domain'],
 | 
						|
                    'enabled' => $validatedData['enabled'],
 | 
						|
                    'sendonly' => $validatedData['sendonly'],
 | 
						|
                    'quota' => $validatedData['quota'],
 | 
						|
                    'password' => $hash,
 | 
						|
                ]);
 | 
						|
                $account->save();
 | 
						|
 | 
						|
                return [$account];
 | 
						|
            }
 | 
						|
            elseif($action == 'checkusername')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'username' => ['required', 'string', ''],
 | 
						|
                    'id' => ['nullable','integer'],
 | 
						|
                ]);
 | 
						|
                if(!empty($validatedData['id']))
 | 
						|
                {
 | 
						|
                    $a = Account::Find($validatedData['id']);
 | 
						|
                    if($validatedData['username'] == $a->username) {
 | 
						|
                        return true;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                
 | 
						|
                return (Account::where('domain',$domain->domain)->where('username',$validatedData['username'])->count() == 0);
 | 
						|
            }
 | 
						|
            elseif($action == 'list')
 | 
						|
            {
 | 
						|
                $accounts = $domain->accounts;
 | 
						|
                return $accounts;
 | 
						|
            }
 | 
						|
            elseif($action == 'update')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'id' => ['required','integer'],
 | 
						|
                    'username' => ['nullable', 'string',],
 | 
						|
                    'enabled' => ['required', 'boolean',],
 | 
						|
                    'sendonly' => ['required', 'boolean',],
 | 
						|
                    'quota' => ['required', 'integer',],
 | 
						|
                    'password' => ['nullable', 'string',],
 | 
						|
                ]);
 | 
						|
 | 
						|
                $account = Account::Find($validatedData['id']);
 | 
						|
 | 
						|
                if(!empty($validatedData['username']) && $validatedData['username'] != $account->username)
 | 
						|
                {
 | 
						|
                    if((Account::where('domain',$domain)->where('username',$validatedData['username'])->count()) == 0)
 | 
						|
                    {
 | 
						|
                        $account->username = $validatedData['username'];
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                $account->enabled = $validatedData['enabled'];
 | 
						|
                $account->sendonly = $validatedData['sendonly'];
 | 
						|
                $account->quota = $validatedData['quota'];
 | 
						|
 | 
						|
                if(!empty($validatedData['password']))
 | 
						|
                {
 | 
						|
                    if(Entropy::Calculate($validatedData['password']) < static::MinimumEntropy) {
 | 
						|
                        throw new  ValidationException('Password is not complex enough');
 | 
						|
                    }
 | 
						|
                    // encode password
 | 
						|
                    $hash = DovecotPw::Encrypt($validatedData['password']);
 | 
						|
                    $account->password = $hash;
 | 
						|
                }
 | 
						|
                $account->save();
 | 
						|
 | 
						|
                return [$account,$hash];
 | 
						|
            }
 | 
						|
            elseif($action == 'delete')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'id' => ['required','integer'],
 | 
						|
                ]);
 | 
						|
                $account = Account::Find($validatedData['id']);
 | 
						|
                $account->delete();
 | 
						|
                return [];
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                return response(['fail' => 'action', 'errors' => ['Action unknown: '. $action]],400);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        catch(ValidationException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'validation', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
        catch(PermissionException $x)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'role', 'errors' => ['Action requires role '. $x->role()]],403);
 | 
						|
        }
 | 
						|
        catch(ErrorException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'errors', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function siteAccountsAjax(Request $request)
 | 
						|
    {
 | 
						|
        $action = $request->input('action');
 | 
						|
        try
 | 
						|
        {
 | 
						|
            // Allow only admin
 | 
						|
            if(!(Auth::user()->hasRole('admin'))) { throw PermissionException('Not Authorized');}        
 | 
						|
 | 
						|
            if($action == 'create')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'username' => ['required', 'string',],
 | 
						|
                    'enabled' => ['required', 'boolean',],
 | 
						|
                    'sendonly' => ['required', 'boolean',],
 | 
						|
                    'quota' => ['required', 'integer',],
 | 
						|
                    'password' => ['required', 'string',],
 | 
						|
                ]);
 | 
						|
                if(Account::where('username',$validatedData['username'])->where('domain', '')->count() > 0){
 | 
						|
                    throw new  ValidationException('Account already exists');
 | 
						|
                }
 | 
						|
 | 
						|
                // encode password
 | 
						|
                if(Entropy::Calculate($validatedData['password']) < static::MinimumEntropy) {
 | 
						|
                    throw new  ValidationException('Password is not complex enough');
 | 
						|
                }                
 | 
						|
                $hash = DovecotPw::Encrypt($validatedData['password']);
 | 
						|
 | 
						|
                $account = Account::Create([
 | 
						|
                    'username' => $validatedData['username'],
 | 
						|
                    'domain' => "localhost",
 | 
						|
                    'enabled' => $validatedData['enabled'],
 | 
						|
                    'sendonly' => $validatedData['sendonly'],
 | 
						|
                    'quota' => $validatedData['quota'],
 | 
						|
                    'password' => $hash,
 | 
						|
                ]);
 | 
						|
                $account->save();
 | 
						|
 | 
						|
                return [$account];
 | 
						|
            }
 | 
						|
            elseif($action == 'checkusername')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'username' => ['required', 'string', ''],
 | 
						|
                    'id' => ['nullable','integer'],
 | 
						|
                ]);
 | 
						|
                if(!empty($validatedData['id']))
 | 
						|
                {
 | 
						|
                    $a = Account::Find($validatedData['id']);
 | 
						|
                    if($validatedData['username'] == $a->username) {
 | 
						|
                        return true;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                
 | 
						|
                return (Account::where('domain',"localhost")->where('username',$validatedData['username'])->count() == 0);
 | 
						|
            }
 | 
						|
            elseif($action == 'list')
 | 
						|
            {
 | 
						|
                $accounts = Account::where('domain',"localhost")->get();
 | 
						|
                return $accounts;
 | 
						|
            }
 | 
						|
            elseif($action == 'update')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'id' => ['required','integer'],
 | 
						|
                    'username' => ['nullable', 'string',],
 | 
						|
                    'enabled' => ['required', 'boolean',],
 | 
						|
                    'sendonly' => ['required', 'boolean',],
 | 
						|
                    'quota' => ['required', 'integer',],
 | 
						|
                    'password' => ['nullable', 'string',],
 | 
						|
                ]);
 | 
						|
 | 
						|
                $account = Account::Find($validatedData['id']);
 | 
						|
 | 
						|
                if(!empty($validatedData['username']) && $validatedData['username'] != $account->username)
 | 
						|
                {
 | 
						|
                    if((Account::where('domain',"localhost")->where('username',$validatedData['username'])->count()) == 0)
 | 
						|
                    {
 | 
						|
                        $account->username = $validatedData['username'];
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                $account->enabled = $validatedData['enabled'];
 | 
						|
                $account->sendonly = $validatedData['sendonly'];
 | 
						|
                $account->quota = $validatedData['quota'];
 | 
						|
 | 
						|
                if(!empty($validatedData['password']))
 | 
						|
                {
 | 
						|
                    if(Entropy::Calculate($validatedData['password']) < static::MinimumEntropy) {
 | 
						|
                        throw new  ValidationException('Password is not complex enough');
 | 
						|
                    }
 | 
						|
                    // encode password
 | 
						|
                    $hash = DovecotPw::Encrypt($validatedData['password']);
 | 
						|
                    $account->password = $hash;
 | 
						|
                }
 | 
						|
                $account->save();
 | 
						|
 | 
						|
                return [$account,$hash];
 | 
						|
            }
 | 
						|
            elseif($action == 'delete')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'id' => ['required','integer'],
 | 
						|
                ]);
 | 
						|
                $account = Account::Find($validatedData['id']);
 | 
						|
                $account->delete();
 | 
						|
                return [];
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                return response(['fail' => 'action', 'errors' => ['Action unknown: '. $action]],400);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        catch(ValidationException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'validation', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
        catch(PermissionException $x)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'role', 'errors' => ['Action requires role '. $x->role()]],403);
 | 
						|
        }
 | 
						|
        catch(ErrorException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'errors', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private function tidyAliases($aliases)
 | 
						|
    {
 | 
						|
        // figure out how to merge 
 | 
						|
 | 
						|
        $a_list = [];
 | 
						|
 | 
						|
        foreach($aliases as $a)
 | 
						|
        {
 | 
						|
            if(empty($a_list[$a->source_username]))
 | 
						|
            {
 | 
						|
                $a_list[$a->source_username] = new \stdClass;
 | 
						|
                $a_list[$a->source_username]->source = $a->source_username;
 | 
						|
                $a_list[$a->source_username]->dest = [];
 | 
						|
            }
 | 
						|
            
 | 
						|
            $a->destination = empty($a->destination_domain)?($a->destination_username):($a->destination_username.'@'.$a->destination_domain);
 | 
						|
            $a_list[$a->source_username]->dest[] = $a;
 | 
						|
        }
 | 
						|
 | 
						|
        return array_values($a_list);
 | 
						|
    }
 | 
						|
 | 
						|
    public function aliasesAjax(Request $request)
 | 
						|
    {
 | 
						|
        $action = $request->input('action');
 | 
						|
        try
 | 
						|
        {
 | 
						|
            // block unverified users
 | 
						|
            if(!(Auth::user()->hasRole('admin') || Auth::user()->hasRole('user'))){
 | 
						|
                throw PermissionException('Not Authorized');
 | 
						|
            }
 | 
						|
 | 
						|
            $firstValidatedData = $request->validate([
 | 
						|
                'domain' => ['required', 'string', 'exists:App\Domain,domain'],
 | 
						|
            ]);
 | 
						|
            $domain = Domain::where('domain',$firstValidatedData['domain'])->first();
 | 
						|
            if(!Auth::user()->hasRole('admin')){
 | 
						|
                // if not an admin, check if edit roles are enabled for this domain
 | 
						|
                $domain->needRole('edit'); // throws exception if curren user does not have this role
 | 
						|
            }
 | 
						|
            if($action == 'checksource')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'source' => ['required', 'string', ''],
 | 
						|
                    'id' => ['nullable','integer'],
 | 
						|
                ]);
 | 
						|
                if(!empty($validatedData['id']))
 | 
						|
                {
 | 
						|
                    $a = Alias::Find($validatedData['id']);
 | 
						|
                    if($validatedData['source_username'] == $a->source) {
 | 
						|
                        return true;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                return (Alias::where('source_domain',$domain->domain)->where('source_username',$validatedData['source'])->count() == 0);
 | 
						|
            }
 | 
						|
            elseif($action == 'list')
 | 
						|
            {
 | 
						|
                return $this->tidyAliases($domain->aliases);
 | 
						|
            }
 | 
						|
            elseif($action == 'add_dest')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'source' => ['required','string'],
 | 
						|
                    'destination' => ['nullable', 'string',],
 | 
						|
                    'enabled' => ['required', 'boolean',],
 | 
						|
                    'comment' => ['nullable', 'string',],
 | 
						|
                ]);
 | 
						|
 | 
						|
                $dparts = explode('@',$validatedData['destination'],2);
 | 
						|
                $a = Alias::Create([
 | 
						|
                    'source_username' => $validatedData['source'],
 | 
						|
                    'source_domain' => $domain->domain,
 | 
						|
                    'destination_username' => $dparts[0],
 | 
						|
                    'destination_domain' => isset($dparts[1])?$dparts[1]:null,
 | 
						|
                    'enabled' => $validatedData['enabled'],
 | 
						|
                    'comment' => $validatedData['comment'],
 | 
						|
                ]);
 | 
						|
                $a->save();
 | 
						|
 | 
						|
                return $this->tidyAliases([$a]);
 | 
						|
            }
 | 
						|
            elseif($action == 'update_dest')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'id' => ['required','integer'],
 | 
						|
                    'destination' => ['nullable', 'string',],
 | 
						|
                    'enabled' => ['required', 'boolean',],
 | 
						|
                    'comment' => ['nullable', 'string',],
 | 
						|
                ]);
 | 
						|
 | 
						|
                $a = Alias::Find($validatedData['id']);
 | 
						|
 | 
						|
                $dparts = explode('@',$validatedData['destination'],2);
 | 
						|
                $a->destination_username = $dparts[0];
 | 
						|
                $a->destination_domain = isset($dparts[1])?$dparts[1]:null;
 | 
						|
                $a->enabled = $validatedData['enabled'];
 | 
						|
                $a->comment = $validatedData['comment'];
 | 
						|
 | 
						|
                $a->save();
 | 
						|
 | 
						|
                return $this->tidyAliases([$a]);
 | 
						|
            }
 | 
						|
            elseif($action == 'delete_dest')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'id' => ['required','integer'],
 | 
						|
                ]);
 | 
						|
                $a = Alias::Find($validatedData['id']);
 | 
						|
                $a->delete();
 | 
						|
                return [];
 | 
						|
            }
 | 
						|
            elseif($action == 'delete_src')
 | 
						|
            {
 | 
						|
                $validatedData = $request->validate([
 | 
						|
                    'source' => ['required','string'],
 | 
						|
                ]);
 | 
						|
                $aliases = Alias::where('source_domain',$domain->domain)->where('source_username',$validatedData['source']);
 | 
						|
                foreach($aliases as $a)
 | 
						|
                {
 | 
						|
                    $a->delete();
 | 
						|
                }
 | 
						|
                return [];
 | 
						|
            }            
 | 
						|
            else
 | 
						|
            {
 | 
						|
                return response(['fail' => 'action', 'errors' => ['Action unknown: '. $action]],400);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        catch(ValidationException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'validation', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
        catch(PermissionException $x)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'role', 'errors' => ['Action requires role '. $x->role()]],403);
 | 
						|
        }
 | 
						|
        catch(ErrorException $v)
 | 
						|
        {
 | 
						|
            return response(['fail' => 'errors', 'errors' => $v->errors()],400);
 | 
						|
        }
 | 
						|
    }    
 | 
						|
}
 |