diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..8c84f66 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +# Webhook Configuration +NEXTJS_WEBHOOK_URL=https://your-nextjs-app.com/api/webhooks/mail-signal +WEBHOOK_SECRET=besiktasK1903* + +# Redis (Optional, if used in other parts) +REDIS_URL=redis://localhost:6379 diff --git a/Dockerfile b/Dockerfile index e8bde91..5ac764e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM node:20-alpine -# Install docker cli to be able to run 'docker logs' from within the container +# Install docker cli to be able to run 'docker exec' from within the container # Note: You must mount /var/run/docker.sock when running this container RUN apk add --no-cache docker-cli @@ -11,6 +11,5 @@ RUN npm install COPY . . -RUN npm run build - +# Run using the start script (tsx apps/worker/main.ts) CMD ["npm", "start"] \ No newline at end of file diff --git a/README.md b/README.md index eb896b4..a46f565 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,42 @@ -# AyrisTech Worker +# AyrisTech Worker (V10.3) -This worker listens to Mailcow Dovecot logs and publishes incoming mail events to Redis. +This worker monitors Mailcow vmail volumes and triggers Next.js webhooks when new mail arrives. ## Features -- Real-time mail event tracking -- Redis Pub/Sub integration -- Dockerized deployment +- Real-time filesystem monitoring with `chokidar` +- Automatic mail decoding via `doveadm` +- Next.js Webhook integration +- Secure secret-based authentication -## Setup -1. Clone the repository -2. Install dependencies: `npm install` -3. Configure `.env` file -4. Run the worker: `npm start` +## Setup Instructions + +### 1. Configuration +Create a `.env` file in the root directory (copy from `.env.example` if available): +```env +NEXTJS_WEBHOOK_URL=https://your-nextjs-app.com/api/webhooks/mail-signal +WEBHOOK_SECRET=your_secret_here +``` + +### 2. Local Installation +```bash +npm install +npm start +``` + +### 3. Docker Deployment +To run as a container, you must provide access to the Docker socket and the Mailcow volumes: + +```bash +docker build -t ayristech-worker . + +docker run -d \ + --name ayristech-worker \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/:/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/ \ + --env-file .env \ + ayristech-worker +``` + +## Important Notes +- **Docker Socket**: The worker runs `docker exec` commands, so `/var/run/docker.sock` must be mounted. +- **Vmail Path**: The worker watches `/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/`. Ensure this volume exists and is mounted at the exact same path inside the container. diff --git a/apps/worker/main.ts b/apps/worker/main.ts index c6b81cc..f4acb54 100644 --- a/apps/worker/main.ts +++ b/apps/worker/main.ts @@ -1,35 +1,65 @@ -import { Redis } from 'ioredis'; -import { spawn } from 'child_process'; -import dotenv from 'dotenv'; +require('dotenv').config(); +const chokidar = require('chokidar'); +const axios = require('axios'); +const { exec } = require('child_process'); -dotenv.config(); +const NEXTJS_WEBHOOK_URL = process.env.NEXTJS_WEBHOOK_URL; +const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; +const vmailPath = '/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/'; -const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379'; -const CONTAINER_NAME = process.env.MAILCOW_CONTAINER_NAME || 'mailcowdockerized-dovecot-mailcow-1'; +console.log("🚀 AyrisTech Güvenli Dekoder (V10.3) Başlatıldı..."); -const redis = new Redis(REDIS_URL); +const watcher = chokidar.watch(vmailPath, { + ignored: /(^|[\/\\])\../, + persistent: true, + ignoreInitial: true, + depth: 5 +}); -console.log("🚀 AyrisTech Worker Bağlanıyor..."); +watcher.on('add', (filePath) => { + if (filePath.includes('/new/')) { + const parts = filePath.split('/'); + const fullEmail = `${parts[8]}@${parts[7]}`; -// Dovecot loglarını dinliyoruz -const logProcess = spawn('docker', ['logs', '-f', CONTAINER_NAME]); + console.log(`📩 Yeni şifreli mail: ${fullEmail}. Çözülüyor...`); -logProcess.stdout.on('data', async (data) => { - const line = data.toString(); + // Komutu daha garantici bir hale getirdik + const cmd = `docker exec mailcowdockerized-dovecot-mailcow-1 doveadm fetch -u "${fullEmail}" "hdr.from hdr.subject body.snippet" ALL`; - // Mailcow'un mail teslimat logunu yakala - if (line.includes('saved mail to INBOX')) { - const match = line.match(/user=<([^>]+)>/); - if (match) { - const email = match[1]; - console.log(`📩 Mail Geldi: ${email}`); + setTimeout(() => { + exec(cmd, async (error, stdout, stderr) => { + if (error || stderr) { + console.error("❌ Doveadm Hatası:", error ? error.message : stderr); + return; + } - // Olayı Redis'e fırlat (Pub/Sub) - // Bu sayede Next.js veya diğer servisler bu haberi alabilir - await redis.publish('NEW_MAIL_EVENT', JSON.stringify({ - to: email, - time: new Date().toISOString() - })); - } + if (!stdout.trim()) { + console.log("⚠️ Mail içeriği henüz hazır değil (Stdout boş)."); + return; + } + + let mailData = { to: fullEmail, from: 'Bilinmiyor', subject: 'Konu Yok', snippet: '' }; + + // Satır satır parse etme + const lines = stdout.split('\n'); + lines.forEach(line => { + const l = line.trim(); + if (l.toLowerCase().startsWith('hdr.from:')) mailData.from = l.split(':').slice(1).join(':').trim(); + if (l.toLowerCase().startsWith('hdr.subject:')) mailData.subject = l.split(':').slice(1).join(':').trim(); + if (l.toLowerCase().startsWith('body.snippet:')) mailData.snippet = l.split(':').slice(1).join(':').trim(); + }); + + console.log(`✨ İçerik Çözüldü: ${mailData.subject}`); + + try { + await axios.post(NEXTJS_WEBHOOK_URL, mailData, { + headers: { 'x-ayristech-secret': WEBHOOK_SECRET } + }); + console.log(`✅ Webhook Next.js'e başarıyla ulaştı.`); + } catch (err) { + console.error("❌ Webhook Hatası:", err.message); + } + }); + }, 2500); // Mailin DB'ye tam işlenmesi için süreyi biraz artırdık } }); \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index 3a66686..0000000 --- a/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "ayristech-worker", - "version": "1.0.0", - "description": "", - "type": "module", - "main": "dist/apps/worker/main.js", - "scripts": { - "build": "tsc", - "start": "node dist/apps/worker/main.js", - "dev": "tsx apps/worker/main.ts", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "dotenv": "^16.4.7", - "ioredis": "^5.10.1" - }, - "devDependencies": { - "@types/node": "^25.7.0", - "tsx": "^4.19.2", - "typescript": "^6.0.3" - } -}