This commit is contained in:
2022-12-30 16:23:27 +00:00
parent 02776e8478
commit 20da343c54
1304 changed files with 870224 additions and 0 deletions

1090
app/docs/api.md Normal file

File diff suppressed because it is too large Load Diff

BIN
app/docs/archi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
app/docs/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

15
app/docs/build-image.md Normal file
View File

@ -0,0 +1,15 @@
To build a multi-architecture image, you need to use `buildx`.
Here's the command to build and push the images from a Mac M1:
1) First create a new buildx environment (or context). This is only necessary for the first time.
```bash
docker buildx create --use
```
2) Build and push the image. Replace `simplelogin/name:tag` by the correct docker image name and tag.
```bash
docker buildx build --platform linux/amd64,linux/arm64 --push -t simplelogin/name:tag
```

View File

@ -0,0 +1,10 @@
# TODO
`local_data/`: contain files used only locally. In deployment, these files should be replaced.
- jwtRS256.key: generated using
```bash
ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key
# Don't add passphrase
openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub
```

BIN
app/docs/custom-alias.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
app/docs/diagram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

51
app/docs/enforce-spf.md Normal file
View File

@ -0,0 +1,51 @@
Some email services like Gmail, Proton Mail, etc don't have a strict SPF record (`-all`) to support the "classic" email forwarding
that is usually used for group mailing list. In this scenario, an email is sent to a group is forwarded as-is,
breaking therefore the SPF.
A malicious hacker could use this security fail to impersonate your alias via the reverse-alias. This rarely happens
as the reverse-alias is generated randomly and is unique for each sender.
However if you want to prevent this kind of attack, you can enforce the SPF policy even if your mailbox uses a "soft" policy.
1) Install `postfix-pcre`
```bash
apt install -y postfix-pcre
```
2) Add `/etc/postfix/body_checks.pcre` file with the following content
```
/^X-SimpleLogin-Client-IP:/ IGNORE
```
3) Add `/etc/postfix/client_headers.pcre` with the following content
```
/^([0-9a-f:.]+)$/ prepend X-SimpleLogin-Client-IP: $1
```
4) Add the following lines to your Postfix config file at `/etc/postfix/main.cf`
```
body_checks = pcre:/etc/postfix/body_checks.pcre
smtpd_client_restrictions = pcre:/etc/postfix/client_headers.pcre
```
5) Enable `ENFORCE_SPF` in your SimpleLogin config file
```
ENFORCE_SPF=true
```
6) Restart Postfix
```bash
systemctl restart postfix
```
7) Restart SimpleLogin mail handler
```bash
sudo docker restart sl-email
```

200
app/docs/gmail-relay.md Normal file
View File

@ -0,0 +1,200 @@
# Using Gmail as SMTP relay to send email from SimpleLogin
###### port 25 blocked by ISP...?
> you can use postfix with a Gmail SMTP relay... So Postfix will send on port 587.
## How to:
- create a Gmail account
- set MFA
- create an app password
- update firewall's rules for port 587
- update Postfix conf:
=> nano /etc/postfix/master.cf
```
...
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - y - - smtpd
#smtp inet n - y - 1 postscreen
#smtpd pass - - y - - smtpd
#dnsblog unix - - y - 0 dnsblog
#tlsproxy unix - - y - 0 tlsproxy
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_auth_only=yes
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_client_restrictions=$mua_client_restrictions
# -o smtpd_helo_restrictions=$mua_helo_restrictions
...
```
=> nano /etc/postfix/sasl_passwd
```
[smtp.gmail.com]:587 email_created@gmail.com:app_password_created
```
=> postmap /etc/postfix/sasl_passwd
=> chmod 600 /etc/postfix/sasl_passwd
=> nano /etc/postfix/main.cf
```
# POSTFIX config file, adapted for SimpleLogin
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no
# appending .domain is the MUA's job.
append_dot_mydomain = no
# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h
readme_directory = no
# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
# fresh installs.
compatibility_level = 2
# TLS parameters
smtpd_tls_cert_file=/etc/letsencrypt/live/app.mydomain.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/app.mydomain.com/privkey.pem
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_security_level = may
smtpd_tls_security_level = may
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.
alias_maps = hash:/etc/aliases
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.0.0.0/24
# Set your domain here
mydestination = localhost.localdomain, localhost
myhostname = app.mydomain.com
mydomain = mydomain.com
myorigin = /etc/mailname
relay_domains = pgsql:/etc/postfix/pgsql-relay-domains.cf
transport_maps = pgsql:/etc/postfix/pgsql-transport-maps.cf
# HELO restrictions
smtpd_delay_reject = yes
smtpd_helo_required = yes
smtpd_helo_restrictions =
permit_mynetworks,
reject_non_fqdn_helo_hostname,
reject_invalid_helo_hostname,
permit
# Sender restrictions:
smtpd_sender_restrictions =
permit_mynetworks,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
permit
# Recipient restrictions:
smtpd_recipient_restrictions =
reject_unauth_pipelining,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
permit_mynetworks,
reject_unauth_destination,
reject_rbl_client zen.spamhaus.org,
reject_rbl_client bl.spamcop.net,
permit
# Enfore SPF
body_checks = pcre:/etc/postfix/body_checks.pcre
smtpd_client_restrictions = pcre:/etc/postfix/client_headers.pcre
# Postfix conf
mailbox_size_limit = 10000000000
recipient_delimiter = -
inet_interfaces = all
inet_protocols = ipv4
# Relay Gmail
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_tls_security_options = noanonymous
header_size_limit = 4096000
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
relayhost = [smtp.gmail.com]:587
```
>cat /etc/hosts
>
>127.0.0.1 localhost.localdomain localhost
- restart Postfix:
=> systemctl reload postfix
=> service postfix restart
- update SimpleLogin conf:
=> nano /simplelogin.env
```
# WebApp URL
URL=http://app.mydomain.com
# domain used to create alias
EMAIL_DOMAIN=mydomaine.com
# transactional email is sent from this email address
SUPPORT_EMAIL=support@mydomain.com
# custom domain needs to point to these MX servers
EMAIL_SERVERS_WITH_PRIORITY=[(10, "app.mydomain.com.")]
# By default, new aliases must end with ".{random_word}". This is to avoid a person taking all "nice" aliases.
# this option doesn't make sense in self-hosted. Set this variable to disable this option.
DISABLE_ALIAS_SUFFIX=1
# the DKIM private key used to compute DKIM-Signature
DKIM_PRIVATE_KEY_PATH=/dkim.key
# DB Connection
DB_URI=postgresql://mysqluser:mysqlpassword@sl-db:5432/simplelogin
FLASK_SECRET=SomeThing_Secret
GNUPGHOME=/sl/pgp
LOCAL_FILE_UPLOAD=1
# Postfix 587 TLS
POSTFIX_PORT=587
POSTFIX_SUBMISSION_TLS=true
# Enforce SPF
ENFORCE_SPF=true
```
- restart SL-Mail:
=> docker restart sl-email
=> reboot
> for debug:
>
> view system logs => tail -f /var/log/syslog
>
> view postfix logs => tail -f /var/log/mail.log
>
> view postfix queue => mailq
>
> delete postfix queue => postsuper -d ALL
;-)

BIN
app/docs/hero.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

49
app/docs/hero.svg Normal file
View File

@ -0,0 +1,49 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1105" height="1131" viewBox="0 0 1105 1131">
<defs>
<linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#e3156a"/>
<stop offset="1" stop-color="#91187f"/>
</linearGradient>
<clipPath id="clip-Artboard_3">
<rect width="1105" height="1131"/>
</clipPath>
</defs>
<g id="Artboard_3" data-name="Artboard 3" clip-path="url(#clip-Artboard_3)">
<rect width="1105" height="1131" fill="#fff"/>
<path id="Icon_simple-groupon" data-name="Icon simple-groupon" d="M7.6,46.6A26.694,26.694,0,0,0,27.527,55,27.933,27.933,0,0,0,50.394,43.168,26.235,26.235,0,0,0,55,27.688c0-1.109-.073-2.305-.144-3.5H24.28V34.748H39.6A13.689,13.689,0,0,1,27.527,41.9c-7.4,0-14.036-6.472-14.036-14.889A13.963,13.963,0,0,1,27.527,13.1c4.226,0,7.689,1.716,11.025,5.131H53.494C49.2,6.919,39.151,0,27.69,0A27.308,27.308,0,0,0,8.142,7.812,26.319,26.319,0,0,0,0,26.936,27.257,27.257,0,0,0,7.6,46.6Z" transform="translate(181 141)" fill="rgba(66,150,56,0.69)"/>
<text id="groupon_alias.com" data-name="groupon@alias.com" transform="translate(91.809 596.283)" fill="#c11672" font-size="26" font-family="HelveticaNeue, Helvetica Neue" opacity="0.997"><tspan x="0" y="0">groupon@alias.com</tspan></text>
<text id="meetup_alias.com" data-name="meetup@alias.com" transform="translate(800.967 594.607)" fill="#b91674" font-size="26" font-family="HelveticaNeue, Helvetica Neue" opacity="0.997"><tspan x="0" y="0">meetup@alias.com</tspan></text>
<text id="facebook_alias.com" data-name="facebook@alias.com" transform="translate(444.654 594.565)" fill="#bc1673" font-size="26" font-family="HelveticaNeue, Helvetica Neue" opacity="0.997"><tspan x="0" y="0">facebook@alias.com</tspan></text>
<path id="Icon_simple-meetup" data-name="Icon simple-meetup" d="M54.948,44.712c-.7-4.425-8.878-1.017-9.386-5.864-.717-6.87,9.51-21.676,8.7-27.435C53.546,6.245,50.044,5.157,47.01,5.1c-2.942-.046-3.719.417-4.716,1A1.772,1.772,0,0,1,39.746,6c-.765-.729-1.276-1.228-2.074-1.877a4.388,4.388,0,0,0-2.166-.905,7.109,7.109,0,0,0-3.419.383,9.429,9.429,0,0,0-2.351,1.716c-.74.649-2.628,2.745-4.379,1.968-.768-.332-3.341-1.618-5.207-2.418-3.582-1.551-8.759.962-10.624,4.276-2.78,4.925-8.25,24.3-9.084,26.846-1.854,5.734,2.365,10.4,8.041,10.138,2.411-.117,4.01-.985,5.527-3.754.88-1.588,9.118-23.115,9.735-24.16a2.7,2.7,0,0,1,3.185-1.089,2.916,2.916,0,0,1,1.331,3.256c-.312,2.051-6.116,15.191-6.35,16.671-.371,2.528.823,3.928,3.453,4.065,1.8.094,3.591-.543,5-3.231.8-1.494,9.966-19.859,10.775-21.087.894-1.343,1.611-1.785,2.528-1.737.708.034,1.831.22,1.554,2.328-.28,2.074-7.661,15.537-8.424,18.839a9.752,9.752,0,0,0,5.365,10.835c2.548,1.251,13.681,3.382,12.78-2.353Z" transform="translate(902 139.845)" fill="rgba(237,65,65,0.81)"/>
<path id="Icon_awesome-facebook-square" data-name="Icon awesome-facebook-square" d="M49.107,2.25H5.893A5.893,5.893,0,0,0,0,8.143V51.357A5.893,5.893,0,0,0,5.893,57.25h16.85v-18.7H15.008v-8.8h7.734V23.042c0-7.63,4.542-11.845,11.5-11.845a46.856,46.856,0,0,1,6.816.594V19.28H37.22c-3.782,0-4.962,2.347-4.962,4.755V29.75H40.7l-1.35,8.8H32.257v18.7h16.85A5.893,5.893,0,0,0,55,51.357V8.143A5.893,5.893,0,0,0,49.107,2.25Z" transform="translate(550 136.75)" fill="rgba(78,85,165,0.79)"/>
<path id="Icon_awesome-toggle-on" data-name="Icon awesome-toggle-on" d="M30,4.5H15a15,15,0,1,0,0,30H30a15,15,0,1,0,0-30Zm0,25a10,10,0,1,1,10-10A9.994,9.994,0,0,1,30,29.5Z" transform="translate(251 512.5)" fill="#aa1778"/>
<path id="Icon_awesome-toggle-on-2" data-name="Icon awesome-toggle-on" d="M30,4.5H15a15,15,0,1,0,0,30H30a15,15,0,1,0,0-30Zm0,25a10,10,0,1,1,10-10A9.994,9.994,0,0,1,30,29.5Z" transform="translate(965 503.5)" fill="#b91674"/>
<path id="Icon_awesome-toggle-off" data-name="Icon awesome-toggle-off" d="M30,4.5H15a15,15,0,1,0,0,30H30a15,15,0,1,0,0-30ZM5,19.5a10,10,0,1,1,10,10A9.995,9.995,0,0,1,5,19.5Zm25,10H26.179a14.994,14.994,0,0,0,0-20H30a10,10,0,0,1,0,20Z" transform="translate(625 511.5)" fill="#c61671"/>
<path id="Icon_material-mail-outline" data-name="Icon material-mail-outline" d="M57,6H9a5.992,5.992,0,0,0-5.97,6L3,48a6.018,6.018,0,0,0,6,6H57a6.018,6.018,0,0,0,6-6V12A6.018,6.018,0,0,0,57,6Zm0,42H9V18L33,33,57,18ZM33,27,9,12H57Z" transform="translate(173 502)" fill="#7bb674"/>
<path id="Icon_material-mail-outline-2" data-name="Icon material-mail-outline" d="M57,6H9a5.992,5.992,0,0,0-5.97,6L3,48a6.018,6.018,0,0,0,6,6H57a6.018,6.018,0,0,0,6-6V12A6.018,6.018,0,0,0,57,6Zm0,42H9V18L33,33,57,18ZM33,27,9,12H57Z" transform="translate(547 499)" fill="#7379b8"/>
<path id="Icon_material-mail-outline-3" data-name="Icon material-mail-outline" d="M57,6H9a5.992,5.992,0,0,0-5.97,6L3,48a6.018,6.018,0,0,0,6,6H57a6.018,6.018,0,0,0,6-6V12A6.018,6.018,0,0,0,57,6Zm0,42H9V18L33,33,57,18ZM33,27,9,12H57Z" transform="translate(887 499)" fill="#f06565"/>
<line id="Line_1" data-name="Line 1" x1="1" y2="258" transform="translate(205.5 218.5)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<line id="Line_4" data-name="Line 4" x1="1" y2="258" transform="translate(931.5 204.5)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<line id="Line_2" data-name="Line 2" y2="85" transform="translate(580.5 217.5)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<line id="Line_3" data-name="Line 3" y2="108" transform="translate(580.5 361.5)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<path id="Path_186" data-name="Path 186" d="M-164.529,1669.5l16.008,14.3,17.483-14.3" transform="translate(729 -1202)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<path id="Path_191" data-name="Path 191" d="M-164.529,1669.5l16.008,14.3,17.483-14.3" transform="translate(354 -1201)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<path id="Path_192" data-name="Path 192" d="M-164.529,1669.5l16.008,14.3,17.483-14.3" transform="translate(1080 -1215)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<path id="Icon_ionic-md-paper-plane" data-name="Icon ionic-md-paper-plane" d="M3.375,27.487l12.862,4.825,1.6,16.064,8.037-11.25,11.25,11.25,11.25-45Zm31.9,13.63-8.968-9.032L38.737,14.625,19.125,29.531l-7.431-2.683,31.478-16.9Z" transform="matrix(-0.174, 0.985, -0.985, -0.174, 203.577, 332.524)" fill="#c11672"/>
<path id="Icon_ionic-md-paper-plane-2" data-name="Icon ionic-md-paper-plane" d="M3.375,27.487l12.862,4.825,1.6,16.064,8.037-11.25,11.25,11.25,11.25-45Zm31.9,13.63-8.968-9.032L38.737,14.625,19.125,29.531l-7.431-2.683,31.478-16.9Z" transform="matrix(-0.174, 0.985, -0.985, -0.174, 929.577, 318.524)" fill="#c11672"/>
<g id="Icon_ionic-md-mail-unread" data-name="Icon ionic-md-mail-unread" transform="translate(529.75 896.5)">
<path id="Path_187" data-name="Path 187" d="M34.875,9a4.5,4.5,0,1,1-4.5-4.5,4.5,4.5,0,0,1,4.5,4.5Z" transform="translate(57.375)" fill="#af1677"/>
<path id="Path_188" data-name="Path 188" d="M71.852,30.254,46.681,47.139,11.771,23.727V15.205l34.91,23.411L66.735,25.164A18.039,18.039,0,0,1,66.5,5.625H10.72a8.517,8.517,0,0,0-8.47,8.522V67.376A8.517,8.517,0,0,0,10.72,75.9H82.662a8.517,8.517,0,0,0,8.47-8.522V30.393a17.762,17.762,0,0,1-19.28-.14Z" transform="translate(0 0)" fill="#af1677"/>
</g>
<path id="Path_189" data-name="Path 189" d="M-147.165,1816s-43.6,110.247,31.553,178.6,104.424,7.328,185.53,15.373S171,2081.49,171,2081.49" transform="translate(353 -1200)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<path id="Path_190" data-name="Path 190" d="M152,2079.774l22.535,5.764v-20.9" transform="translate(355.277 -1200)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 4"/>
<text id="X" transform="translate(567 352)" fill="#b11777" font-size="44" font-family="HelveticaNeue, Helvetica Neue"><tspan x="0" y="0">X</tspan></text>
<text id="my-real-email_example.com" data-name="my-real-email@example.com" transform="translate(397 1006)" fill="#ae0721" font-size="30" font-family="HelveticaNeue, Helvetica Neue"><tspan x="0" y="0">my-real-email@example.com</tspan></text>
<path id="Icon_map-locksmith" data-name="Icon map-locksmith" d="M31.075,15.12H29.52V8.9c0-4.088-4.1-8.185-8.189-8.185H14.5C10.418.72,6.48,4.817,6.48,8.9V15.12H4.759a1.544,1.544,0,0,0-1.159,1.2v18.33c0,.431.672.635,1.159.635H31.075c.489,0,1.325-.2,1.325-.635V16.315a1.76,1.76,0,0,0-1.325-1.2ZM21.393,32.4H14.445L15.9,25.224a3.723,3.723,0,0,1-1.458-2.956,3.527,3.527,0,0,1,3.474-3.524,3.428,3.428,0,0,1,3.475,3.406,4,4,0,0,1-1.457,3.094ZM24.48,15.12H11.52V8.9A2.944,2.944,0,0,1,14.574,5.76h6.688A3.076,3.076,0,0,1,24.48,8.9Z" transform="translate(285.93 767)" fill="url(#linear-gradient)"/>
<path id="Icon_map-locksmith-2" data-name="Icon map-locksmith" d="M31.075,15.12H29.52V8.9c0-4.088-4.1-8.185-8.189-8.185H14.5C10.418.72,6.48,4.817,6.48,8.9V15.12H4.759a1.544,1.544,0,0,0-1.159,1.2v18.33c0,.431.672.635,1.159.635H31.075c.489,0,1.325-.2,1.325-.635V16.315a1.76,1.76,0,0,0-1.325-1.2ZM21.393,32.4H14.445L15.9,25.224a3.723,3.723,0,0,1-1.458-2.956,3.527,3.527,0,0,1,3.474-3.524,3.428,3.428,0,0,1,3.475,3.406,4,4,0,0,1-1.457,3.094ZM24.48,15.12H11.52V8.9A2.944,2.944,0,0,1,14.574,5.76h6.688A3.076,3.076,0,0,1,24.48,8.9Z" transform="translate(713.93 709)" fill="url(#linear-gradient)"/>
<path id="Path_195" data-name="Path 195" d="M852.538,1776.159s-40.43,11.784-54.916,60,0,81.47,0,81.47,11.734,48.231,48.454,32.742,6.461-52.778,6.461-52.778-32.971-17.76-73.978,14.531-92.788,152.565-92.788,152.565" transform="translate(-37.825 -1155.685)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 6"/>
<path id="Path_196" data-name="Path 196" d="M294.5,2009.748l-2.011,17.9,15.542-6.695" transform="translate(351 -1114)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 4"/>
<path id="Path_197" data-name="Path 197" d="M-159.743,1740.307l15.2-15.786,7.495,20.667" transform="translate(354 -1119)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 4"/>
<path id="Path_198" data-name="Path 198" d="M453.9,1730.937l19.345,3.03-10.607,18.592" transform="translate(353 -1119)" fill="none" stroke="#707070" stroke-width="3" stroke-dasharray="4 4"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

57
app/docs/oauth.md Normal file
View File

@ -0,0 +1,57 @@
## OAuth
SL currently supports code and implicit flow.
#### Code flow
To trigger the code flow locally, you can go to the [following url](http://localhost:7777/oauth/authorize?client_id=client-id&state=123456&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A7000%2Fcallback&state=random_string) after running `python server.py`:
You should see the authorization page where user is asked for permission to share their data. Once user approves, user is redirected to this url with an `authorization code`: `http://localhost:7000/callback?state=123456&code=the_code`
Next, exchange the code to get the token with `{code}` replaced by the code obtained in previous step. The `http` tool used here is [httpie](https://httpie.org)
```
http -f -a client-id:client-secret http://localhost:7777/oauth/token grant_type=authorization_code code={code}
```
This should return an `access token` that allows to get user info via the following command. Again, `http` is used.
```
http http://localhost:7777/oauth/user_info 'Authorization:Bearer {token}'
```
#### Implicit flow
Similar to code flow, except for the the `access token` which we we get back with the redirection.
For implicit flow, you can use [this url](http://localhost:7777/oauth/authorize?client_id=client-id&state=123456&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3A7000%2Fcallback&state=random_string)
#### OpenID and OAuth2 response_type & scope
According to the sharing web blog titled [Diagrams of All The OpenID Connect Flows](https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660), we should pay attention to:
- `response_type` can be either `code, token, id_token` or any combination of those attributes.
- `scope` might contain `openid`
Below are the potential combinations that are taken into account in SL until now:
```
response_type=code
scope:
with `openid` in scope, return `id_token` at /token: OK
without: OK
response_type=token
scope:
with and without `openid`, nothing to do: OK
response_type=id_token
return `id_token` in /authorization endpoint
response_type=id_token token
return `id_token` in addition to `access_token` in /authorization endpoint
response_type=id_token code
return `id_token` in addition to `authorization_code` in /authorization endpoint
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

15
app/docs/postfix-tls.md Normal file
View File

@ -0,0 +1,15 @@
In case your Postfix server is on another server, it's recommended to enable TLS on Postfix submission to
secure the connection between SimpleLogin email handler and Postfix.
This can be enabled by adding those lines at the end of `/etc/postfix/master.cf`
```
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_auth_only=yes
```
Make sure to set the `POSTFIX_SUBMISSION_TLS` variable to `true` in the SimpleLogin `simplelogin.env` file.

68
app/docs/ses.md Normal file
View File

@ -0,0 +1,68 @@
Contribution from https://github.com/havedill/
## Integrating with Amazon SES
If you're self hosting, here is the method I used to route emails through Amazon's SES service.
For me, when hosting on AWS the public IP is widely blacklisted for abuse. If you have an SES account, you are whitelisted, use TLS, and amazon creates the DKIM records.
First, I modify the postfix inet protocols to only route via IPv4: in `/etc/postfix/main.cf`, change `inet_protocols = ipv4`
### Amazon Simple Email Service Console:
First, verify your domain with SES, and check off "Generate DKIM Records".
<img src=https://i.imgur.com/9KeIlhA.png>
I use Route53, so pressing the Use Route53 button will automatically generate my DNS values. If you do not use Route53, you will have to create them on your DNS provider.
If you do choose route53, this is what generating the record sets looks like
<img src=https://i.imgur.com/8FSHehx.png>
Now, in SES we need to generate SMTP Credentials to use. Go to the SMTP settings tab, and create credentails. Also note your server name, port, etc.
<img src=https://i.imgur.com/FcFjrCO.png>
Now on your server, run the following (Updating the SMTP DNS address to match what you see in the SMTP settings tab of SES)
```
sudo postconf -e "relayhost = [email-smtp.us-east-1.amazonaws.com]:587" \
"smtp_sasl_auth_enable = yes" \
"smtp_sasl_security_options = noanonymous" \
"smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd" \
"smtp_use_tls = yes" \
"smtp_tls_security_level = may" \
"smtp_tls_note_starttls_offer = yes"
```
Now let's create `/etc/postfix/sasl_passwd` and inside put your SMTP Setting values;
`[email-smtp.us-east-1.amazonaws.com]:587 SMTPUSERNAME:SMTPPASSWORD`
Create a hashmap with `sudo postmap hash:/etc/postfix/sasl_passwd`
Secure the files (optional but recommended)
```
sudo chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
```
For Ubuntu, we point postfix to the CA Certs;
```bash
sudo postconf -e 'smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt'
```
Also make sure that Postfix is able to authenticate successfully by installing the SASL package:
```bash
sudo apt install libsasl2-modules
```
Then restart postfix
```bash
sudo systemctl restart postfix
```
and you should see the mail in `/var/log/mail.log` and in your alias emails routed through Amazons servers!
<img src=https://i.imgur.com/0qLiqmH.png>

60
app/docs/ssl.md Normal file
View File

@ -0,0 +1,60 @@
# SSL, HTTPS, and HSTS
It's highly recommended to enable SSL/TLS on your server, both for the web app and email server.
## Using Certbot to get a certificate
This doc will use https://letsencrypt.org to get a free SSL certificate for app.mydomain.com that's used by both Postfix and Nginx. Let's Encrypt provides Certbot, a tool to obtain and renew SSL certificates.
To install Certbot, please follow instructions on https://certbot.eff.org
Then obtain a certificate for Nginx, use the following command. You'd need to provide an email so Let's Encrypt can send you notifications when your domain is about to expire.
```bash
sudo certbot --nginx
```
After this step, you should see some "managed by Certbot" lines in `/etc/nginx/sites-enabled/simplelogin`
### Securing Postfix
Now let's use the new certificate for our Postfix.
Replace these lines in /etc/postfix/main.cf
```
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
```
with
```
smtpd_tls_cert_file = /etc/letsencrypt/live/app.mydomain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/app.mydomain.com/privkey.pem
```
Make sure to replace app.mydomain.com with your own domain.
### Updating `simplelogin.env`
Make sure to change the `URL` in `simplelogin.env` to `https://app.mydomain.com`, otherwise not all page assets will load securely, and some functionality (e.g. Webauthn) will break.
You will need to reload the docker containers for this to take effect.
## HTTP Strict Transport Security (HSTS)
HSTS is an extra step you can take to protect your web app from certain man-in-the-middle attacks. It does this by specifying an amount of time (usually a really long one) for which you should only accept HTTPS connections, not HTTP ones. Because of this **you should only enable HSTS once you know HTTPS is working correctly**, as otherwise you may find your browser blocking you from accessing your own web app.
To enable HSTS, add the following line to the `server` block of the Nginx configuration file:
```
add_header Strict-Transport-Security "max-age: 31536000; includeSubDomains" always;
```
(The `max-age` is the time in seconds to not permit a HTTP connection, in this case it's one year.)
Now, reload Nginx:
```bash
sudo systemctl reload nginx
```

View File

@ -0,0 +1,65 @@
# Troubleshooting
## A. If you can't receive a welcome email when signing up
This can either mean:
1) Postfix can't send emails to your mailbox
2) The `sl-app` container can't connect to Postfix (run on the host)
### A.1
To test 1), running `swaks --to your-mailbox@mail.com` should send you an email.
Make sure to replace `your-mailbox@mail.com` by your mailbox address.
`swaks` can be installed with `sudo apt install swaks` on Debian-based OS.
### A.2
Once 1) works, we can test the 2) by
a) first connecting to the container by `docker exec -it sl-app bash`
b) then run the following commands
```bash
apt update
apt install telnet -y
telnet 10.0.0.1 25
```
If the `telnet 10.0.0.1 25` doesn't work, it means Postfix can't be reached from the docker container.
This means an issue with the Docker network.
You can then try `telnet 172.17.0.1 25` as `172.17.0.1` is *usually* the host IP address. If this works, then you can set
the `POSTFIX_SERVER=172.17.0.1` in your SimpleLogin config file `~/simplelogin.env` and re-run all the containers.
If not, please run through the self-hosting instructions and make sure no step is missed.
## B. You send an email to your alias and can't receive the forwarded email on your mailbox
This can be either due to:
1) Postfix doesn't recognize the alias domain
2) Postfix can't connect to the `sl-email` container
3) `sl-email` container can't connect to Postfix
4) Postfix can't send emails to
### B.1
For 1), this can mean the `/etc/postfix/pgsql-relay-domains.cf` and `/etc/postfix/pgsql-transport-maps.cf` aren't correctly set up.
To test 1), `postmap -q mydomain.com pgsql:/etc/postfix/pgsql-relay-domains.cf` should return `mydomain.com`.
And `postmap -q not-exist.com pgsql:/etc/postfix/pgsql-relay-domains.cf` should return nothing.
`postmap -q mydomain.com pgsql:/etc/postfix/pgsql-transport-maps.cf` should return `smtp:127.0.0.1:20381`
And `postmap -q not-exist.com pgsql:/etc/postfix/pgsql-transport-maps.cf` should return nothing.
### B.2
For 2), you can check in the `sl-email` log by running `docker logs sl-email` and if the incoming email doesn't appear there,
then it means Postfix can't connect to the `sl-email` container. Please run through the self-hosting instructions and
make sure no step is missed.
### B.3
For 3), you can check in the `sl-email` log by running `docker logs sl-email` and make sure there's no error there.
### B.4
For 4), please refer to the A.1 section to make sure Postfix can send emails to your mailbox.

16
app/docs/ufw.md Normal file
View File

@ -0,0 +1,16 @@
SimpleLogin needs to have the following ports open:
- 22: so you SSH into the server
- 25: to receive the incoming emails
- 80 and optionally 443 for SimpleLogin webapp
If you use `UFW` Firewall, you could run the following commands to open these ports:
```bash
sudo ufw allow 22
sudo ufw allow 25
sudo ufw allow 80
# optional, enable 443 if you set up TLS for the webapp
sudo ufw allow 443
```

210
app/docs/upgrade.md Normal file
View File

@ -0,0 +1,210 @@
Upgrading SimpleLogin usually consists of simply pulling the latest version, stop & re-run SimpleLogin containers: *sl-migration*, *sl-app* and *sl-email*. It's not necessary to restart *sl-db* as it uses Postgres image.
No emails or any data is lost in the upgrade process. The same process is by the way used by the SimpleLogin SaaS version which is deployed several times per day.
Sometimes upgrading to a major version might require running a manual migration. This is for example the case when upgrading to 2.0.0. In this case please follow the corresponding migration first before running these scripts.
If you are running versions prior to 3x, please:
1. first upgrade to 2.1.2 then
2. upgrade to the latest version which is 3.4.0
<details>
<summary>After upgrade to 3x from 2x</summary>
<p>
3x has some data structure changes that cannot be automatically upgraded from 2x.
Once you have upgraded your installation to 3x, please run the following scripts to make your data fully compatible with 3x
First connect to your SimpleLogin container shell:
```bash
docker exec -it sl-app python shell.py
```
Then copy and run this below script:
```python
from app.extensions import db
from app.models import AliasUsedOn, Contact, EmailLog
for auo in AliasUsedOn.query.all():
auo.user_id = auo.alias.user_id
db.session.commit()
for contact in Contact.query.all():
contact.user_id = contact.alias.user_id
db.session.commit()
for email_log in EmailLog.query.all():
email_log.user_id = email_log.contact.user_id
db.session.commit()
```
</p>
</details>
<details>
<summary>Upgrade to 2.1.0 from 2.0.0</summary>
<p>
2.1.0 comes with PGP support. If you use PGP, please follow these steps to enable this feature:
1) In your home directory (where `dkim.key` is located), create directory to store SimpleLogin data
```bash
mkdir sl
mkdir sl/pgp # to store PGP key
mkdir sl/db # to store database
```
2) Then add this line to your config simplelogin.env file
```
GNUPGHOME=/sl/pgp # where to store PGP keys
```
Now you can follow the usual steps to upgrade SimpleLogin.
</p>
</details>
<details>
<summary>Upgrade to 2.0.0</summary>
<p>
2.0.0 comes with mailbox feature that requires running a script that puts all existing users to "full-mailbox" mode.
1) First please make sure to upgrade to 1.0.5 which is the latest version before 2.0.0.
2) Then connect to your SimpleLogin container shell:
```bash
docker exec -it sl-app python shell.py
```
3) Finally copy and run this below script:
```python
"""This ad-hoc script is to be run when upgrading from 1.0.5 to 2.0.0
"""
from app.extensions import db
from app.log import LOG
from app.models import Mailbox, Alias, User
for user in User.query.all():
if user.default_mailbox_id:
# already run the migration on this user
continue
# create a default mailbox
default_mb = Mailbox.get_by(user_id=user.id, email=user.email)
if not default_mb:
LOG.d("create default mailbox for user %s", user)
default_mb = Mailbox.create(user_id=user.id, email=user.email, verified=True)
db.session.commit()
# assign existing alias to this mailbox
for gen_email in Alias.query.filter_by(user_id=user.id):
if not gen_email.mailbox_id:
LOG.d("Set alias %s mailbox to default mailbox", gen_email)
gen_email.mailbox_id = default_mb.id
# finally set user to full_mailbox
user.full_mailbox = True
user.default_mailbox_id = default_mb.id
db.session.commit()
```
</p>
</details>
## Upgrade to the latest version 3.4.0
```bash
# Pull the latest version
sudo docker pull simplelogin/app:3.4.0
# Stop SimpleLogin containers
sudo docker stop sl-email sl-migration sl-app sl-db sl-job-runner
# Make sure to remove these containers to avoid conflict
sudo docker rm -f sl-email sl-migration sl-app sl-db
# create ./sl/upload/ if not exist
mkdir -p ./sl/upload/
# Run the database container. Make sure to replace `myuser` and `mypassword`
docker run -d \
--name sl-db \
-e POSTGRES_PASSWORD=mypassword \
-e POSTGRES_USER=myuser \
-e POSTGRES_DB=simplelogin \
-p 127.0.0.1:5432:5432 \
-v $(pwd)/sl/db:/var/lib/postgresql/data \
--restart always \
--network="sl-network" \
postgres:12.1
# Run the database migration
sudo docker run --rm \
--name sl-migration \
-v $(pwd)/sl:/sl \
-v $(pwd)/sl/upload:/code/static/upload \
-v $(pwd)/dkim.key:/dkim.key \
-v $(pwd)/dkim.pub.key:/dkim.pub.key \
-v $(pwd)/simplelogin.env:/code/.env \
--network="sl-network" \
simplelogin/app:3.4.0 flask db upgrade
# Run init data
sudo docker run --rm \
--name sl-init \
-v $(pwd)/sl:/sl \
-v $(pwd)/sl/upload:/code/static/upload \
-v $(pwd)/simplelogin.env:/code/.env \
-v $(pwd)/dkim.key:/dkim.key \
-v $(pwd)/dkim.pub.key:/dkim.pub.key \
--network="sl-network" \
simplelogin/app:3.4.0 python init_app.py
# Run the webapp container
sudo docker run -d \
--name sl-app \
-v $(pwd)/sl:/sl \
-v $(pwd)/sl/upload:/code/static/upload \
-v $(pwd)/simplelogin.env:/code/.env \
-v $(pwd)/dkim.key:/dkim.key \
-v $(pwd)/dkim.pub.key:/dkim.pub.key \
-p 127.0.0.1:7777:7777 \
--restart always \
--network="sl-network" \
simplelogin/app:3.4.0
# Run the email handler container
sudo docker run -d \
--name sl-email \
-v $(pwd)/sl:/sl \
-v $(pwd)/sl/upload:/code/static/upload \
-v $(pwd)/simplelogin.env:/code/.env \
-v $(pwd)/dkim.key:/dkim.key \
-v $(pwd)/dkim.pub.key:/dkim.pub.key \
-p 127.0.0.1:20381:20381 \
--restart always \
--network="sl-network" \
simplelogin/app:3.4.0 python email_handler.py
# Run the job runner
docker run -d \
--name sl-job-runner \
-v $(pwd)/sl:/sl \
-v $(pwd)/sl/upload:/code/static/upload \
-v $(pwd)/simplelogin.env:/code/.env \
-v $(pwd)/dkim.key:/dkim.key \
-v $(pwd)/dkim.pub.key:/dkim.pub.key \
--restart always \
--network="sl-network" \
simplelogin/app:3.4.0 python job_runner.py
```