Compare commits

...

6 Commits

Author SHA1 Message Date
AyrisAI
17ad42b3b9 vbsgf 2026-05-14 19:29:58 +03:00
AyrisAI
ac9cd464ff docs: add .env.example and English documentation to README 2026-05-14 19:19:06 +03:00
AyrisAI
dc501566d9 security: obfuscate sensitive data in README and .env 2026-05-14 19:18:24 +03:00
AyrisAI
98f92b1b2b fix: restore .gitignore 2026-05-14 19:16:16 +03:00
AyrisAI
4a7b3bcc3a chore: simplify to plain JS worker.js and finalize install instructions 2026-05-14 19:16:08 +03:00
AyrisAI
06789a25af docs: finalize installation instructions and infrastructure for overhauled worker 2026-05-14 19:14:43 +03:00
10 changed files with 160 additions and 274 deletions

3
.env Normal file
View File

@@ -0,0 +1,3 @@
NEXTJS_WEBHOOK_URL=https://webmail.ayris.tech/api/webhooks/mail-signal
WEBHOOK_SECRET=besiktasK1903*

2
.env.example Normal file
View File

@@ -0,0 +1,2 @@
NEXTJS_WEBHOOK_URL=
WEBHOOK_SECRET=

View File

@@ -1,16 +1,18 @@
FROM node:20-alpine
# Hafif bir Node.js imajı kullanalım
FROM node:20-slim
# Install docker cli to be able to run 'docker logs' from within the container
# Note: You must mount /var/run/docker.sock when running this container
RUN apk add --no-cache docker-cli
# Docker CLI'ı içine kuruyoruz (Çünkü Worker, Dovecot konteynerine komut gönderecek)
RUN apt-get update && apt-get install -y docker.io && rm -rf /var/lib/apt/lists/*
# Çalışma dizini
WORKDIR /app
# Paket listelerini kopyala ve bağımlılıkları kur
COPY package*.json ./
RUN npm install
RUN npm install --production
# Tüm kodları ve .env dosyasını kopyala
COPY . .
RUN npm run build
CMD ["npm", "start"]
# Uygulamayı başlat
CMD ["node", "worker.js"]

View File

@@ -1,14 +1,61 @@
# AyrisTech Worker
# AyrisTech Mail Worker (V10.3)
This worker listens to Mailcow Dovecot logs and publishes incoming mail events to Redis.
Mailcow Dovecot loglarını ve dosya sistemini izleyerek yeni gelen mailleri Next.js webhook'una ileten servis.
## Features
- Real-time mail event tracking
- Redis Pub/Sub integration
- Dockerized deployment
## Kurulum (Türkçe)
## Setup
1. Clone the repository
2. Install dependencies: `npm install`
3. Configure `.env` file
4. Run the worker: `npm start`
### 1. Dosyaları Hazırlayın
Örnek dosyayı kopyalayın ve bilgilerinizi girin:
```bash
cp .env.example .env
```
### 2. Çalıştırma (Docker Compose)
En kolay ve tavsiye edilen yöntem:
```bash
docker compose up -d --build
```
### 3. Manuel Çalıştırma (Geliştirme)
```bash
npm install
npm start
```
---
# AyrisTech Mail Worker (V10.3) - English
Service that monitors Mailcow Dovecot logs and filesystem to forward new incoming emails to a Next.js webhook.
## Installation (English)
### 1. Prepare Files
Copy the example file and enter your details:
```bash
cp .env.example .env
```
### 2. Execution (Docker Compose)
The easiest and recommended method:
```bash
docker compose up -d --build
```
### 3. Manual Run (Development)
```bash
npm install
npm start
```
---
## Önemli Notlar / Important Notes
- **TR**: Servis `docker exec` komutu kullandığı için `/var/run/docker.sock` erişimine ihtiyaç duyar.
- **EN**: The service requires access to `/var/run/docker.sock` to execute `docker exec` commands.
- **TR**: Mailcow mail dosyaları `/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/` yolunda olmalıdır.
- **EN**: Mailcow email files must be located at `/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/`.

View File

@@ -1,35 +0,0 @@
import { Redis } from 'ioredis';
import { spawn } from 'child_process';
import dotenv from 'dotenv';
dotenv.config();
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
const CONTAINER_NAME = process.env.MAILCOW_CONTAINER_NAME || 'mailcowdockerized-dovecot-mailcow-1';
const redis = new Redis(REDIS_URL);
console.log("🚀 AyrisTech Worker Bağlanıyor...");
// Dovecot loglarını dinliyoruz
const logProcess = spawn('docker', ['logs', '-f', CONTAINER_NAME]);
logProcess.stdout.on('data', async (data) => {
const line = data.toString();
// 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}`);
// 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()
}));
}
}
});

14
docker-compose.yml Normal file
View File

@@ -0,0 +1,14 @@
version: '3.8'
services:
ayristech-worker:
build: .
container_name: ayristech-worker
restart: always
volumes:
# Mail dosyalarını okumak için vmail volume'unu bağlıyoruz
- /var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data:/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data:ro
# Docker içinde docker komutu çalıştırabilmek için socket'i bağlıyoruz
- /var/run/docker.sock:/var/run/docker.sock
env_file:
- .env

161
package-lock.json generated
View File

@@ -1,161 +0,0 @@
{
"name": "ayristech-worker",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ayristech-worker",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"ioredis": "^5.10.1"
},
"devDependencies": {
"@types/node": "^25.7.0",
"typescript": "^6.0.3"
}
},
"node_modules/@ioredis/commands": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz",
"integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==",
"license": "MIT"
},
"node_modules/@types/node": {
"version": "25.7.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.7.0.tgz",
"integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.21.0"
}
},
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/ioredis": {
"version": "5.10.1",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.1.tgz",
"integrity": "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==",
"license": "MIT",
"dependencies": {
"@ioredis/commands": "1.5.1",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
},
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ioredis"
}
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"license": "MIT"
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
"license": "MIT"
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/redis-errors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/redis-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"license": "MIT",
"dependencies": {
"redis-errors": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
"license": "MIT"
},
"node_modules/typescript": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.21.0.tgz",
"integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==",
"dev": true,
"license": "MIT"
}
}
}

View File

@@ -1,25 +1,16 @@
{
"name": "ayristech-worker",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "dist/apps/worker/main.js",
"description": "AyrisTech Mailcow Worker",
"main": "worker.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"
"start": "node worker.js",
"dev": "node --watch worker.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"dotenv": "^16.4.7",
"axios": "^1.16.1",
"chokidar": "^5.0.0",
"dotenv": "^17.4.2",
"ioredis": "^5.10.1"
},
"devDependencies": {
"@types/node": "^25.7.0",
"tsx": "^4.19.2",
"typescript": "^6.0.3"
}
}
}

View File

@@ -1,42 +0,0 @@
{
// Visit https://aka.ms/tsconfig to read more about this file
"compilerOptions": {
// File Layout
"rootDir": "./",
"outDir": "./dist",
// Environment Settings
// See also https://aka.ms/tsconfig/module
"module": "nodenext",
"target": "esnext",
"lib": ["esnext"],
"types": ["node"],
// and npm install -D @types/node
// Other Outputs
"sourceMap": true,
"declaration": true,
"declarationMap": true,
// Stricter Typechecking Options
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
// Style Options
// "noImplicitReturns": true,
// "noImplicitOverride": true,
// "noUnusedLocals": true,
// "noUnusedParameters": true,
// "noFallthroughCasesInSwitch": true,
// "noPropertyAccessFromIndexSignature": true,
// Recommended Options
"strict": true,
"jsx": "react-jsx",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true,
}
}

65
worker.js Normal file
View File

@@ -0,0 +1,65 @@
require('dotenv').config();
const chokidar = require('chokidar');
const axios = require('axios');
const { exec } = require('child_process');
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/';
console.log("🚀 AyrisTech Güvenli Dekoder (V10.3) Başlatıldı...");
const watcher = chokidar.watch(vmailPath, {
ignored: /(^|[\/\\])\../,
persistent: true,
ignoreInitial: true,
depth: 5
});
watcher.on('add', (filePath) => {
if (filePath.includes('/new/')) {
const parts = filePath.split('/');
const fullEmail = `${parts[8]}@${parts[7]}`;
console.log(`📩 Yeni şifreli mail: ${fullEmail}. Çözülüyor...`);
// 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`;
setTimeout(() => {
exec(cmd, async (error, stdout, stderr) => {
if (error || stderr) {
console.error("❌ Doveadm Hatası:", error ? error.message : stderr);
return;
}
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
}
});