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);
 | |
|         }
 | |
|     }    
 | |
| }
 | 
