Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ package-lock.json
/lang/vendor
/storage/*.key
/storage/dcc-data/
/storage
storage
/vendor
yarn.lock
yarn-error.log
Expand Down
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM php:8.2-fpm-bookworm

# Cài đặt các gói hệ thống và PHP extension cần thiết
RUN apt-get update && apt-get install -y \
git curl zip unzip libpng-dev libonig-dev libxml2-dev libzip-dev libicu-dev \
libjpeg-dev libfreetype6-dev libssl-dev libkrb5-dev libc-client-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
# Cấu hình IMAP với Kerberos & SSL
&& docker-php-ext-configure imap --with-kerberos --with-imap-ssl \
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip calendar intl imap \
&& rm -rf /var/lib/apt/lists/*

# Cài Composer (phiên bản 2.5)
COPY --from=composer:2.5 /usr/bin/composer /usr/bin/composer

# Thiết lập thư mục làm việc
WORKDIR /var/www/html

# Copy toàn bộ source code vào container
COPY . .

# Cấp quyền cho storage & bootstrap/cache
RUN chown -R www-data:www-data storage bootstrap/cache && \
chmod -R 775 storage bootstrap/cache

# Cổng để PHP-FPM phục vụ nội bộ (cho Nginx proxy)
EXPOSE 9000

CMD ["php-fpm"]
103 changes: 103 additions & 0 deletions app/Console/Commands/TestReadMail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use League\OAuth2\Client\Provider\GenericProvider;
use Webklex\PHPIMAP\ClientManager;
use Webklex\PHPIMAP\Exceptions\AuthFailedException;

class TestReadMail extends Command
{
protected $signature = 'test:read-mail';
protected $description = 'Test reading Outlook mail via OAuth2 IMAP';

public function handle()
{
$this->info('--- Starting Outlook OAuth2 IMAP Test ---');

$tenantId = 'c1018ad6-79f6-4ce8-92a0-b797019cca0d';
$clientId = '3bf5abf4-a3ee-40bb-b133-a69123a3e141';
$clientSecret = env('OAUTH_CLIENT_SECRET'); // đảm bảo bạn có trong .env
$redirectUri = 'http://localhost:8085/oauth/callback';
$tokenPath = storage_path('app/outlook_token.json');

$provider = new GenericProvider([
'clientId' => $clientId,
'clientSecret' => $clientSecret,
'redirectUri' => $redirectUri,
'urlAuthorize' => "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/authorize",
'urlAccessToken' => "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token",
'urlResourceOwnerDetails' => 'https://graph.microsoft.com/v1.0/me',
'scopes' => 'offline_access IMAP.AccessAsUser.All Mail.Read Mail.ReadWrite Mail.Send SMTP.Send User.Read'
]);

$token = null;
if (file_exists($tokenPath)) {
$token = json_decode(file_get_contents($tokenPath), true);
if (isset($token['expires']) && $token['expires'] < time()) {
$this->info('Access token expired. Refreshing...');
try {
$newToken = $provider->getAccessToken('refresh_token', [
'refresh_token' => $token['refresh_token']
]);
file_put_contents($tokenPath, json_encode($newToken->jsonSerialize(), JSON_PRETTY_PRINT));
$token = $newToken->jsonSerialize();
} catch (\Exception $e) {
$this->error('Token refresh failed: ' . $e->getMessage());
unlink($tokenPath);
return;
}
}
}

if (!$token) {
$authUrl = $provider->getAuthorizationUrl();
$this->info("Go to the following URL and authorize the app:\n" . $authUrl);
$authCode = $this->ask('Enter the authorization code:');
try {
$accessToken = $provider->getAccessToken('authorization_code', [
'code' => trim($authCode),
]);
file_put_contents($tokenPath, json_encode($accessToken->jsonSerialize(), JSON_PRETTY_PRINT));
$token = $accessToken->jsonSerialize();
$this->info('Access token saved.');
} catch (\Exception $e) {
$this->error('Failed to get access token: ' . $e->getMessage());
return;
}
}

// --- Connect IMAP using XOAUTH2 ---
$cm = new ClientManager(['options' => [
'fetch' => \Webklex\PHPIMAP\IMAP::FT_PEEK,
'sequence' => \Webklex\PHPIMAP\IMAP::ST_UID,
]]);

$client = $cm->make([
'host' => 'outlook.office365.com',
'port' => 993,
'encryption' => 'ssl',
'validate_cert' => true,
'protocol' => 'imap',
'authentication' => 'oauth',
'username' => '[email protected]',
'password' => $token['access_token'],
]);

try {
$this->info('Connecting directly to outlook.office365.com:993 via XOAUTH2...');
$client->connect();
$this->info('✅ Successfully authenticated via XOAUTH2!');
$folder = $client->getFolder('INBOX');
$messages = $folder->messages()->limit(5)->get();
$this->info("Fetched {$messages->count()} messages from INBOX.");
} catch (AuthFailedException $e) {
$this->error("❌ IMAP XOAUTH2 failed: " . $e->getMessage());
} catch (\Exception $e) {
$this->error("Error occurred: " . $e->getMessage());
}

$this->info('--- Test completed ---');
}
}
2 changes: 2 additions & 0 deletions app/Http/Middleware/Authenticate.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Support\Facades\Auth;

class Authenticate extends Middleware
{
Expand All @@ -14,6 +15,7 @@ class Authenticate extends Middleware
*/
protected function redirectTo($request)
{
dd(Auth::check(), Auth::user(), session()->all());
if (! $request->expectsJson()) {
return route('login');
}
Expand Down
1 change: 1 addition & 0 deletions app/Http/Middleware/RedirectIfAuthenticated.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class RedirectIfAuthenticated
*/
public function handle(Request $request, Closure $next, ...$guards)
{
dd(Auth::check(), Auth::user(), session()->all());
$guards = empty($guards) ? [null] : $guards;

foreach ($guards as $guard) {
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Middleware/TrustProxies.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class TrustProxies extends Middleware
*
* @var array|string|null
*/
protected $proxies;
protected $proxies = '*';

/**
* The headers that should be used to detect proxies.
Expand Down
8 changes: 8 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Providers;

use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
Expand All @@ -24,5 +25,12 @@ public function register()
public function boot()
{
//
// URL::forceScheme('https');
if (config('app.env') === 'production') {
URL::forceScheme('https');
}
if (config('app.env') === 'local') {
URL::forceScheme('http');
}
}
}
Empty file modified bootstrap/cache/.gitignore
100644 → 100755
Empty file.
8 changes: 6 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
"diglactic/laravel-breadcrumbs": "^8.0",
"doctrine/dbal": "^3.0",
"enshrined/svg-sanitize": "^0.21.0",
"guzzlehttp/guzzle": "^7.0.1",
"guzzlehttp/guzzle": "^7.10",
"khaled.alshamaa/ar-php": "^6.3",
"konekt/concord": "^1.10",
"laravel/framework": "^10.0",
"laravel/sanctum": "^3.2",
"laravel/tinker": "^2.5",
"laravel/ui": "^4.5",
"league/oauth2-client": "*",
"maatwebsite/excel": "^3.1",
"microsoft/microsoft-graph": "*",
"mpdf/mpdf": "^8.2",
"prettus/l5-repository": "^2.7.9",
"smalot/pdfparser": "^2.11",
Expand All @@ -44,7 +46,9 @@
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true
"pestphp/pest-plugin": true,
"php-http/discovery": true,
"tbachert/spi": true
}
},
"extra": {
Expand Down
Loading