diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php index 94de456..db4430b 100644 --- a/app/Http/Controllers/AppController.php +++ b/app/Http/Controllers/AppController.php @@ -49,6 +49,14 @@ class AppController extends Controller } } + public function switchP($email) { + Premium::setEmailP($email); + if (json_decode(config('app.settings.configuration_settings'))->disable_mailbox_slug) { + return redirect()->route('dashboard'); + } + return redirect()->route('dashboard.premium'); + } + public function deleteP($email = null) { if ($email) { $emails = Premium::getEmails(); diff --git a/app/Livewire/Dashboard/Dashboard.php b/app/Livewire/Dashboard/Dashboard.php index 06008ba..f8dd34f 100644 --- a/app/Livewire/Dashboard/Dashboard.php +++ b/app/Livewire/Dashboard/Dashboard.php @@ -2,12 +2,14 @@ namespace App\Livewire\Dashboard; +use App\Models\UsageLog; use Illuminate\Http\Request; use Livewire\Component; class Dashboard extends Component { public $message; + public $usageLog; public $subscription; public $plans; @@ -61,7 +63,11 @@ class Dashboard extends Component } } - + $usageLog = UsageLog::where('user_id', auth()->user()->id)->first(); + $this->usageLog = [ + 'emails_created_count' => $usageLog->emails_created_count ?? 0, + 'emails_received_count' => $usageLog->emails_received_count ?? 0, + ]; } public function render() diff --git a/app/Livewire/Dashboard/Mailbox/Inbox.php b/app/Livewire/Dashboard/Mailbox/Inbox.php index 1c9916b..cf982d3 100644 --- a/app/Livewire/Dashboard/Mailbox/Inbox.php +++ b/app/Livewire/Dashboard/Mailbox/Inbox.php @@ -5,15 +5,18 @@ namespace App\Livewire\Dashboard\Mailbox; use App\ColorPicker; use App\Models\Log; use App\Models\Premium; +use App\Models\PremiumEmail; +use App\Models\UsageLog; +use Artisan; use Carbon\Carbon; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Cookie; use Livewire\Component; +use Session; class Inbox extends Component { use ColorPicker; - public $messages = []; public $deleted = []; public $error = ''; @@ -24,8 +27,11 @@ class Inbox extends Component public $messageId; public $list = false; public $emails; + public $mailboxHistory; + public $emailsHistory; public $username, $domain, $domains, $action; public $email_limit = 20; + private $isSubscribed; protected $listeners = ['updateEmail' => 'syncEmail', 'getEmail' => 'generateEmail', 'fetchMessages' => 'fetch', 'setMessageId' => 'setMessageId']; @@ -38,8 +44,11 @@ class Inbox extends Component $this->initial = false; $this->checkMultipleEmails(); $this->validateDomainInEmail(); + $this->emailsHistory = array_reverse(PremiumEmail::parseEmail(\auth()->user()->id)['data']) ?? []; - if(auth()->user()->subscribedToProduct(config('app.plans')[0]['product_id'])) { + $subscriptionCheck = auth()->user()->subscribedToProduct(config('app.plans')[0]['product_id']); + Session::put('isSubscribed', $subscriptionCheck); + if($subscriptionCheck) { try { $result = auth()->user()->subscriptions()->where(['stripe_status' => 'active'])->orderByDesc('updated_at')->first(); $userPriceID = $result['items'][0]['stripe_price']; @@ -57,6 +66,9 @@ class Inbox extends Component \Log::error($e->getMessage()); } } + + $mailboxHistory = UsageLog::where(['user_id' => auth()->user()->id])->first(); + $this->mailboxHistory = $mailboxHistory->emails_created_history ?? []; } private function checkMultipleEmails(): void @@ -73,7 +85,22 @@ class Inbox extends Component public function switchEmail($email) { - return redirect()->route('switch', ['email' => $email]); + try { + if ($email != null) { + $data = explode('@', $email); + if (isset($data[1])) { + $domain = $data[1]; + $domains = json_decode(config('app.settings.configuration_settings'))->premium_domains ?? []; + if (!in_array($domain, $domains)) { + return $this->showAlert('error', __('This mailbox can not be recovered.')); + } + } + } + } catch (\Exception $exception) { + \Log::error($exception->getMessage()); + } + + return redirect()->route('switchP', ['email' => $email]); } public function syncEmail(): void @@ -183,19 +210,25 @@ class Inbox extends Component private function validateDomainInEmail(): void { - $data = explode('@', $this->email); - if (isset($data[1])) { - $domain = $data[1]; - $domains = json_decode(config('app.settings.configuration_settings'))->premium_domains ?? []; - if (!in_array($domain, $domains)) { - $key = array_search($this->email, $this->emails); - Premium::removeEmail($this->email); - if ($key == 0 && count($this->emails) == 1 && json_decode(config('app.settings.configuration_settings'))->after_last_email_delete == 'redirect_to_homepage') { - redirect()->route('dashboard.premium'); - } else { - redirect()->route('dashboard.premium'); + try { + if ($this->email != null) { + $data = explode('@', $this->email); + if (isset($data[1])) { + $domain = $data[1]; + $domains = json_decode(config('app.settings.configuration_settings'))->premium_domains ?? []; + if (!in_array($domain, $domains)) { + $key = array_search($this->email, $this->emails); + Premium::removeEmail($this->email); + if ($key == 0 && count($this->emails) == 1 && json_decode(config('app.settings.configuration_settings'))->after_last_email_delete == 'redirect_to_homepage') { + redirect()->route('dashboard.premium'); + } else { + redirect()->route('dashboard.premium'); + } + } } } + } catch (\Exception $exception) { + \Log::error($exception->getMessage()); } } @@ -241,6 +274,15 @@ class Inbox extends Component $this->dispatch('showNewMailNotification', $notification); } Premium::incrementMessagesStats(count($notifications)); + + if ($this->email != null && count($this->messages) > 0) { + foreach ($this->messages as $message) { + PremiumEmail::createEmail($message, $this->email); + } + } + + $this->emailsHistory = array_reverse(PremiumEmail::parseEmail(\auth()->user()->id)['data']) ?? []; + } catch (\Exception $e) { if (Auth::check() && Auth::user()->level == 9) { $this->error = $e->getMessage(); @@ -252,6 +294,17 @@ class Inbox extends Component $this->initial = true; } + public function processQueue(): void + { + try { + Artisan::call('queue:work', [ + '--once' => true, + ]); + } catch (\Exception $exception) { + \Log::error($exception->getMessage()); + } + } + public function delete($messageId) { try { @@ -274,7 +327,11 @@ class Inbox extends Component public function render() { - return view('livewire.dashboard.mailbox.inbox')->layout('components.layouts.dashboard'); + if (Session::get('isSubscribed')) { + return view('livewire.dashboard.mailbox.inbox')->layout('components.layouts.dashboard'); + } else { + return view('livewire.dashboard.not-subscribed')->layout('components.layouts.dashboard'); + } } private function rrmdir($dir): void diff --git a/app/Livewire/Dashboard/NotSubscribed.php b/app/Livewire/Dashboard/NotSubscribed.php new file mode 100644 index 0000000..91b9fa5 --- /dev/null +++ b/app/Livewire/Dashboard/NotSubscribed.php @@ -0,0 +1,13 @@ +layout('components.layouts.dashboard'); + } +} diff --git a/app/Models/Premium.php b/app/Models/Premium.php index 68f45ba..3b0c6a9 100644 --- a/app/Models/Premium.php +++ b/app/Models/Premium.php @@ -35,6 +35,12 @@ class Premium extends Model public static function fetchMessages($email, $type = 'to', $deleted = []): array { + if ($email == null) { + return [ + "data" => [], + "notifications" => [] + ]; + } $allowed = explode(',', 'doc,docx,xls,xlsx,ppt,pptx,xps,pdf,dxf,ai,psd,eps,ps,svg,ttf,zip,rar,tar,gzip,mp3,mpeg,wav,ogg,jpeg,jpg,png,gif,bmp,tif,webm,mpeg4,3gpp,mov,avi,mpegs,wmv,flx,txt'); $connection = self::connectMailBox(); @@ -91,6 +97,7 @@ class Premium extends Model $obj['date'] = $date->format(json_decode(config('app.settings.configuration_settings'))->date_format ?? 'd M Y h:i A'); $obj['datediff'] = $datediff->diffForHumans(); $obj['id'] = $message->getNumber(); + $obj['size'] = $message->getSize(); $obj['content'] = $content; $obj['contentText'] = $contentText; $obj['attachments'] = []; @@ -191,6 +198,15 @@ class Premium extends Model Cookie::queue('email', $email, 43800); } } + + public static function setEmailP($email): void + { + $usageLogs = UsageLog::where(['user_id' => auth()->user()->id])->first(); + $emails = $usageLogs->emails_created_history; + if (is_array($emails) && in_array($email, $emails)) { + Cookie::queue('email', $email, 43800); + } + } public static function removeEmail($email): void { $emails = self::getEmails(); @@ -287,14 +303,14 @@ class Premium extends Model if ($domain == "gmail.com") { $rd = mt_rand(0,1); if ($rd == 0) { - $email = $zemail->generateRandomGmail(); + $email = $zemail->generateRandomGmail(false); } else { $email = $zemail->getRandomGmailUser().'+'.$zemail->generateRandomUsername().'@gmail.com'; } } elseif ($domain == "googlemail.com") { $rd = mt_rand(0,1); if ($rd == 0) { - $email = $zemail->generateRandomGmail(); + $email = $zemail->generateRandomGmail(false); } else { $email = $zemail->getRandomGmailUser().'+'.$zemail->generateRandomUsername().'@googlemail.com'; } diff --git a/app/Models/PremiumEmail.php b/app/Models/PremiumEmail.php new file mode 100644 index 0000000..0edf4ca --- /dev/null +++ b/app/Models/PremiumEmail.php @@ -0,0 +1,160 @@ + 'array', + 'cc' => 'array', + 'bcc' => 'array', + 'attachments' => 'array', + 'timestamp' => 'datetime' + ]; + + public static function createEmail($message, $email): void + { + $initialData = $message; + $utcTime = CarbonImmutable::instance($message['timestamp'])->setTimezone('UTC')->toDateTimeString(); + $messageId = Carbon::parse($utcTime)->format('Ymd').$initialData['id']; + $userId = \auth()->user()->id; + $exists = PremiumEmail::where('user_id', $userId)->where('message_id', $messageId)->exists(); + + $data = [ + 'user_id' => $userId, + 'message_id' => $messageId, + 'subject' => $initialData['subject'], + 'from_name' => $initialData['sender_name'], + 'from_email' => $initialData['sender_email'], + 'to' => ["$email"], + 'cc' => [], + 'bcc' => [], + 'timestamp' => $utcTime, + 'body_text' => $initialData['contentText'], + 'body_html' => $initialData['content'], + 'is_seen' => true, + 'is_flagged' => false, + 'size' => $initialData['size'], + 'mailbox' => 'INBOX', + 'raw_headers' => null, + 'raw_body' => null, + 'attachments' => $initialData['attachments'], + ]; + + if (!$exists) { + PremiumEmail::create($data); + } + } + + public static function fetchEmailFromDB($userId) { + + $validator = Validator::make(['user_id' => $userId], [ + 'user_id' => 'required|integer' + ]); + + if ($validator->fails()) { + return []; + } + return self::whereJsonContains('user_id', $userId)->orderBy('timestamp', 'desc')->get(); + } + + public static function parseEmail($userId, $deleted = []): array + { + $messages = self::fetchEmailFromDB($userId); + $limit = 50; + $count = 1; + $response = [ + 'data' => [], + 'notifications' => [] + ]; + + foreach ($messages as $message) { + + if (in_array($message['message_id'], $deleted)) { + // If it exists, delete the matching record from the 'emails' table + Email::where('message_id', $message['message_id'])->delete(); + continue; + } + + $blocked = false; + + $timestamp = $message['timestamp']; + $carbonTimestamp = Carbon::parse($timestamp, 'UTC'); + $obj = []; + $obj['subject'] = $message['subject']; + $obj['to'] = $message['to']; + $obj['sender_name'] = $message['from_name']; + $obj['sender_email'] = $message['from_email']; + $obj['timestamp'] = $message['timestamp']; + $obj['date'] = $carbonTimestamp->format('d M Y h:i A'); + $obj['datediff'] = $carbonTimestamp->diffForHumans(Carbon::now('UTC')); + $obj['id'] = $message['message_id']; + $obj['content'] = $message['body_html']; + $obj['contentText'] = $message['body_text']; + $obj['attachments'] = []; + $obj['is_seen'] = $message['is_seen']; + $obj['sender_photo'] = self::chooseColor(strtoupper(substr($message['from_name'] ?: $message['from_email'], 0, 1) )); + + + $domain = explode('@', $obj['sender_email'])[1]; + $blocked = in_array($domain, json_decode(config('app.settings.configuration_settings'))->blocked_domains); + if ($blocked) { + $obj['subject'] = __('Blocked'); + $obj['content'] = __('Emails from') . ' ' . $domain . ' ' . __('are blocked by Admin'); + $obj['contentText'] = __('Emails from') . ' ' . $domain . ' ' . __('are blocked by Admin'); + } + + if (count($message['attachments']) > 0 && !$blocked) { + $obj['attachments'] = $message['attachments']; + + } + + $response['data'][] = $obj; + if (!$message['is_seen']) { + $response['notifications'][] = [ + 'subject' => $obj['subject'], + 'sender_name' => $obj['sender_name'], + 'sender_email' => $obj['sender_email'] + ]; + if (config('app.zemail_log')) { + file_put_contents(storage_path('logs/zemail.csv'), request()->ip() . "," . date("Y-m-d h:i:s a") . "," . $obj['sender_email'] . "," . $email . PHP_EOL, FILE_APPEND); + } + } + PremiumEmail::where('message_id', $message['message_id'])->update(['is_seen' => true]); + if (++$count > $limit) { + break; + } + } + return $response; + } + +} diff --git a/database/migrations/2025_05_05_212255_create_premium_emails_table.php b/database/migrations/2025_05_05_212255_create_premium_emails_table.php new file mode 100644 index 0000000..85b6f95 --- /dev/null +++ b/database/migrations/2025_05_05_212255_create_premium_emails_table.php @@ -0,0 +1,47 @@ +id(); + $table->unsignedBigInteger('user_id'); + $table->string('message_id')->unique()->index(); + $table->string('subject')->nullable(); + $table->string('from_name')->nullable(); + $table->string('from_email'); + $table->text('to'); + $table->text('cc')->nullable(); + $table->text('bcc')->nullable(); + $table->dateTime('timestamp')->nullable(); + $table->longText('body_text')->nullable(); + $table->longText('body_html')->nullable(); + $table->boolean('is_seen')->default(false); + $table->boolean('is_flagged')->default(false); + $table->unsignedBigInteger('size')->nullable(); + $table->string('mailbox')->default('INBOX'); + $table->longText('raw_headers')->nullable(); + $table->longText('raw_body')->nullable(); + $table->json('attachments')->nullable(); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('premium_emails'); + } +}; diff --git a/resources/views/flux/icon/lock-keyhole.blade.php b/resources/views/flux/icon/lock-keyhole.blade.php new file mode 100644 index 0000000..ba89d7f --- /dev/null +++ b/resources/views/flux/icon/lock-keyhole.blade.php @@ -0,0 +1,43 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + diff --git a/resources/views/livewire/dashboard/dashboard.blade.php b/resources/views/livewire/dashboard/dashboard.blade.php index 701ce90..195a91e 100644 --- a/resources/views/livewire/dashboard/dashboard.blade.php +++ b/resources/views/livewire/dashboard/dashboard.blade.php @@ -9,7 +9,7 @@
-

0

+

{{ $usageLog['emails_created_count'] }}

Mailbox Created

@@ -19,7 +19,7 @@
-

0

+

{{ $usageLog['emails_received_count'] }}

Emails Received

diff --git a/resources/views/livewire/dashboard/mailbox/inbox.blade.php b/resources/views/livewire/dashboard/mailbox/inbox.blade.php index 66838c0..f5e48f4 100644 --- a/resources/views/livewire/dashboard/mailbox/inbox.blade.php +++ b/resources/views/livewire/dashboard/mailbox/inbox.blade.php @@ -55,8 +55,25 @@ +
+
+
+ + + + + +
+
+ @if($email !== null) -
+
Copy
@@ -241,5 +258,195 @@
@endif -
+ +
+
+
+

Generated Mailbox Addresses

+ +
+ @foreach(array_reverse($mailboxHistory) as $email) +
+ {{ $email }} + +
+ @endforeach +
+
+
+
+ +
+
+
+

Email History

+ +
+
+ @if($emailsHistory) +
+
+
+ @foreach(array_reverse($emailsHistory) as $i => $message) +
+
+
+
+
+ + {{-- inbox-logo--}} + + + + @if(!$message['is_seen']) + + @endif + +
+
+
+
+ {{ $message['sender_name'] }} +
+
+ + + + {{ $message['sender_email'] }}
+
+ +
+
+
+ + + +
+
+
+
+ @endforeach +
+
+ @foreach(array_reverse($emailsHistory) as $message) +
+ + +
+ + +
+
+

+ {{ $message['subject'] }} +

+
+
+ Download + {{-- Source--}} + Print + {{ __('Delete') }} +
+
+
+
+
+
+
+ + + +
+
+
+ {{ $message['sender_name'] }} + {{ $message['sender_email'] }} +
+ +
+
+
+
+ +
+
+
+ +
+ @if (count($message['attachments']) > 0) +
+ @foreach ($message['attachments'] as $attachment) + + @endforeach +
+ @endif + +
+
+
+
+ @endforeach +
+
+ + @else +
+
+
+
+
+ +
+ + + + + + {{ __('No email history') }} +
+
+
+ @endif +
+
+
+
+
+
+
diff --git a/resources/views/livewire/dashboard/not-subscribed.blade.php b/resources/views/livewire/dashboard/not-subscribed.blade.php new file mode 100644 index 0000000..fb0b769 --- /dev/null +++ b/resources/views/livewire/dashboard/not-subscribed.blade.php @@ -0,0 +1,23 @@ + +
+
+ +
+{{-- logo--}} + +
+

+ You don't have permission to access this page +

+

+ To continue, you need to subscribe to a plan that grants access. +

+ + + + Subscribe now + +
+
+
diff --git a/routes/web.php b/routes/web.php index 606fc45..dc82b17 100644 --- a/routes/web.php +++ b/routes/web.php @@ -21,6 +21,7 @@ Route::get('/mailbox', Mailbox::class)->name('mailbox'); Route::get('/mailbox/{email?}', [AppController::class, 'mailbox'])->name('mailboxFromURL'); Route::get('/switch/{email}', [AppController::class, 'switch'])->name('switch'); +Route::get('/switchP/{email}', [AppController::class, 'switchP'])->name('switchP'); Route::get('/delete/{email?}', [AppController::class, 'delete'])->name('delete'); Route::get('/deleteP/{email?}', [AppController::class, 'deleteP'])->name('deleteP');