From 3db9e9d52316a8528b11dbd9525ac419700f8ea5 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Wed, 4 Nov 2020 14:37:37 +0100 Subject: [PATCH 1/6] Add README.md contents and update app.service accordingly --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++ app.service | 9 ++++--- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e69de29..1fc5b30 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,78 @@ +# Rainbox Email + +Rainbox Email is an ISP-like mail service database manager. It also comes with some built-in authentication provider features such as an integrated LDAP server. + +For now, it only supports MySQL. + +Please feel free to contribute by making issues, bug reports and pull requests. + +## /!\ THIS PROJECT STILL LACKS ESSENTIAL FEATURES SUCH AS: /!\ + +- Change password +- Password recovery (recovery emails are unused yet) +- Quota management +- Editable terms of service +- Complex permissions system +- Redirections (can be manually setup with sql queries) +- Probably many others, please make an issue so I can add them to this list + +## How does it work? + +When a user register, they don't immediately get a mailbox. If approval_mode is on, then they have to get approved by an administrator. Then they have to create their first email address which will be their mailbox username. + +Users can only create one email address with their username from public domains (domains set as owned by "Public"). + +However, domains can also be owned by a specific user in which case the user owning the domain can create infinite addresses @the-domain.com. + +Note that a user only has one mailbox once they create their first address and cannot have more. + +## Installation instructions & recommendations + +### Requirements + +- mariadb (for the mysql database that will be operated) +- redis (cache) (this may go as I think I'm not using it at all, but it won't start without it yet) +- A working mail smtp server (to send emails) +- git and yarn for updates + +### Instructions + +- Create a user i.e. `rainbox-email` and its home directory i.e. `/home/rainbox-email` +- `su rainbox-email` (switch to the new user) +- `git clone git@gitlab.com:ArisuOngaku/rainbox.email.git ~/live` (clone Rainbox Email into a new `live` folder) +- `cd ~/live` +- `yarn install && yarn build` +- MySQL + - Create a new empty database named as per configuration (default is `rainbox_email`) + - Create a new mysql user and give them all permissions on the database (`GRANT ALL PRIVILEGES ON rainbox_email.* TO rainbox_email@localhost IDENTIFIED BY "secret_password";`) + - Don't forget to add mysql user and password in `config/local.json5` (see ###Configuration) +- Configure mail (required) and redis (if needed) + - For a private instance, please don't forget to set `approval_mode` to `true` +- Service + - Edit [app.service](app.service) as needed, copy to `/etc/systemd/system/rainbox-email.service` + - When ready, enable and start the service (`systemctl enable --now rainbox-email`) +- Once started, if there were no errors then the database should be created. +- To gain administrator rights, register an account and then go back to mysql and run: `UPDATE users SET is_admin=1 WHERE name="your_user_name";` + +### Configuration + +Create a `config/local.json5` file and override all wanted parameters. See `config/{default,prouction}.json5` and `node_modules/wms-core/config/{default,production}.json5` for defaults. + +## Postfix and dovecot mysql queries + +### Postfix + +- `virtual_mailbox_domains` => `SELECT 1 FROM mail_domains WHERE name='%s'` +- `virtual_mailbox_maps` => `SELECT 1 FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id AND u.main_mail_identity_id=i.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%s'` +- `virtual_alias_maps` => `(SELECT redirects_to FROM mail_identities i LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%s' AND redirects_to IS NOT NULL) UNION (SELECT CONCAT(i.name, '@', d.name) FROM users u LEFT JOIN mail_identities i ON i.id=u.main_mail_identity_id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE (SELECT u.id FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%s' AND redirects_to IS NULL LIMIT 1)=u.id AND i.id IS NOT NULL)` +- `smtpd_sender_login_maps` => `SELECT CONCAT(i.name, '@', d.name) FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%s'` + +### Dovecot `dovecot-sql.conf.ext` + +Note that the quota is hardcoded in the `user_query` to 5GB, please change as needed. + +- `user_query = SELECT CONCAT(i.name, '@', d.name) as user, CONCAT('*:bytes=', '5368709000') as quota_rule, '/storage1/mail/%d/%n' as home, 1011 as uid, 1012 as gid FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id AND u.main_mail_identity_id=i.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%u'` +- `password_query = SELECT password FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id AND u.main_mail_identity_id=i.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%u' AND redirects_to IS NULL` +- `iterate_query = SELECT CONCAT(i.name, '@', d.name) as user FROM users u LEFT JOIN mail_identities i ON i.id=u.main_mail_identity_id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE i.id IS NOT NULL` + +It is recommended to set `default_pass_scheme = ARGON2ID`. diff --git a/app.service b/app.service index 32f2b99..be03794 100644 --- a/app.service +++ b/app.service @@ -1,16 +1,17 @@ [Unit] -Description=WMS website +Description=Rainbox Email website After=network-online.target Wants=network-online.target [Service] Type=simple -User=wms -Group=wms -WorkingDirectory=/home/wms/live +User=rainbox-email +Group=rainbox-email +WorkingDirectory=/home/rainbox-email/live Restart=on-success Environment=NODE_ENV=production ExecStart=/bin/node . +ProtectSystem=yes [Install] WantedBy=multi-user.target From 40c36ef1e1aa52ab58f088bacbe436199027ae30 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Sun, 8 Nov 2020 11:01:43 +0100 Subject: [PATCH 2/6] mail autoconfig: add host_domain config parameter --- config/default.json5 | 1 + config/production.json5 | 1 + src/controllers/MailAutoConfigController.ts | 3 ++- views/mail-auto-config.xml.njk | 8 +++----- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/config/default.json5 b/config/default.json5 index 75f1805..5a5e697 100644 --- a/config/default.json5 +++ b/config/default.json5 @@ -8,6 +8,7 @@ db_log_level: "ERROR", public_url: "http://localhost:4899", public_websocket_url: "ws://localhost:4899", + host_domain: 'localhost', port: 4899, mysql: { connectionLimit: 10, diff --git a/config/production.json5 b/config/production.json5 index c3d13ab..097b32e 100644 --- a/config/production.json5 +++ b/config/production.json5 @@ -3,6 +3,7 @@ db_log_level: "ERROR", public_url: "https://rainbox.email", public_websocket_url: "wss://rainbox.email", + host_domain: 'rainbox.email', session: { cookie: { secure: true diff --git a/src/controllers/MailAutoConfigController.ts b/src/controllers/MailAutoConfigController.ts index e744a03..f7a5c26 100644 --- a/src/controllers/MailAutoConfigController.ts +++ b/src/controllers/MailAutoConfigController.ts @@ -1,6 +1,7 @@ import Controller from "wms-core/Controller"; import {Request, Response} from "express"; import MailDomain from "../models/MailDomain"; +import config from "config"; export default class MailAutoConfigController extends Controller { public routes(): void { @@ -14,7 +15,7 @@ export default class MailAutoConfigController extends Controller { res.contentType('text/xml'); const domains = await MailDomain.select().get(); res.render('mail-auto-config.xml.njk', { - domain: domains[0], + host_domain: config.get('host_domain'), domains: domains, display_name: 'Rainbox Email', display_name_short: 'Rainbox', diff --git a/views/mail-auto-config.xml.njk b/views/mail-auto-config.xml.njk index af19c67..dcc34b1 100644 --- a/views/mail-auto-config.xml.njk +++ b/views/mail-auto-config.xml.njk @@ -1,10 +1,8 @@ - - {{ domain }} - - {% for d in domains %} - {{ d.name }} + + {% for domain in domains %} + {{ domain.name }} {% endfor %} {{ display_name }} From ed3fa80ee1abfccd206c47f0f3602158bfb3ed44 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Sun, 8 Nov 2020 11:02:07 +0100 Subject: [PATCH 3/6] mail autoconfig: also serve /mail/config-v1.1.xml --- src/controllers/MailAutoConfigController.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/controllers/MailAutoConfigController.ts b/src/controllers/MailAutoConfigController.ts index f7a5c26..53f2e85 100644 --- a/src/controllers/MailAutoConfigController.ts +++ b/src/controllers/MailAutoConfigController.ts @@ -5,7 +5,10 @@ import config from "config"; export default class MailAutoConfigController extends Controller { public routes(): void { - this.get('/.well-known/autoconfig/mail/config-v1.1.xml', this.getAutoConfig, 'mail-auto-config'); + this.get([ + '/.well-known/autoconfig/mail/config-v1.1.xml', + '/mail/config-v1.1.xml', + ], this.getAutoConfig, 'mail-auto-config'); } /** From 414f3258c4bf4220c53e9f40118f0ebfde886c68 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Sun, 8 Nov 2020 11:02:28 +0100 Subject: [PATCH 4/6] mail autoconfig: sort domains by ascending name --- src/controllers/MailAutoConfigController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/MailAutoConfigController.ts b/src/controllers/MailAutoConfigController.ts index 53f2e85..0531e3d 100644 --- a/src/controllers/MailAutoConfigController.ts +++ b/src/controllers/MailAutoConfigController.ts @@ -19,7 +19,7 @@ export default class MailAutoConfigController extends Controller { const domains = await MailDomain.select().get(); res.render('mail-auto-config.xml.njk', { host_domain: config.get('host_domain'), - domains: domains, + domains: domains.sort((a, b) => a.name && b.name && a.name > b.name ? 1 : -1), display_name: 'Rainbox Email', display_name_short: 'Rainbox', username: '%EMAILADDRESS%', From 868f9e2683c25353af104b1a64d494615d2967d7 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Sun, 8 Nov 2020 11:11:25 +0100 Subject: [PATCH 5/6] mail autoconfig: load all parameters from app config --- config/default.json5 | 23 ++++++++++++++++- config/production.json5 | 25 ++++++++++++++++-- src/controllers/MailAutoConfigController.ts | 28 ++++++++++----------- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/config/default.json5 b/config/default.json5 index 5a5e697..0789dce 100644 --- a/config/default.json5 +++ b/config/default.json5 @@ -8,7 +8,6 @@ db_log_level: "ERROR", public_url: "http://localhost:4899", public_websocket_url: "ws://localhost:4899", - host_domain: 'localhost', port: 4899, mysql: { connectionLimit: 10, @@ -45,4 +44,26 @@ magic_link: { validity_period: 20, }, + mail_autoconfig: { + main_domain: 'localhost', + display_name: 'Rainbox Email', + display_name_short: 'Rainbox', + username: '%EMAILADDRESS%', + auth_method: 'password-cleartext', + imap: { + server: 'localhost', + port: '143', + method: 'STARTTLS', + }, + pop3: { + server: 'localhost', + port: '110', + method: 'STARTTLS', + }, + smtp: { + server: 'localhost', + port: '587', + method: 'STARTTLS', + }, + }, } diff --git a/config/production.json5 b/config/production.json5 index 097b32e..d8984cb 100644 --- a/config/production.json5 +++ b/config/production.json5 @@ -3,7 +3,6 @@ db_log_level: "ERROR", public_url: "https://rainbox.email", public_websocket_url: "wss://rainbox.email", - host_domain: 'rainbox.email', session: { cookie: { secure: true @@ -16,5 +15,27 @@ approval_mode: true, magic_link: { validity_period: 900, - } + }, + mail_autoconfig: { + main_domain: 'rainbox.email', + display_name: 'Rainbox Email', + display_name_short: 'Rainbox', + username: '%EMAILADDRESS%', + auth_method: 'password-cleartext', + imap: { + server: 'rainbox.email', + port: '143', + method: 'STARTTLS', + }, + pop3: { + server: 'rainbox.email', + port: '110', + method: 'STARTTLS', + }, + smtp: { + server: 'rainbox.email', + port: '587', + method: 'STARTTLS', + }, + }, } diff --git a/src/controllers/MailAutoConfigController.ts b/src/controllers/MailAutoConfigController.ts index 0531e3d..48593de 100644 --- a/src/controllers/MailAutoConfigController.ts +++ b/src/controllers/MailAutoConfigController.ts @@ -18,26 +18,26 @@ export default class MailAutoConfigController extends Controller { res.contentType('text/xml'); const domains = await MailDomain.select().get(); res.render('mail-auto-config.xml.njk', { - host_domain: config.get('host_domain'), + host_domain: config.get('mail_autoconfig.main_domain'), domains: domains.sort((a, b) => a.name && b.name && a.name > b.name ? 1 : -1), - display_name: 'Rainbox Email', - display_name_short: 'Rainbox', - username: '%EMAILADDRESS%', - auth_method: 'password-cleartext', + display_name: config.get('mail_autoconfig.display_name'), + display_name_short: config.get('mail_autoconfig.display_name_short'), + username: config.get('mail_autoconfig.username'), + auth_method: config.get('mail_autoconfig.auth_method'), imap: { - server: 'rainbox.email', - port: '143', - method: 'STARTTLS', + server: config.get('mail_autoconfig.imap.server'), + port: config.get('mail_autoconfig.imap.port'), + method: config.get('mail_autoconfig.imap.method'), }, pop3: { - server: 'rainbox.email', - port: '110', - method: 'STARTTLS', + server: config.get('mail_autoconfig.pop3.server'), + port: config.get('mail_autoconfig.pop3.port'), + method: config.get('mail_autoconfig.pop3.method'), }, smtp: { - server: 'rainbox.email', - port: '587', - method: 'STARTTLS', + server: config.get('mail_autoconfig.smtp.server'), + port: config.get('mail_autoconfig.smtp.port'), + method: config.get('mail_autoconfig.smtp.method'), }, }); } From 3b5b27b6a2ad05e7f08690a9bed1fcca9e1203ca Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Sun, 8 Nov 2020 11:13:21 +0100 Subject: [PATCH 6/6] Version 2.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 55547bb..b0bd05f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rainbox.email", - "version": "2.0.2", + "version": "2.1.0", "description": "ISP mail provider manager with mysql and integrated LDAP server", "repository": "https://gitlab.com/ArisuOngaku/rainbox.email", "author": "Alice Gaudon ",