mirror of
https://github.com/simple-login/app.git
synced 2024-09-20 06:55:59 +08:00
Update pre-commit (#1138)
* Update pre-commit * Upgrade djlint, remove flake8 and add pylint * Reformat with new djlint version * Run pre-commit on CI * Use only python3.10 on CI * Reformat files with pre-commit * Run pre-commit against all files * Reformat * Added global excludes * Added pre-commit to the contributing file * Set python 3.9 as default * Set language version to python3 Co-authored-by: Adrià Casajús <adria.casajus@proton.ch> Co-authored-by: Carlos Quintana <carlos.quintana@proton.ch>
This commit is contained in:
parent
e2f9ea4ae1
commit
046748c443
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -7,12 +7,12 @@ assignees: ''
|
|||
|
||||
---
|
||||
|
||||
Please note that this is only for bug report.
|
||||
Please note that this is only for bug report.
|
||||
|
||||
For help on your account, please reach out to us at hi[at]simplelogin.io. Please make sure to check out [our FAQ](https://simplelogin.io/faq/) that contains frequently asked questions.
|
||||
|
||||
|
||||
For feature request, you can use our [forum](https://github.com/simple-login/app/discussions/categories/feature-request).
|
||||
For feature request, you can use our [forum](https://github.com/simple-login/app/discussions/categories/feature-request).
|
||||
|
||||
For self-hosted question/issue, please ask in [self-hosted forum](https://github.com/simple-login/app/discussions/categories/self-hosting-question)
|
||||
|
||||
|
|
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
|
@ -1,6 +1,6 @@
|
|||
name: Run tests & Publish to Docker Registry
|
||||
|
||||
on:
|
||||
on:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
|
@ -9,7 +9,7 @@ jobs:
|
|||
strategy:
|
||||
max-parallel: 4
|
||||
matrix:
|
||||
python-version: [3.7, "3.10"]
|
||||
python-version: ["3.9", "3.10"]
|
||||
|
||||
# service containers to run with `postgres-job`
|
||||
services:
|
||||
|
@ -75,9 +75,7 @@ jobs:
|
|||
|
||||
- name: Check formatting & linting
|
||||
run: |
|
||||
poetry run black --check .
|
||||
poetry run flake8
|
||||
poetry run djlint --check templates
|
||||
poetry run pre-commit run --all-files
|
||||
|
||||
- name: Run db migration
|
||||
run: |
|
||||
|
@ -214,4 +212,4 @@ jobs:
|
|||
release_name: ${{ github.ref }}
|
||||
body: ${{ steps.build_changelog.outputs.changelog }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
@ -1,10 +1,27 @@
|
|||
exclude: "(migrations|static/node_modules|static/assets|static/vendor)"
|
||||
default_language_version:
|
||||
python: python3
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.1.0
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.2.0
|
||||
hooks:
|
||||
- id: black
|
||||
language_version: python3.7
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 4.0.1
|
||||
- id: check-yaml
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.3.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- id: black
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.9.2
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/Riverside-Healthcare/djLint
|
||||
rev: v1.3.0
|
||||
hooks:
|
||||
- id: djlint-jinja
|
||||
files: '.*\.html'
|
||||
entry: djlint --reformat
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: v2.14.4
|
||||
hooks:
|
||||
- id: pylint
|
||||
|
|
227
.pylintrc
Normal file
227
.pylintrc
Normal file
|
@ -0,0 +1,227 @@
|
|||
[MASTER]
|
||||
extension-pkg-allow-list=re2
|
||||
|
||||
fail-under=7.0
|
||||
ignore=CVS
|
||||
ignore-paths=migrations
|
||||
ignore-patterns=^\.#
|
||||
jobs=0
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
disable=missing-function-docstring,
|
||||
missing-module-docstring,
|
||||
duplicate-code,
|
||||
#import-error,
|
||||
missing-class-docstring,
|
||||
useless-object-inheritance,
|
||||
use-dict-literal,
|
||||
logging-format-interpolation,
|
||||
consider-using-f-string,
|
||||
unnecessary-comprehension,
|
||||
inconsistent-return-statements,
|
||||
wrong-import-order,
|
||||
line-too-long,
|
||||
invalid-name,
|
||||
global-statement,
|
||||
no-else-return,
|
||||
unspecified-encoding,
|
||||
logging-fstring-interpolation,
|
||||
too-few-public-methods,
|
||||
bare-except,
|
||||
fixme,
|
||||
unnecessary-pass,
|
||||
f-string-without-interpolation,
|
||||
super-init-not-called,
|
||||
unused-argument,
|
||||
ungrouped-imports,
|
||||
too-many-locals,
|
||||
consider-using-with,
|
||||
too-many-statements,
|
||||
consider-using-set-comprehension,
|
||||
unidiomatic-typecheck,
|
||||
useless-else-on-loop,
|
||||
too-many-return-statements,
|
||||
broad-except,
|
||||
protected-access,
|
||||
consider-using-enumerate,
|
||||
too-many-nested-blocks,
|
||||
too-many-branches,
|
||||
simplifiable-if-expression,
|
||||
possibly-unused-variable,
|
||||
pointless-string-statement,
|
||||
wrong-import-position,
|
||||
redefined-outer-name,
|
||||
raise-missing-from,
|
||||
logging-too-few-args,
|
||||
redefined-builtin,
|
||||
too-many-arguments,
|
||||
import-outside-toplevel,
|
||||
redefined-argument-from-local,
|
||||
logging-too-many-args,
|
||||
too-many-instance-attributes,
|
||||
unreachable,
|
||||
no-name-in-module,
|
||||
no-member,
|
||||
consider-using-ternary,
|
||||
too-many-lines,
|
||||
arguments-differ,
|
||||
too-many-public-methods,
|
||||
unused-variable,
|
||||
consider-using-dict-items,
|
||||
consider-using-in,
|
||||
reimported,
|
||||
too-many-boolean-expressions,
|
||||
cyclic-import,
|
||||
not-callable, # (paddle_utils.py) verifier.verify cannot be called (although it can)
|
||||
abstract-method, # (models.py)
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Naming style matching correct argument names.
|
||||
argument-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct argument names. Overrides argument-
|
||||
# naming-style. If left empty, argument names will be checked with the set
|
||||
# naming style.
|
||||
#argument-rgx=
|
||||
|
||||
# Naming style matching correct attribute names.
|
||||
attr-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||
# style. If left empty, attribute names will be checked with the set naming
|
||||
# style.
|
||||
#attr-rgx=
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma.
|
||||
bad-names=foo,
|
||||
bar,
|
||||
baz,
|
||||
toto,
|
||||
tutu,
|
||||
tata
|
||||
|
||||
# Bad variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be refused
|
||||
bad-names-rgxs=
|
||||
|
||||
# Naming style matching correct class attribute names.
|
||||
class-attribute-naming-style=any
|
||||
|
||||
# Regular expression matching correct class attribute names. Overrides class-
|
||||
# attribute-naming-style. If left empty, class attribute names will be checked
|
||||
# with the set naming style.
|
||||
#class-attribute-rgx=
|
||||
|
||||
# Naming style matching correct class constant names.
|
||||
class-const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct class constant names. Overrides class-
|
||||
# const-naming-style. If left empty, class constant names will be checked with
|
||||
# the set naming style.
|
||||
#class-const-rgx=
|
||||
|
||||
# Naming style matching correct class names.
|
||||
class-naming-style=PascalCase
|
||||
|
||||
# Regular expression matching correct class names. Overrides class-naming-
|
||||
# style. If left empty, class names will be checked with the set naming style.
|
||||
#class-rgx=
|
||||
|
||||
# Naming style matching correct constant names.
|
||||
const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct constant names. Overrides const-naming-
|
||||
# style. If left empty, constant names will be checked with the set naming
|
||||
# style.
|
||||
#const-rgx=
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
# Naming style matching correct function names.
|
||||
function-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct function names. Overrides function-
|
||||
# naming-style. If left empty, function names will be checked with the set
|
||||
# naming style.
|
||||
#function-rgx=
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma.
|
||||
good-names=i,
|
||||
j,
|
||||
k,
|
||||
ex,
|
||||
Run,
|
||||
_
|
||||
|
||||
# Good variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be accepted
|
||||
good-names-rgxs=
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name.
|
||||
include-naming-hint=no
|
||||
|
||||
# Naming style matching correct inline iteration names.
|
||||
inlinevar-naming-style=any
|
||||
|
||||
# Regular expression matching correct inline iteration names. Overrides
|
||||
# inlinevar-naming-style. If left empty, inline iteration names will be checked
|
||||
# with the set naming style.
|
||||
#inlinevar-rgx=
|
||||
|
||||
# Naming style matching correct method names.
|
||||
method-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct method names. Overrides method-naming-
|
||||
# style. If left empty, method names will be checked with the set naming style.
|
||||
#method-rgx=
|
||||
|
||||
# Naming style matching correct module names.
|
||||
module-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct module names. Overrides module-naming-
|
||||
# style. If left empty, module names will be checked with the set naming style.
|
||||
#module-rgx=
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=^_
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
# These decorators are taken in consideration only for invalid-name.
|
||||
property-classes=abc.abstractproperty
|
||||
|
||||
# Regular expression matching correct type variable names. If left empty, type
|
||||
# variable names will be checked with the set naming style.
|
||||
#typevar-rgx=
|
||||
|
||||
# Naming style matching correct variable names.
|
||||
variable-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct variable names. Overrides variable-
|
||||
# naming-style. If left empty, variable names will be checked with the set
|
||||
# naming style.
|
||||
#variable-rgx=
|
||||
|
||||
|
||||
[STRING]
|
||||
|
||||
# This flag controls whether inconsistent-quotes generates a warning when the
|
||||
# character used as a quote delimiter is used inconsistently within a module.
|
||||
check-quote-consistency=no
|
||||
|
||||
# This flag controls whether the implicit-str-concat should generate a warning
|
||||
# on implicit string concatenation in sequences defined over several lines.
|
||||
check-str-concat-over-line-jumps=no
|
||||
|
||||
|
||||
[FORMAT]
|
||||
max-line-length=88
|
||||
single-line-if-stmt=yes
|
|
@ -117,7 +117,7 @@ Add SUPPORT_NAME param to set a support email name.
|
|||
|
||||
## [1.0.1] - 2020-01-28
|
||||
|
||||
Simplify config file.
|
||||
Simplify config file.
|
||||
|
||||
## [1.0.0] - 2020-01-22
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Thanks for taking the time to contribute! 🎉👍
|
||||
|
||||
Before working on a new feature, please get in touch with us at dev[at]simplelogin.io to avoid duplication.
|
||||
We can also discuss the best way to implement it.
|
||||
Before working on a new feature, please get in touch with us at dev[at]simplelogin.io to avoid duplication.
|
||||
We can also discuss the best way to implement it.
|
||||
|
||||
The project uses Flask, Python3.7+ and requires Postgres 12+ as dependency.
|
||||
The project uses Flask, Python3.7+ and requires Postgres 12+ as dependency.
|
||||
|
||||
## General Architecture
|
||||
|
||||
|
@ -43,13 +43,23 @@ You also need to install `gpg` tool, on Mac it can be done with:
|
|||
brew install gnupg
|
||||
```
|
||||
|
||||
If you see the `pyre2` package in the error message, you might need to install its dependencies with `brew`.
|
||||
If you see the `pyre2` package in the error message, you might need to install its dependencies with `brew`.
|
||||
More info on https://github.com/andreasvc/pyre2
|
||||
|
||||
```bash
|
||||
brew install -s re2 pybind11
|
||||
```
|
||||
|
||||
## Linting and static analysis
|
||||
|
||||
We use pre-commit to run all our linting and static analysis checks. Please run
|
||||
|
||||
```bash
|
||||
poetry run pre-commit install
|
||||
```
|
||||
|
||||
To install it in your development environment.
|
||||
|
||||
## Run tests
|
||||
|
||||
```bash
|
||||
|
|
10
README.md
10
README.md
|
@ -29,12 +29,12 @@
|
|||
|
||||
---
|
||||
|
||||
Your email address is your **online identity**. When you use the same email address everywhere, you can be easily tracked.
|
||||
More information on https://simplelogin.io
|
||||
Your email address is your **online identity**. When you use the same email address everywhere, you can be easily tracked.
|
||||
More information on https://simplelogin.io
|
||||
|
||||
This README contains instructions on how to self host SimpleLogin.
|
||||
|
||||
Once you have your own SimpleLogin instance running, you can change the `API URL` in SimpleLogin's Chrome/Firefox extension, Android/iOS app to your server.
|
||||
Once you have your own SimpleLogin instance running, you can change the `API URL` in SimpleLogin's Chrome/Firefox extension, Android/iOS app to your server.
|
||||
|
||||
SimpleLogin roadmap is at https://github.com/simple-login/app/projects/1 and our forum at https://github.com/simple-login/app/discussions, feel free to submit new ideas or vote on features.
|
||||
|
||||
|
@ -374,10 +374,10 @@ sudo systemctl restart postfix
|
|||
To run SimpleLogin, you need a config file at `$(pwd)/simplelogin.env`. Below is an example that you can use right away, make sure to
|
||||
|
||||
- replace `mydomain.com` by your domain,
|
||||
- set `FLASK_SECRET` to a secret string,
|
||||
- set `FLASK_SECRET` to a secret string,
|
||||
- update 'myuser' and 'mypassword' with your database credentials used in previous step.
|
||||
|
||||
All possible parameters can be found in [config example](example.env). Some are optional and are commented out by default.
|
||||
All possible parameters can be found in [config example](example.env). Some are optional and are commented out by default.
|
||||
Some have "dummy" values, fill them up if you want to enable these features (Paddle, AWS, etc).
|
||||
|
||||
```.env
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
## Supported Versions
|
||||
|
||||
We only add security updates to the latest MAJOR.MINOR version of the project. No security updates are backported to previous versions.
|
||||
We only add security updates to the latest MAJOR.MINOR version of the project. No security updates are backported to previous versions.
|
||||
If you want be up to date on security patches, make sure your SimpleLogin image is up to date.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you've found a security vulnerability, you can disclose it responsibly by sending a summary to security@simplelogin.io.
|
||||
We will review the potential threat and fix it as fast as we can.
|
||||
If you've found a security vulnerability, you can disclose it responsibly by sending a summary to security@simplelogin.io.
|
||||
We will review the potential threat and fix it as fast as we can.
|
||||
|
||||
We are incredibly thankful for people who disclose vulnerabilities, unfortunately we do not have a bounty program in place yet.
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ Input:
|
|||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
Output:
|
||||
|
||||
- 200 with ```{"ok": true}``` if sudo mode has been enabled.
|
||||
- 403 with ```{"error": "Some error"}``` if there is an error.
|
||||
|
@ -308,7 +308,7 @@ Input:
|
|||
Output: a json with the following field:
|
||||
|
||||
- can_create: boolean. Whether user can create new alias
|
||||
- suffixes: list of alias suffix that user can use.
|
||||
- suffixes: list of alias suffix that user can use.
|
||||
Each item is a dictionary with `suffix`, `signed-suffix`, `is_custom`, `is_premium` as keys.
|
||||
The `signed-suffix` is necessary to avoid request tampering.
|
||||
- prefix_suggestion: string. Suggestion for the `alias prefix`. Usually this is the website name extracted
|
||||
|
@ -389,8 +389,8 @@ Input:
|
|||
- `page_id` in query. Used for the pagination. The endpoint returns maximum 20 aliases for each page. `page_id` starts
|
||||
at 0.
|
||||
- (Optional) `pinned` in query. If set, only pinned aliases are returned.
|
||||
- (Optional) `disabled` in query. If set, only disabled aliases are returned.
|
||||
- (Optional) `enabled` in query. If set, only enabled aliases are returned.
|
||||
- (Optional) `disabled` in query. If set, only disabled aliases are returned.
|
||||
- (Optional) `enabled` in query. If set, only enabled aliases are returned.
|
||||
Please note `pinned`, `disabled`, `enabled` are exclusive, i.e. only one can be present.
|
||||
- (Optional) query: included in request body. Some frameworks might prevent GET request having a non-empty body, in this
|
||||
case this endpoint also supports POST.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# TODO
|
||||
|
||||
`local_data/`: contain files used only locally. In deployment, these files should be replaced.
|
||||
- jwtRS256.key: generated using
|
||||
|
||||
- jwtRS256.key: generated using
|
||||
|
||||
```bash
|
||||
ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key
|
||||
# Don't add passphrase
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
Some email services like Gmail, Protonmail, 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,
|
||||
Some email services like Gmail, Protonmail, 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
|
||||
|
||||
```
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
In case your Postfix server is on another server, it's recommended to enable TLS on Postfix submission to
|
||||
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`
|
||||
|
@ -11,5 +11,5 @@ submission inet n - y - - smtpd
|
|||
-o smtpd_tls_auth_only=yes
|
||||
```
|
||||
|
||||
Make sure to set the `POSTFIX_SUBMISSION_TLS` variable to `true` in the SimpleLogin `simplelogin.env` file.
|
||||
Make sure to set the `POSTFIX_SUBMISSION_TLS` variable to `true` in the SimpleLogin `simplelogin.env` file.
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ 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.
|
||||
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.
|
||||
|
||||
|
@ -57,11 +57,11 @@ Also make sure that Postfix is able to authenticate successfully by installing t
|
|||
sudo apt install libsasl2-modules
|
||||
```
|
||||
|
||||
Then restart postfix
|
||||
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!
|
||||
|
||||
|
|
|
@ -27,12 +27,12 @@ smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
|||
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
|
||||
```
|
||||
|
||||
with
|
||||
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.
|
||||
|
||||
|
|
|
@ -8,23 +8,23 @@ This can either mean:
|
|||
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.
|
||||
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
|
||||
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.
|
||||
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
|
||||
|
@ -52,8 +52,8 @@ And `postmap -q not-exist.com pgsql:/etc/postfix/pgsql-relay-domains.cf` should
|
|||
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
|
||||
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
|
||||
|
|
|
@ -2,7 +2,7 @@ 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
|
||||
|
|
|
@ -193,7 +193,7 @@ sudo docker run -d \
|
|||
--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 \
|
||||
|
@ -205,6 +205,6 @@ docker run -d \
|
|||
--restart always \
|
||||
--network="sl-network" \
|
||||
simplelogin/app:3.4.0 python job_runner.py
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ def upgrade():
|
|||
session = Session(bind=bind)
|
||||
|
||||
session.execute("""
|
||||
ALTER TABLE alias ADD COLUMN ts_vector tsvector GENERATED ALWAYS
|
||||
ALTER TABLE alias ADD COLUMN ts_vector tsvector GENERATED ALWAYS
|
||||
AS (to_tsvector('english', note)) STORED;
|
||||
""")
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""empty message
|
||||
|
||||
Revision ID: 5e549314e1e2
|
||||
Revises:
|
||||
Revises:
|
||||
Create Date: 2019-06-23 16:02:14.692075
|
||||
|
||||
"""
|
||||
|
|
309
poetry.lock
generated
309
poetry.lock
generated
|
@ -66,14 +66,6 @@ python-dateutil = "*"
|
|||
python-editor = ">=0.3"
|
||||
SQLAlchemy = ">=1.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "appdirs"
|
||||
version = "1.4.4"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "appnope"
|
||||
version = "0.1.0"
|
||||
|
@ -93,6 +85,20 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
|||
[package.dependencies]
|
||||
python-dateutil = ">=2.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "astroid"
|
||||
version = "2.11.6"
|
||||
description = "An abstract syntax tree for Python with inference support."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.2"
|
||||
|
||||
[package.dependencies]
|
||||
lazy-object-proxy = ">=1.4.0"
|
||||
typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""}
|
||||
typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""}
|
||||
wrapt = ">=1.11,<2"
|
||||
|
||||
[[package]]
|
||||
name = "async-timeout"
|
||||
version = "3.0.1"
|
||||
|
@ -142,6 +148,21 @@ category = "main"
|
|||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "backports.entry-points-selectable"
|
||||
version = "1.1.1"
|
||||
description = "Compatibility shim providing selectable entry points for older implementations"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7"
|
||||
|
||||
[package.dependencies]
|
||||
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["pytest", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "bcrypt"
|
||||
version = "3.2.0"
|
||||
|
@ -378,6 +399,17 @@ wrapt = ">=1.10,<2"
|
|||
[package.extras]
|
||||
dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"]
|
||||
|
||||
[[package]]
|
||||
name = "dill"
|
||||
version = "0.3.5.1"
|
||||
description = "serialize all of python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
|
||||
|
||||
[package.extras]
|
||||
graph = ["objgraph (>=1.7.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "distlib"
|
||||
version = "0.3.1"
|
||||
|
@ -388,23 +420,26 @@ python-versions = "*"
|
|||
|
||||
[[package]]
|
||||
name = "djlint"
|
||||
version = "0.7.3"
|
||||
version = "1.3.0"
|
||||
description = "HTML Template Linter and Formatter"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.2,<4.0.0"
|
||||
python-versions = ">=3.7,<4.0"
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8.0.1,<9.0.0"
|
||||
colorama = ">=0.4.4,<0.5.0"
|
||||
html-tag-names = ">=0.1.2,<0.2.0"
|
||||
html-void-elements = ">=0.1.0,<0.2.0"
|
||||
importlib-metadata = ">=4.11.0,<5.0.0"
|
||||
pathspec = ">=0.9.0,<0.10.0"
|
||||
PyYAML = ">=6.0,<7.0"
|
||||
regex = ">=2022.1.18,<2023.0.0"
|
||||
tomlkit = ">=0.8.0,<0.9.0"
|
||||
tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
|
||||
tqdm = ">=4.62.2,<5.0.0"
|
||||
|
||||
[package.extras]
|
||||
test = ["coverage (>=6.2,<7.0)", "pytest (>=6.2.5,<7.0.0)", "pytest-cov (>=3.0.0,<4.0.0)"]
|
||||
test = ["coverage (>=6.3.1,<7.0.0)", "pytest (>=7.0.1,<8.0.0)", "pytest-cov (>=3.0.0,<4.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "dkimpy"
|
||||
|
@ -469,35 +504,6 @@ category = "main"
|
|||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "4.0.1"
|
||||
description = "the modular source code checker: pep8 pyflakes and co"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""}
|
||||
mccabe = ">=0.6.0,<0.7.0"
|
||||
pycodestyle = ">=2.8.0,<2.9.0"
|
||||
pyflakes = ">=2.4.0,<2.5.0"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-bugbear"
|
||||
version = "22.1.11"
|
||||
description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=19.2.0"
|
||||
flake8 = ">=3.0.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit"]
|
||||
|
||||
[[package]]
|
||||
name = "flanker"
|
||||
version = "0.9.11"
|
||||
|
@ -816,6 +822,22 @@ gevent = ["gevent (>=0.13)"]
|
|||
setproctitle = ["setproctitle"]
|
||||
tornado = ["tornado (>=0.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "html-tag-names"
|
||||
version = "0.1.2"
|
||||
description = "List of known HTML tag names"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7,<4.0"
|
||||
|
||||
[[package]]
|
||||
name = "html-void-elements"
|
||||
version = "0.1.0"
|
||||
description = "List of HTML void tag names."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7,<4.0"
|
||||
|
||||
[[package]]
|
||||
name = "httplib2"
|
||||
version = "0.18.1"
|
||||
|
@ -856,18 +878,20 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "1.7.0"
|
||||
version = "4.12.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "rst.linker"]
|
||||
testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
|
||||
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
|
||||
perf = ["ipython"]
|
||||
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
|
@ -917,6 +941,20 @@ category = "main"
|
|||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "5.10.1"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.1,<4.0"
|
||||
|
||||
[package.extras]
|
||||
pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
|
||||
requirements_deprecated_finder = ["pipreqs", "pip-api"]
|
||||
colors = ["colorama (>=0.4.3,<0.5.0)"]
|
||||
plugins = ["setuptools"]
|
||||
|
||||
[[package]]
|
||||
name = "itsdangerous"
|
||||
version = "1.1.0"
|
||||
|
@ -973,6 +1011,14 @@ python-versions = "*"
|
|||
[package.dependencies]
|
||||
cryptography = ">=2.3"
|
||||
|
||||
[[package]]
|
||||
name = "lazy-object-proxy"
|
||||
version = "1.7.1"
|
||||
description = "A fast and thorough lazy object proxy."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "limits"
|
||||
version = "1.5.1"
|
||||
|
@ -1020,11 +1066,11 @@ traitlets = "*"
|
|||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
version = "0.6.1"
|
||||
version = "0.7.0"
|
||||
description = "McCabe checker, plugin for flake8"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "memory-profiler"
|
||||
|
@ -1283,14 +1329,6 @@ python-versions = "*"
|
|||
[package.dependencies]
|
||||
pyasn1 = ">=0.4.6,<0.5.0"
|
||||
|
||||
[[package]]
|
||||
name = "pycodestyle"
|
||||
version = "2.8.0"
|
||||
description = "Python style guide checker"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.20"
|
||||
|
@ -1307,14 +1345,6 @@ category = "main"
|
|||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "pyflakes"
|
||||
version = "2.4.0"
|
||||
description = "passive checker of Python programs"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.7.4"
|
||||
|
@ -1337,6 +1367,29 @@ dev = ["sphinx", "sphinx-rtd-theme", "zope.interface", "cryptography (>=3.3.1)",
|
|||
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
|
||||
tests = ["pytest (>=6.0.0,<7.0.0)", "coverage[toml] (==5.0.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "2.14.4"
|
||||
description = "python code static checker"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
|
||||
[package.dependencies]
|
||||
astroid = ">=2.11.6,<=2.12.0-dev0"
|
||||
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
|
||||
dill = ">=0.2"
|
||||
isort = ">=4.2.5,<6"
|
||||
mccabe = ">=0.6,<0.8"
|
||||
platformdirs = ">=2.2.0"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
tomlkit = ">=0.10.1"
|
||||
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
|
||||
|
||||
[package.extras]
|
||||
spelling = ["pyenchant (>=3.2,<4.0)"]
|
||||
testutils = ["gitpython (>3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyopenssl"
|
||||
version = "19.1.0"
|
||||
|
@ -1731,7 +1784,7 @@ python-versions = "*"
|
|||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
category = "dev"
|
||||
optional = false
|
||||
|
@ -1739,7 +1792,7 @@ python-versions = ">=3.7"
|
|||
|
||||
[[package]]
|
||||
name = "tomlkit"
|
||||
version = "0.8.0"
|
||||
version = "0.11.0"
|
||||
description = "Style preserving TOML library"
|
||||
category = "dev"
|
||||
optional = false
|
||||
|
@ -1836,22 +1889,23 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "virtualenv"
|
||||
version = "20.0.31"
|
||||
version = "20.8.1"
|
||||
description = "Virtual Python Environment builder"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
|
||||
[package.dependencies]
|
||||
appdirs = ">=1.4.3,<2"
|
||||
"backports.entry-points-selectable" = ">=1.0.4"
|
||||
distlib = ">=0.3.1,<1"
|
||||
filelock = ">=3.0.0,<4"
|
||||
importlib-metadata = {version = ">=0.12,<2", markers = "python_version < \"3.8\""}
|
||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||
platformdirs = ">=2,<3"
|
||||
six = ">=1.9.0,<2"
|
||||
|
||||
[package.extras]
|
||||
docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"]
|
||||
testing = ["coverage (>=5)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "pytest-xdist (>=1.31.0)", "packaging (>=20.0)", "xonsh (>=0.9.16)"]
|
||||
testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "watchtower"
|
||||
|
@ -2004,8 +2058,8 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
|
|||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.7"
|
||||
content-hash = "29d95a850f0a87a38aabb8f5eddba072316860dae26943fd690898ea9bac2b02"
|
||||
python-versions = "^3.7.2"
|
||||
content-hash = "04190874ee0655ddf7d67e024a61009c5f9c92439ff0af8dfce3341580269edb"
|
||||
|
||||
[metadata.files]
|
||||
aiohttp = [
|
||||
|
@ -2038,10 +2092,6 @@ alembic = [
|
|||
{file = "alembic-1.4.3-py2.py3-none-any.whl", hash = "sha256:4e02ed2aa796bd179965041afa092c55b51fb077de19d61835673cc80672c01c"},
|
||||
{file = "alembic-1.4.3.tar.gz", hash = "sha256:5334f32314fb2a56d86b4c4dd1ae34b08c03cae4cb888bc699942104d66bc245"},
|
||||
]
|
||||
appdirs = [
|
||||
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
||||
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||
]
|
||||
appnope = [
|
||||
{file = "appnope-0.1.0-py2.py3-none-any.whl", hash = "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0"},
|
||||
{file = "appnope-0.1.0.tar.gz", hash = "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"},
|
||||
|
@ -2050,6 +2100,10 @@ arrow = [
|
|||
{file = "arrow-0.16.0-py2.py3-none-any.whl", hash = "sha256:98184d8dd3e5d30b96c2df4596526f7de679ccb467f358b82b0f686436f3a6b8"},
|
||||
{file = "arrow-0.16.0.tar.gz", hash = "sha256:92aac856ea5175c804f7ccb96aca4d714d936f1c867ba59d747a8096ec30e90a"},
|
||||
]
|
||||
astroid = [
|
||||
{file = "astroid-2.11.6-py3-none-any.whl", hash = "sha256:ba33a82a9a9c06a5ceed98180c5aab16e29c285b828d94696bf32d6015ea82a9"},
|
||||
{file = "astroid-2.11.6.tar.gz", hash = "sha256:4f933d0bf5e408b03a6feb5d23793740c27e07340605f236496cd6ce552043d6"},
|
||||
]
|
||||
async-timeout = [
|
||||
{file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"},
|
||||
{file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"},
|
||||
|
@ -2069,6 +2123,10 @@ backcall = [
|
|||
{file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
|
||||
{file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
|
||||
]
|
||||
"backports.entry-points-selectable" = [
|
||||
{file = "backports.entry_points_selectable-1.1.1-py2.py3-none-any.whl", hash = "sha256:7fceed9532a7aa2bd888654a7314f864a3c16a4e710b34a58cfc0f08114c663b"},
|
||||
{file = "backports.entry_points_selectable-1.1.1.tar.gz", hash = "sha256:914b21a479fde881635f7af5adc7f6e38d6b274be32269070c53b698c60d5386"},
|
||||
]
|
||||
bcrypt = [
|
||||
{file = "bcrypt-3.2.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b589229207630484aefe5899122fb938a5b017b0f4349f769b8c13e78d99a8fd"},
|
||||
{file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"},
|
||||
|
@ -2269,13 +2327,17 @@ deprecated = [
|
|||
{file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"},
|
||||
{file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"},
|
||||
]
|
||||
dill = [
|
||||
{file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"},
|
||||
{file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"},
|
||||
]
|
||||
distlib = [
|
||||
{file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"},
|
||||
{file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"},
|
||||
]
|
||||
djlint = [
|
||||
{file = "djlint-0.7.3-py3-none-any.whl", hash = "sha256:714ed457e022047149c8bff57d5be00ce30f8846b60e866791c66d27e7d11e7f"},
|
||||
{file = "djlint-0.7.3.tar.gz", hash = "sha256:68aad9ddfef883cc9d9e0d177387b74840af5ca12dcce6e4629eb7075c97dc05"},
|
||||
{file = "djlint-1.3.0-py3-none-any.whl", hash = "sha256:0c986bf542cdac3025d431a5b15e6c3977f652f2e76e408dbb5e7aaab6b73d99"},
|
||||
{file = "djlint-1.3.0.tar.gz", hash = "sha256:b2d8e6c0a14f88da165296f0da05795d15299b7ab0a9093d670ce9ffd867bc79"},
|
||||
]
|
||||
dkimpy = [
|
||||
{file = "dkimpy-1.0.5.tar.gz", hash = "sha256:9a2420bf09af686736773153fca32a02ae11ecbe24b540c26104628959f91121"},
|
||||
|
@ -2296,14 +2358,6 @@ filelock = [
|
|||
{file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
|
||||
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
|
||||
]
|
||||
flake8 = [
|
||||
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
|
||||
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
|
||||
]
|
||||
flake8-bugbear = [
|
||||
{file = "flake8-bugbear-22.1.11.tar.gz", hash = "sha256:4c2a4136bd4ecb8bf02d5159af302ffc067642784c9d0488b33ce4610da825ee"},
|
||||
{file = "flake8_bugbear-22.1.11-py3-none-any.whl", hash = "sha256:ce7ae44aaaf67ef192b8a6de94a5ac617144e1675ad0654fdea556f48dc18d9b"},
|
||||
]
|
||||
flanker = [
|
||||
{file = "flanker-0.9.11.tar.gz", hash = "sha256:974418e5b498fd3bcb3859c22e22d26495257f9cf98b744c17f2335aca86e001"},
|
||||
]
|
||||
|
@ -2474,6 +2528,14 @@ gunicorn = [
|
|||
{file = "gunicorn-20.0.4-py2.py3-none-any.whl", hash = "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c"},
|
||||
{file = "gunicorn-20.0.4.tar.gz", hash = "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626"},
|
||||
]
|
||||
html-tag-names = [
|
||||
{file = "html-tag-names-0.1.2.tar.gz", hash = "sha256:04924aca48770f36b5a41c27e4d917062507be05118acb0ba869c97389084297"},
|
||||
{file = "html_tag_names-0.1.2-py3-none-any.whl", hash = "sha256:eeb69ef21078486b615241f0393a72b41352c5219ee648e7c61f5632d26f0420"},
|
||||
]
|
||||
html-void-elements = [
|
||||
{file = "html-void-elements-0.1.0.tar.gz", hash = "sha256:931b88f84cd606fee0b582c28fcd00e41d7149421fb673e1e1abd2f0c4f231f0"},
|
||||
{file = "html_void_elements-0.1.0-py3-none-any.whl", hash = "sha256:784cf39db03cdeb017320d9301009f8f3480f9d7b254d0974272e80e0cb5e0d2"},
|
||||
]
|
||||
httplib2 = [
|
||||
{file = "httplib2-0.18.1-py3-none-any.whl", hash = "sha256:ca2914b015b6247791c4866782fa6042f495b94401a0f0bd3e1d6e0ba2236782"},
|
||||
{file = "httplib2-0.18.1.tar.gz", hash = "sha256:8af66c1c52c7ffe1aa5dc4bcd7c769885254b0756e6e69f953c7f0ab49a70ba3"},
|
||||
|
@ -2491,8 +2553,8 @@ idna = [
|
|||
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
|
||||
]
|
||||
importlib-metadata = [
|
||||
{file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"},
|
||||
{file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"},
|
||||
{file = "importlib_metadata-4.12.0-py3-none-any.whl", hash = "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"},
|
||||
{file = "importlib_metadata-4.12.0.tar.gz", hash = "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670"},
|
||||
]
|
||||
iniconfig = [
|
||||
{file = "iniconfig-1.0.1-py3-none-any.whl", hash = "sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437"},
|
||||
|
@ -2506,6 +2568,10 @@ ipython-genutils = [
|
|||
{file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"},
|
||||
{file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"},
|
||||
]
|
||||
isort = [
|
||||
{file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
|
||||
{file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
|
||||
]
|
||||
itsdangerous = [
|
||||
{file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
|
||||
{file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
|
||||
|
@ -2526,6 +2592,45 @@ jwcrypto = [
|
|||
{file = "jwcrypto-0.8-py2.py3-none-any.whl", hash = "sha256:16e17faa4dce36551ade3a3ccb06236a61e5924ea1db163c9be9827acf935a82"},
|
||||
{file = "jwcrypto-0.8.tar.gz", hash = "sha256:b7fee2635bbefdf145399392f5be26ad54161c8271c66b5fe107b4b452f06c24"},
|
||||
]
|
||||
lazy-object-proxy = [
|
||||
{file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"},
|
||||
{file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"},
|
||||
]
|
||||
limits = [
|
||||
{file = "limits-1.5.1-py2-none-any.whl", hash = "sha256:0e5f8b10f18dd809eb2342f5046eb9aa5e4e69a0258567b5f4aa270647d438b3"},
|
||||
{file = "limits-1.5.1.tar.gz", hash = "sha256:f0c3319f032c4bfad68438ed1325c0fac86dac64582c7c25cddc87a0b658fa20"},
|
||||
|
@ -2593,8 +2698,8 @@ matplotlib-inline = [
|
|||
{file = "matplotlib_inline-0.1.3-py3-none-any.whl", hash = "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c"},
|
||||
]
|
||||
mccabe = [
|
||||
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
|
||||
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
|
||||
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
|
||||
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
||||
]
|
||||
memory-profiler = [
|
||||
{file = "memory_profiler-0.57.0.tar.gz", hash = "sha256:23b196f91ea9ac9996e30bfab1e82fecc30a4a1d24870e81d1e81625f786a2c3"},
|
||||
|
@ -2825,10 +2930,6 @@ pyasn1-modules = [
|
|||
{file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"},
|
||||
{file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"},
|
||||
]
|
||||
pycodestyle = [
|
||||
{file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
|
||||
{file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
|
||||
]
|
||||
pycparser = [
|
||||
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
|
||||
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
|
||||
|
@ -2870,10 +2971,6 @@ pycryptodome = [
|
|||
{file = "pycryptodome-3.9.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9f62d21bc693f3d7d444f17ed2ad7a913b4c37c15cd807895d013c39c0517dfd"},
|
||||
{file = "pycryptodome-3.9.8.tar.gz", hash = "sha256:0e24171cf01021bc5dc17d6a9d4f33a048f09d62cc3f62541e95ef104588bda4"},
|
||||
]
|
||||
pyflakes = [
|
||||
{file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
|
||||
{file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
|
||||
]
|
||||
pygments = [
|
||||
{file = "Pygments-2.7.4-py3-none-any.whl", hash = "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435"},
|
||||
{file = "Pygments-2.7.4.tar.gz", hash = "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337"},
|
||||
|
@ -2882,6 +2979,10 @@ pyjwt = [
|
|||
{file = "PyJWT-2.4.0-py3-none-any.whl", hash = "sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf"},
|
||||
{file = "PyJWT-2.4.0.tar.gz", hash = "sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba"},
|
||||
]
|
||||
pylint = [
|
||||
{file = "pylint-2.14.4-py3-none-any.whl", hash = "sha256:89b61867db16eefb7b3c5b84afc94081edaf11544189e2b238154677529ad69f"},
|
||||
{file = "pylint-2.14.4.tar.gz", hash = "sha256:47705453aa9dce520e123a7d51843d5f0032cbfa06870f89f00927aa1f735a4a"},
|
||||
]
|
||||
pyopenssl = [
|
||||
{file = "pyOpenSSL-19.1.0-py2.py3-none-any.whl", hash = "sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504"},
|
||||
{file = "pyOpenSSL-19.1.0.tar.gz", hash = "sha256:9a24494b2602aaf402be5c9e30a0b82d4a5c67528fe8fb475e3f3bc00dd69507"},
|
||||
|
@ -3240,12 +3341,12 @@ toml = [
|
|||
{file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
|
||||
]
|
||||
tomli = [
|
||||
{file = "tomli-2.0.0-py3-none-any.whl", hash = "sha256:b5bde28da1fed24b9bd1d4d2b8cba62300bfb4ec9a6187a957e8ddb9434c5224"},
|
||||
{file = "tomli-2.0.0.tar.gz", hash = "sha256:c292c34f58502a1eb2bbb9f5bbc9a5ebc37bee10ffb8c2d6bbdfa8eb13cc14e1"},
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
tomlkit = [
|
||||
{file = "tomlkit-0.8.0-py3-none-any.whl", hash = "sha256:b824e3466f1d475b2b5f1c392954c6cb7ea04d64354ff7300dc7c14257dc85db"},
|
||||
{file = "tomlkit-0.8.0.tar.gz", hash = "sha256:29e84a855712dfe0e88a48f6d05c21118dbafb283bb2eed614d46f80deb8e9a1"},
|
||||
{file = "tomlkit-0.11.0-py3-none-any.whl", hash = "sha256:0f4050db66fd445b885778900ce4dd9aea8c90c4721141fde0d6ade893820ef1"},
|
||||
{file = "tomlkit-0.11.0.tar.gz", hash = "sha256:71ceb10c0eefd8b8f11fe34e8a51ad07812cb1dc3de23247425fbc9ddc47b9dd"},
|
||||
]
|
||||
tqdm = [
|
||||
{file = "tqdm-4.64.0-py2.py3-none-any.whl", hash = "sha256:74a2cdefe14d11442cedf3ba4e21a3b84ff9a2dbdc6cfae2c34addb2a14a5ea6"},
|
||||
|
@ -3302,8 +3403,8 @@ urllib3 = [
|
|||
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
|
||||
]
|
||||
virtualenv = [
|
||||
{file = "virtualenv-20.0.31-py2.py3-none-any.whl", hash = "sha256:e0305af10299a7fb0d69393d8f04cb2965dda9351140d11ac8db4e5e3970451b"},
|
||||
{file = "virtualenv-20.0.31.tar.gz", hash = "sha256:43add625c53c596d38f971a465553f6318decc39d98512bc100fa1b1e839c8dc"},
|
||||
{file = "virtualenv-20.8.1-py2.py3-none-any.whl", hash = "sha256:10062e34c204b5e4ec5f62e6ef2473f8ba76513a9a617e873f1f8fb4a519d300"},
|
||||
{file = "virtualenv-20.8.1.tar.gz", hash = "sha256:bcc17f0b3a29670dd777d6f0755a4c04f28815395bca279cdcb213b97199a6b8"},
|
||||
]
|
||||
watchtower = [
|
||||
{file = "watchtower-0.8.0-py2.py3-none-any.whl", hash = "sha256:d6704b258494bddc3e9ddda286ef5067e4b09ab4287aea4289afdd035cc4742b"},
|
||||
|
|
|
@ -53,7 +53,7 @@ packages = [
|
|||
include = ["templates/*", "templates/**/*"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
python = "^3.7.2"
|
||||
flask = "^1.1.2"
|
||||
flask_login = "^0.5.0"
|
||||
wtforms = "^2.3.3"
|
||||
|
@ -116,9 +116,8 @@ pytest = "^7.0.0"
|
|||
pytest-cov = "^3.0.0"
|
||||
pre-commit = "^2.17.0"
|
||||
black = "^22.1.0"
|
||||
flake8 = "^4.0.1"
|
||||
flake8-bugbear = "^22.1.11"
|
||||
djlint = "0.7.3"
|
||||
djlint = "^1.3.0"
|
||||
pylint = "^2.14.4"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
export DB_URI=postgresql://myuser:mypassword@localhost:15432/simplelogin
|
||||
echo 'drop schema public cascade; create schema public;' | psql $DB_URI
|
||||
echo 'drop schema public cascade; create schema public;' | psql $DB_URI
|
||||
|
||||
poetry run alembic upgrade head
|
||||
poetry run flask dummy-data
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
export DB_URI=postgresql://myuser:mypassword@localhost:15432/test
|
||||
echo 'drop schema public cascade; create schema public;' | psql $DB_URI
|
||||
echo 'drop schema public cascade; create schema public;' | psql $DB_URI
|
||||
|
||||
poetry run alembic upgrade head
|
||||
|
|
|
@ -7,7 +7,7 @@ function confirmDeleteAlias() {
|
|||
|
||||
let message = `Maybe you want to disable the alias instead? Please note once deleted, it <b>can't</b> be restored.`;
|
||||
if (aliasDomainTrashUrl !== undefined) {
|
||||
message = `Maybe you want to disable the alias instead? When it's deleted, it's moved to the domain
|
||||
message = `Maybe you want to disable the alias instead? When it's deleted, it's moved to the domain
|
||||
<a href="${aliasDomainTrashUrl}">trash</a>`;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
<div class="card">
|
||||
<div class="card-body p-6 text-center">
|
||||
<h1 class="h4">An email to validate your email is on its way.</h1>
|
||||
<p>
|
||||
Please check your inbox/spam folder.
|
||||
</p>
|
||||
<p>Please check your inbox/spam folder.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -29,9 +29,7 @@
|
|||
style="border: 1px solid"
|
||||
class="my-2 img-fluid"/>
|
||||
</p>
|
||||
<p>
|
||||
This might seem like "magic" but trust us, only the first time is a bit awkward.
|
||||
</p>
|
||||
<p>This might seem like "magic" but trust us, only the first time is a bit awkward.</p>
|
||||
<p>
|
||||
{% if alias.mailbox_id %}
|
||||
{% if alias.mailboxes | length == 1 %}
|
||||
|
|
|
@ -10,9 +10,7 @@
|
|||
<p>
|
||||
You are invited to become the owner of the alias <b>{{ alias.email }}</b>
|
||||
</p>
|
||||
<p>
|
||||
Please choose the mailbox(es) that owns this alias 👇
|
||||
</p>
|
||||
<p>Please choose the mailbox(es) that owns this alias 👇</p>
|
||||
<form method="post" class="mt-2">
|
||||
<select data-width="100%" class="mailbox-select" multiple name="mailbox_ids">
|
||||
{% for mailbox in mailboxes %}
|
||||
|
|
|
@ -51,9 +51,7 @@
|
|||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<p class="mt-5">
|
||||
This person can then confirm the reception and become the owner of the alias.
|
||||
</p>
|
||||
<p class="mt-5">This person can then confirm the reception and become the owner of the alias.</p>
|
||||
<div class="alert alert-danger">After the confirmation, you can no longer use this alias.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -131,5 +131,5 @@
|
|||
that.closest("form").submit();
|
||||
|
||||
})
|
||||
</script>
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -109,9 +109,7 @@
|
|||
<div id="debug-zone">
|
||||
<hr />
|
||||
<h3>Debug Zone</h3>
|
||||
<p>
|
||||
You can test whether an alias will be automatically created given the rules above
|
||||
</p>
|
||||
<p>You can test whether an alias will be automatically created given the rules above</p>
|
||||
<div class="alert alert-info">No worries, no alias will be created during the test :)</div>
|
||||
<form method="post" action="#debug-zone">
|
||||
<input type="hidden" name="form-name" value="test-auto-create-rule">
|
||||
|
|
|
@ -7,12 +7,8 @@
|
|||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1 class="h2">Entering Sudo Mode</h1>
|
||||
<p>
|
||||
The next page contains security related setting.
|
||||
</p>
|
||||
<p>
|
||||
Please enter your account password so that we can ensure it's you.
|
||||
</p>
|
||||
<p>The next page contains security related setting.</p>
|
||||
<p>Please enter your account password so that we can ensure it's you.</p>
|
||||
<form method="post">
|
||||
{{ password_check_form.csrf_token }}
|
||||
<div class="font-weight-bold mt-5">Password</div>
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1 class="h2">Extend Subscription</h1>
|
||||
<p>
|
||||
Your subscription is expired on {{ coinbase_subscription.end_at.format("YYYY-MM-DD") }}
|
||||
</p>
|
||||
<p>Your subscription is expired on {{ coinbase_subscription.end_at.format("YYYY-MM-DD") }}</p>
|
||||
<div>
|
||||
<a class="buy-with-crypto"
|
||||
data-custom="{{ current_user.id }}"
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1 class="h2">Manage Your Security Key</h1>
|
||||
<p>
|
||||
Unlink all keys will also disable WebAuthn 2FA.
|
||||
</p>
|
||||
<p>Unlink all keys will also disable WebAuthn 2FA.</p>
|
||||
<form id="formManageKey" method="post">
|
||||
{{ fido_manage_form.csrf_token }}
|
||||
{{ fido_manage_form.credential_id(class="form-control", placeholder="") }}
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1 class="h2 text-center">Register Your Security Key</h1>
|
||||
<p class="text-center">
|
||||
Follow your browser's steps to register your security key with SimpleLogin
|
||||
</p>
|
||||
<p class="text-center">Follow your browser's steps to register your security key with SimpleLogin</p>
|
||||
<form id="formRegisterKey" method="post">
|
||||
{{ fido_token_form.csrf_token }}
|
||||
{{ fido_token_form.sk_assertion(class="form-control", placeholder="") }}
|
||||
|
|
|
@ -26,441 +26,491 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block title %}Alias{% endblock %}
|
||||
{% block default_content %}
|
||||
|
||||
<!-- Global Stats -->
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader">Aliases</div>
|
||||
<div class="text-muted" style="order: 2; margin-left: auto; font-size: .8rem">All time</div>
|
||||
</div>
|
||||
<div class="h1 m-0">{{ stats.nb_alias }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader">Forwards</div>
|
||||
<div class="text-muted" style="order: 2; margin-left: auto; font-size: .8rem">Last 14 days</div>
|
||||
</div>
|
||||
<div class="h1 m-0">{{ stats.nb_forward }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader">Replies/Sent</div>
|
||||
<div class="text-muted" style="order: 2; margin-left: auto; font-size: .8rem">Last 14 days</div>
|
||||
</div>
|
||||
<div class="h1 m-0">{{ stats.nb_reply }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader">Blocks</div>
|
||||
<div class="text-muted" style="order: 2; margin-left: auto; font-size: .8rem">Last 14 days</div>
|
||||
</div>
|
||||
<div class="h1 m-0">{{ stats.nb_block }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Global Stats -->
|
||||
<!-- Controls: buttons & search -->
|
||||
<div id="filter-app">
|
||||
<div class="row mb-3">
|
||||
<div class="col d-flex">
|
||||
<div>
|
||||
<div class="btn-group" role="group">
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="create-custom-email">
|
||||
<button data-toggle="tooltip" title="Create a custom alias" class="btn btn-primary mr-2">
|
||||
<i class="fa fa-plus"></i> New Custom Alias
|
||||
</button>
|
||||
</form>
|
||||
<div class="btn-group" role="group">
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="create-random-email">
|
||||
<button data-toggle="tooltip" title="Create a totally random alias" class="btn btn-success">
|
||||
<i class="fa fa-random"></i> Random Alias
|
||||
</button>
|
||||
</form>
|
||||
<button id="btnGroupDrop1" type="button" class="btn btn-success dropdown-toggle btn-group-border-left" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right border-left" aria-labelledby="btnGroupDrop1">
|
||||
<div>
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="create-random-email">
|
||||
<input type="hidden" name="generator_scheme" value="{{ AliasGeneratorEnum.word.value }}">
|
||||
<button class="dropdown-item">By Random Words</button>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="create-random-email">
|
||||
<input type="hidden" name="generator_scheme" value="{{ AliasGeneratorEnum.uuid.value }}">
|
||||
<button class="dropdown-item">By UUID</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left: auto">
|
||||
<div class="btn-group">
|
||||
<a v-if="!showFilter" @click="toggleFilter()" class="btn btn-outline-secondary">
|
||||
<i class="fe fe-chevrons-down"></i> Filters
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" v-if="showFilter" id="filter-control">
|
||||
<!-- Filter Control -->
|
||||
<div class="col d-flex">
|
||||
<form method="get" class="form-inline">
|
||||
<select name="sort" onchange="this.form.submit()" class="form-control mr-3 shadow">
|
||||
<option value="" {% if sort == "" %} selected{% endif %}>
|
||||
Sort by most recent activity
|
||||
</option>
|
||||
<option value="old2new" {% if sort == "old2new" %} selected{% endif %}>
|
||||
Alias Old-Recent
|
||||
</option>
|
||||
<option value="new2old" {% if sort == "new2old" %} selected{% endif %}>
|
||||
Alias Recent-Old
|
||||
</option>
|
||||
<option value="a2z" {% if sort == "a2z" %} selected{% endif %}>
|
||||
Alias A-Z
|
||||
</option>
|
||||
<option value="z2a" {% if sort == "z2a" %} selected{% endif %}>
|
||||
Alias Z-A
|
||||
</option>
|
||||
</select>
|
||||
<select name="filter" onchange="this.form.submit()" class="form-control mr-3 shadow" style="max-width: 200px">
|
||||
<option value="" {% if filter == "" %} selected{% endif %}>
|
||||
All Aliases
|
||||
</option>
|
||||
<option value="pinned" {% if filter == "pinned" %} selected{% endif %}>
|
||||
Pinned Aliases
|
||||
</option>
|
||||
<option value="enabled" {% if filter == "enabled" %} selected{% endif %}>
|
||||
Only Enabled Aliases
|
||||
</option>
|
||||
<option value="disabled" {% if filter == "disabled" %} selected{% endif %}>
|
||||
Only Disabled Aliases
|
||||
</option>
|
||||
<option value="hibp" {% if filter == "hibp" %} selected{% endif %}>
|
||||
Only Aliases Found In Data Breaches
|
||||
</option>
|
||||
{% for mailbox in current_user.mailboxes() %}
|
||||
|
||||
<option value="mailbox:{{ mailbox.id }}" {% if filter == "mailbox:" ~ mailbox.id %}
|
||||
selected {% endif %}>
|
||||
{{ mailbox.email }}'s aliases
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% for directory in current_user.directories %}
|
||||
|
||||
<option value="directory:{{ directory.id }}" {% if filter == "directory:" ~ directory.id %}
|
||||
selected {% endif %}>
|
||||
Directory <b>{{ directory.name }}</b> aliases
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="search" name="query" placeholder="Enter to search for alias" class="form-control shadow mr-2" style="max-width: 15em" value="{{ query }}">
|
||||
</form>
|
||||
<div style="margin-left: auto">
|
||||
{% if query or sort or filter %}
|
||||
|
||||
<a href="{{ url_for('dashboard.index') }}" class="btn btn-outline-secondary">Reset</a>
|
||||
{% endif %}
|
||||
<a v-if="showFilter" @click="toggleFilter()" class="btn btn-outline-secondary">
|
||||
<i class="fe fe-chevrons-up"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Controls: buttons & search -->
|
||||
<!-- Alias list -->
|
||||
<div class="row">
|
||||
{% for alias_info in alias_infos %}
|
||||
|
||||
{% set alias = alias_info.alias %}
|
||||
<div class="col-12 col-lg-6" id="alias-container-{{ alias.id }}">
|
||||
<div class="card p-4 shadow-sm {% if alias.id == highlight_alias_id %} highlight-row{% endif %} " {% if highlight_alias_id and alias.id != highlight_alias_id %} style="opacity: 0.6"{% endif %}>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<span class="{% if alias.id == highlight_alias_id %} highlighted{% endif %} clipboard cursor mb-0" {% if loop.index ==1 %}
|
||||
data-intro="This is your first <em>alias</em>.
|
||||
<br />
|
||||
<br />
|
||||
Emails sent to an alias are <em>forwarded</em> to your <em>real</em> email address.
|
||||
<br />
|
||||
<br />
|
||||
" data-step="2"
|
||||
{% endif %}
|
||||
{% if alias.enabled %}data-toggle="tooltip" title="Click to copy" data-clipboard-text="{{ alias.email }}"{% endif %}
|
||||
>
|
||||
<span class="font-weight-bold">{{ alias.email }}</span>
|
||||
</span>
|
||||
{% if alias.automatic_creation %}
|
||||
|
||||
<span class="fa fa-inbox" data-toggle="tooltip" title="This alias was automatically generated because of an incoming email"></span>
|
||||
{% endif %}
|
||||
{% if alias.pinned %}
|
||||
|
||||
<span class="fa fa-thumb-tack" data-toggle="tooltip" title="This alias is pinned"></span>
|
||||
{% endif %}
|
||||
{% if alias.hibp_breaches | length > 0 %}
|
||||
|
||||
<a href="https://haveibeenpwned.com/account/{{ alias.email }}">
|
||||
<span class="fa fa-warning text-danger" data-toggle="tooltip" title="This alias was found in {{ alias.hibp_breaches | length }} data breaches. Check haveibeenpwned.com for more information."></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if alias.custom_domain and not alias.custom_domain.verified %}
|
||||
|
||||
<span class="fa fa-warning text-warning" data-toggle="tooltip" title="Alias can't receive emails as its domain doesn't have MX records set up."></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col text-right">
|
||||
<label class="custom-switch cursor" data-toggle="tooltip" {% if alias.enabled %}
|
||||
title="Disable alias - stop receiving emails sent to this alias" {% else %} title="Enable alias - start receiving emails sent to this alias" {% endif %} {% if loop.index ==1 %}
|
||||
data-intro="By <em>disabling</em> an alias, emails sent to this alias will <em>not</em> be forwarded to your inbox.
|
||||
<br />
|
||||
<br />
|
||||
" data-step="3"
|
||||
{% endif %}
|
||||
style="padding-left: 0px">
|
||||
<input type="checkbox" class="enable-disable-alias custom-switch-input" data-alias="{{ alias.id }}" data-alias-email="{{ alias.email }}" {{ "checked" if alias.enabled else "" }}>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Email Activity -->
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<div style="font-size: 12px">
|
||||
{% if alias_info.latest_email_log != None %}
|
||||
|
||||
{% set email_log = alias_info.latest_email_log %}
|
||||
{% set contact = alias_info.latest_contact %}
|
||||
{% if email_log.is_reply %}
|
||||
|
||||
{{ contact.website_email }}
|
||||
<i class="fa fa-reply mr-2" data-toggle="tooltip" title="Email reply/sent from alias"></i>
|
||||
{{ email_log.created_at | dt }}
|
||||
{% elif email_log.bounced %}
|
||||
<span class="text-danger">
|
||||
{{ contact.website_email }}
|
||||
<i class="fa fa-warning mr-2" data-toggle="tooltip" title="Email bounced and cannot be forwarded to your mailbox"></i>
|
||||
{{ email_log.created_at | dt }}
|
||||
</span>
|
||||
{% elif email_log.blocked %}
|
||||
{{ contact.website_email }}
|
||||
<i class="fa fa-ban mr-2 text-danger" data-toggle="tooltip" title="Email blocked"></i>
|
||||
{{ email_log.created_at | dt }}
|
||||
{% else %}
|
||||
{{ contact.website_email }}
|
||||
<i class="fa fa-paper-plane mr-2" data-toggle="tooltip" title="Email sent to alias"></i>
|
||||
{{ email_log.created_at | dt }}
|
||||
{% include 'partials/toggle_contact.html' %}
|
||||
|
||||
{% endif %}
|
||||
{% else %}
|
||||
No emails received/sent in the last 14 days. Created {{ alias.created_at | dt }}.
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Email Activity -->
|
||||
<div class="small-text mt-1">
|
||||
Alias description
|
||||
</div>
|
||||
<div class="d-flex mb-2">
|
||||
<div class="flex-grow-1 mr-2">
|
||||
<textarea id="note-{{ alias.id }}" name="note" class="form-control" style="font-size: 12px" rows="2" placeholder="e.g. where the alias is used or why is it created">{{ alias.note or "" }}</textarea>
|
||||
</div>
|
||||
<div>
|
||||
<a data-alias="{{ alias.id }}"
|
||||
class="save-note btn btn-sm btn-outline-success w-100">
|
||||
Save
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Send Email && More button -->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="{{ url_for('dashboard.alias_contact_manager', alias_id=alias.id) }}" id="send-email-{{ alias.id }}" {% if loop.index ==1 %}
|
||||
data-intro="Not only alias can receive emails, it can <em>send</em> emails too!
|
||||
<br />
|
||||
<br />
|
||||
You can add a new <em>contact</em> for your alias here.
|
||||
<br />
|
||||
<br />
|
||||
If you need to reply to an email, just hit 'Reply': the response will come from your alias and your real email address stays <em>hidden</em>." data-step="4"
|
||||
{% endif %}
|
||||
class="btn btn-sm btn-outline-primary
|
||||
{% if not alias.enabled %}disabled{% endif %}
|
||||
" data-toggle="tooltip" title="Add new contact, manage your existing contacts">
|
||||
Contacts <i class="fe fe-send"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% if not current_user.expand_alias_info %}
|
||||
|
||||
<div class="col text-right">
|
||||
<a class="btn btn-sm collapsed"
|
||||
data-toggle="collapse"
|
||||
href="#alias-{{ alias.id }}"
|
||||
role="button"
|
||||
aria-expanded="false">
|
||||
<span class="if-collapsed">
|
||||
More <i class="fe fe-chevron-down"></i>
|
||||
</span>
|
||||
<span class="if-not-collapsed">Less
|
||||
<i class="fe fe-chevron-up"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<!-- END Send Email && More button -->
|
||||
<!-- Collapse section -->
|
||||
<div class="{% if not current_user.expand_alias_info %} collapse{% endif %} mt-2"
|
||||
id="alias-{{ alias.id }}">
|
||||
{% if alias_info.latest_email_log != None %}
|
||||
|
||||
<div style="font-size: 12px">
|
||||
Alias created {{ alias.created_at | dt }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<span class="alias-activity">{{ alias_info.nb_forward }}</span> forwards,
|
||||
<span class="alias-activity">{{ alias_info.nb_blocked }}</span> blocks,
|
||||
<span class="alias-activity">{{ alias_info.nb_reply }}</span> sents
|
||||
in the last 14 days
|
||||
<a href="{{ url_for('dashboard.alias_log', alias_id=alias.id) }}"
|
||||
class="btn btn-sm btn-link">
|
||||
See All →
|
||||
</a>
|
||||
{% if mailboxes|length > 1 %}
|
||||
|
||||
<div class="small-text">
|
||||
Current mailbox
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1 mr-2">
|
||||
<select required
|
||||
id="mailbox-{{ alias.id }}"
|
||||
data-width="100%"
|
||||
class="mailbox-select"
|
||||
multiple
|
||||
name="mailbox">
|
||||
{% for mailbox in mailboxes %}
|
||||
|
||||
<option value="{{ mailbox.id }}" {% if alias_info.contain_mailbox(mailbox.id) %}
|
||||
selected {% endif %}>
|
||||
{{ mailbox.email }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<!-- Global Stats -->
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader">Aliases</div>
|
||||
<div class="text-muted"
|
||||
style="order: 2; margin-left: auto; font-size: .8rem">All time</div>
|
||||
</div>
|
||||
<div class="h1 m-0">{{ stats.nb_alias }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a data-alias="{{ alias.id }}"
|
||||
class="save-mailbox btn btn-sm btn-outline-info w-100">
|
||||
Update
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader">Forwards</div>
|
||||
<div class="text-muted"
|
||||
style="order: 2; margin-left: auto; font-size: .8rem">Last 14 days</div>
|
||||
</div>
|
||||
<div class="h1 m-0">{{ stats.nb_forward }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader">Replies/Sent</div>
|
||||
<div class="text-muted"
|
||||
style="order: 2; margin-left: auto; font-size: .8rem">Last 14 days</div>
|
||||
</div>
|
||||
<div class="h1 m-0">{{ stats.nb_reply }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 col-lg-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="subheader">Blocks</div>
|
||||
<div class="text-muted"
|
||||
style="order: 2; margin-left: auto; font-size: .8rem">Last 14 days</div>
|
||||
</div>
|
||||
<div class="h1 m-0">{{ stats.nb_block }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Global Stats -->
|
||||
<!-- Controls: buttons & search -->
|
||||
<div id="filter-app">
|
||||
<div class="row mb-3">
|
||||
<div class="col d-flex">
|
||||
<div>
|
||||
<div class="btn-group" role="group">
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="create-custom-email">
|
||||
<button data-toggle="tooltip"
|
||||
title="Create a custom alias"
|
||||
class="btn btn-primary mr-2">
|
||||
<i class="fa fa-plus"></i> New Custom Alias
|
||||
</button>
|
||||
</form>
|
||||
<div class="btn-group" role="group">
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="create-random-email">
|
||||
<button data-toggle="tooltip"
|
||||
title="Create a totally random alias"
|
||||
class="btn btn-success">
|
||||
<i class="fa fa-random"></i> Random Alias
|
||||
</button>
|
||||
</form>
|
||||
<button id="btnGroupDrop1"
|
||||
type="button"
|
||||
class="btn btn-success dropdown-toggle btn-group-border-left"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right border-left"
|
||||
aria-labelledby="btnGroupDrop1">
|
||||
<div>
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="create-random-email">
|
||||
<input type="hidden"
|
||||
name="generator_scheme"
|
||||
value="{{ AliasGeneratorEnum.word.value }}">
|
||||
<button class="dropdown-item">By Random Words</button>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="create-random-email">
|
||||
<input type="hidden"
|
||||
name="generator_scheme"
|
||||
value="{{ AliasGeneratorEnum.uuid.value }}">
|
||||
<button class="dropdown-item">By UUID</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left: auto">
|
||||
<div class="btn-group">
|
||||
<a v-if="!showFilter"
|
||||
@click="toggleFilter()"
|
||||
class="btn btn-outline-secondary">
|
||||
<i class="fe fe-chevrons-down"></i> Filters
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2" v-if="showFilter" id="filter-control">
|
||||
<!-- Filter Control -->
|
||||
<div class="col d-flex">
|
||||
<form method="get" class="form-inline">
|
||||
<select name="sort"
|
||||
onchange="this.form.submit()"
|
||||
class="form-control mr-3 shadow">
|
||||
<option value="" {% if sort == "" %} selected{% endif %}>
|
||||
Sort by most recent activity
|
||||
</option>
|
||||
<option value="old2new" {% if sort == "old2new" %} selected{% endif %}>
|
||||
Alias Old-Recent
|
||||
</option>
|
||||
<option value="new2old" {% if sort == "new2old" %} selected{% endif %}>
|
||||
Alias Recent-Old
|
||||
</option>
|
||||
<option value="a2z" {% if sort == "a2z" %} selected{% endif %}>
|
||||
Alias A-Z
|
||||
</option>
|
||||
<option value="z2a" {% if sort == "z2a" %} selected{% endif %}>
|
||||
Alias Z-A
|
||||
</option>
|
||||
</select>
|
||||
<select name="filter"
|
||||
onchange="this.form.submit()"
|
||||
class="form-control mr-3 shadow"
|
||||
style="max-width: 200px">
|
||||
<option value="" {% if filter == "" %} selected{% endif %}>
|
||||
All Aliases
|
||||
</option>
|
||||
<option value="pinned" {% if filter == "pinned" %} selected{% endif %}>
|
||||
Pinned Aliases
|
||||
</option>
|
||||
<option value="enabled" {% if filter == "enabled" %} selected{% endif %}>
|
||||
Only Enabled Aliases
|
||||
</option>
|
||||
<option value="disabled" {% if filter == "disabled" %} selected{% endif %}>
|
||||
Only Disabled Aliases
|
||||
</option>
|
||||
<option value="hibp" {% if filter == "hibp" %} selected{% endif %}>
|
||||
Only Aliases Found In Data Breaches
|
||||
</option>
|
||||
{% for mailbox in current_user.mailboxes() %}
|
||||
|
||||
<option value="mailbox:{{ mailbox.id }}" {% if filter == "mailbox:" ~ mailbox.id %}
|
||||
selected {% endif %}>
|
||||
{{ mailbox.email }}'s aliases
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% for directory in current_user.directories %}
|
||||
|
||||
<option value="directory:{{ directory.id }}" {% if filter == "directory:" ~ directory.id %}
|
||||
selected {% endif %}>
|
||||
Directory <b>{{ directory.name }}</b> aliases
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="search"
|
||||
name="query"
|
||||
placeholder="Enter to search for alias"
|
||||
class="form-control shadow mr-2"
|
||||
style="max-width: 15em"
|
||||
value="{{ query }}">
|
||||
</form>
|
||||
<div style="margin-left: auto">
|
||||
{% if query or sort or filter %}
|
||||
|
||||
<a href="{{ url_for('dashboard.index') }}"
|
||||
class="btn btn-outline-secondary">Reset</a>
|
||||
{% endif %}
|
||||
<a v-if="showFilter"
|
||||
@click="toggleFilter()"
|
||||
class="btn btn-outline-secondary">
|
||||
<i class="fe fe-chevrons-up"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Controls: buttons & search -->
|
||||
<!-- Alias list -->
|
||||
<div class="row">
|
||||
{% for alias_info in alias_infos %}
|
||||
|
||||
{% set alias = alias_info.alias %}
|
||||
<div class="col-12 col-lg-6" id="alias-container-{{ alias.id }}">
|
||||
<div class="card p-4 shadow-sm {% if alias.id == highlight_alias_id %} highlight-row{% endif %} "
|
||||
{% if highlight_alias_id and alias.id != highlight_alias_id %} style="opacity: 0.6"{% endif %}>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<span class="{% if alias.id == highlight_alias_id %} highlighted{% endif %} clipboard cursor mb-0" {% if loop.index ==1 %}
|
||||
data-intro="This is your first <em>alias</em>.
|
||||
<br />
|
||||
<br />
|
||||
Emails sent to an alias are <em>forwarded</em> to your <em>real</em> email address.
|
||||
<br />
|
||||
<br />
|
||||
" data-step="2"
|
||||
{% endif %}
|
||||
{% if alias.enabled %}data-toggle="tooltip" title="Click to copy" data-clipboard-text="{{ alias.email }}"{% endif %}
|
||||
>
|
||||
<span class="font-weight-bold">{{ alias.email }}</span>
|
||||
</span>
|
||||
{% if alias.automatic_creation %}
|
||||
|
||||
<span class="fa fa-inbox"
|
||||
data-toggle="tooltip"
|
||||
title="This alias was automatically generated because of an incoming email"></span>
|
||||
{% endif %}
|
||||
{% if alias.pinned %}
|
||||
|
||||
<span class="fa fa-thumb-tack"
|
||||
data-toggle="tooltip"
|
||||
title="This alias is pinned"></span>
|
||||
{% endif %}
|
||||
{% if alias.hibp_breaches | length > 0 %}
|
||||
|
||||
<a href="https://haveibeenpwned.com/account/{{ alias.email }}">
|
||||
<span class="fa fa-warning text-danger"
|
||||
data-toggle="tooltip"
|
||||
title="This alias was found in {{ alias.hibp_breaches | length }} data breaches. Check haveibeenpwned.com for more information."></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if alias.custom_domain and not alias.custom_domain.verified %}
|
||||
|
||||
<span class="fa fa-warning text-warning"
|
||||
data-toggle="tooltip"
|
||||
title="Alias can't receive emails as its domain doesn't have MX records set up."></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col text-right">
|
||||
<label class="custom-switch cursor" data-toggle="tooltip" {% if alias.enabled %}
|
||||
title="Disable alias - stop receiving emails sent to this alias" {% else %} title="Enable alias - start receiving emails sent to this alias" {% endif %} {% if loop.index ==1 %}
|
||||
data-intro="By <em>disabling</em> an alias, emails sent to this alias will <em>not</em> be forwarded to your inbox.
|
||||
<br />
|
||||
<br />
|
||||
" data-step="3"
|
||||
{% endif %}
|
||||
style="padding-left: 0px">
|
||||
<input type="checkbox" class="enable-disable-alias custom-switch-input" data-alias="{{ alias.id }}" data-alias-email="{{ alias.email }}" {{ "checked" if alias.enabled else "" }}>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Email Activity -->
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<div style="font-size: 12px">
|
||||
{% if alias_info.latest_email_log != None %}
|
||||
|
||||
{% set email_log = alias_info.latest_email_log %}
|
||||
{% set contact = alias_info.latest_contact %}
|
||||
{% if email_log.is_reply %}
|
||||
|
||||
{{ contact.website_email }}
|
||||
<i class="fa fa-reply mr-2"
|
||||
data-toggle="tooltip"
|
||||
title="Email reply/sent from alias"></i>
|
||||
{{ email_log.created_at | dt }}
|
||||
{% elif email_log.bounced %}
|
||||
<span class="text-danger">
|
||||
{{ contact.website_email }}
|
||||
<i class="fa fa-warning mr-2"
|
||||
data-toggle="tooltip"
|
||||
title="Email bounced and cannot be forwarded to your mailbox"></i>
|
||||
{{ email_log.created_at | dt }}
|
||||
</span>
|
||||
{% elif email_log.blocked %}
|
||||
{{ contact.website_email }}
|
||||
<i class="fa fa-ban mr-2 text-danger"
|
||||
data-toggle="tooltip"
|
||||
title="Email blocked"></i>
|
||||
{{ email_log.created_at | dt }}
|
||||
{% else %}
|
||||
{{ contact.website_email }}
|
||||
<i class="fa fa-paper-plane mr-2"
|
||||
data-toggle="tooltip"
|
||||
title="Email sent to alias"></i>
|
||||
{{ email_log.created_at | dt }}
|
||||
{% include 'partials/toggle_contact.html' %}
|
||||
|
||||
{% endif %}
|
||||
{% else %}
|
||||
No emails received/sent in the last 14 days. Created {{ alias.created_at | dt }}.
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Email Activity -->
|
||||
<div class="small-text mt-1">
|
||||
Alias description
|
||||
</div>
|
||||
<div class="d-flex mb-2">
|
||||
<div class="flex-grow-1 mr-2">
|
||||
<textarea id="note-{{ alias.id }}" name="note" class="form-control" style="font-size: 12px" rows="2" placeholder="e.g. where the alias is used or why is it created">{{ alias.note or "" }}</textarea>
|
||||
</div>
|
||||
<div>
|
||||
<a data-alias="{{ alias.id }}"
|
||||
class="save-note btn btn-sm btn-outline-success w-100">
|
||||
Save
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Send Email && More button -->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="{{ url_for('dashboard.alias_contact_manager', alias_id=alias.id) }}" id="send-email-{{ alias.id }}" {% if loop.index ==1 %}
|
||||
data-intro="Not only alias can receive emails, it can <em>send</em> emails too!
|
||||
<br />
|
||||
<br />
|
||||
You can add a new <em>contact</em> for your alias here.
|
||||
<br />
|
||||
<br />
|
||||
If you need to reply to an email, just hit 'Reply': the response will come from your alias and your real email address stays <em>hidden</em>." data-step="4"
|
||||
{% endif %}
|
||||
class="btn btn-sm btn-outline-primary
|
||||
{% if not alias.enabled %}disabled{% endif %}
|
||||
" data-toggle="tooltip" title="Add new contact, manage your existing contacts">
|
||||
Contacts <i class="fe fe-send"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% elif alias_info.mailbox != None and alias_info.mailbox.email != current_user.email %}
|
||||
<div class="small-text">
|
||||
Owned by <b>{{ alias_info.mailbox.email }}</b> mailbox
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="small-text mt-2"
|
||||
data-toogle="tooltip"
|
||||
title="When sending an email from this alias, the email will have 'Display Name <{{ alias.email }}>' as sender.">
|
||||
Display name
|
||||
<i class="fe fe-help-circle"></i>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1 mr-2">
|
||||
<input id="alias-name-{{ alias.id }}"
|
||||
value="{{ alias.name or '' }}"
|
||||
class="form-control"
|
||||
placeholder="{{ alias.custom_domain.name or "Alias name" }}">
|
||||
</div>
|
||||
<div>
|
||||
<a data-alias="{{ alias.id }}"
|
||||
class="save-alias-name btn btn-sm btn-outline-primary w-100">
|
||||
Save
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% if alias.mailbox_support_pgp() %}
|
||||
{% if not current_user.expand_alias_info %}
|
||||
|
||||
<div class="small-text mt-2"
|
||||
data-toogle="tooltip"
|
||||
title="You can decide to turn off the PGP for an alias. This can be useful if the sender already encrypts the emails">
|
||||
PGP
|
||||
<i class="fe fe-help-circle"></i>
|
||||
<div class="col text-right">
|
||||
<a class="btn btn-sm collapsed"
|
||||
data-toggle="collapse"
|
||||
href="#alias-{{ alias.id }}"
|
||||
role="button"
|
||||
aria-expanded="false">
|
||||
<span class="if-collapsed">
|
||||
More <i class="fe fe-chevron-down"></i>
|
||||
</span>
|
||||
<span class="if-not-collapsed">Less
|
||||
<i class="fe fe-chevron-up"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
<label class="custom-switch cursor pl-0">
|
||||
<input type="checkbox" class="enable-disable-pgp custom-switch-input" data-alias="{{ alias.id }}" data-alias-email="{{ alias.email }}" {{ "checked" if alias.pgp_enabled() else "" }}>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="small-text mt-2"
|
||||
data-toogle="tooltip"
|
||||
title="it's always pinned on top">
|
||||
Pin this alias
|
||||
<i class="fe fe-help-circle"></i>
|
||||
</div>
|
||||
<div>
|
||||
<label class="custom-switch cursor pl-0">
|
||||
<input type="checkbox" class="pin-alias custom-switch-input" data-alias="{{ alias.id }}" data-alias-email="{{ alias.email }}" {{ "checked" if alias.pinned else "" }}>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div class="btn-group float-right" role="group" aria-label="Basic example">
|
||||
<a href="{{ url_for('dashboard.alias_transfer_send_route', alias_id=alias.id) }}"
|
||||
<!-- END Send Email && More button -->
|
||||
<!-- Collapse section -->
|
||||
<div class="{% if not current_user.expand_alias_info %} collapse{% endif %} mt-2"
|
||||
id="alias-{{ alias.id }}">
|
||||
{% if alias_info.latest_email_log != None %}
|
||||
|
||||
<div style="font-size: 12px">
|
||||
Alias created {{ alias.created_at | dt }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<span class="alias-activity">{{ alias_info.nb_forward }}</span> forwards,
|
||||
<span class="alias-activity">{{ alias_info.nb_blocked }}</span> blocks,
|
||||
<span class="alias-activity">{{ alias_info.nb_reply }}</span> sents
|
||||
in the last 14 days
|
||||
<a href="{{ url_for('dashboard.alias_log', alias_id=alias.id) }}"
|
||||
class="btn btn-sm btn-link">
|
||||
Transfer
|
||||
<i class="ml-0 dropdown-icon fe fe-share-2 text-primary"></i>
|
||||
See All →
|
||||
</a>
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="delete-alias">
|
||||
<input type="hidden" name="alias-id" value="{{ alias.id }}">
|
||||
<input type="hidden" name="alias" class="alias" value="{{ alias.email }}">
|
||||
<span class="btn btn-link btn-sm float-right text-danger"
|
||||
onclick="confirmDeleteAlias.call(this)"
|
||||
{% if alias.custom_domain %} data-custom-domain-trash-url="{{ alias.custom_domain.get_trash_url() }}"{% endif %}
|
||||
data-alias="{{ alias.id }}"
|
||||
data-alias-email="{{ alias.email }}">
|
||||
Delete <i class="dropdown-icon fe fe-trash-2 text-danger"></i>
|
||||
</span>
|
||||
</form>
|
||||
{% if mailboxes|length > 1 %}
|
||||
|
||||
<div class="small-text">
|
||||
Current mailbox
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1 mr-2">
|
||||
<select required
|
||||
id="mailbox-{{ alias.id }}"
|
||||
data-width="100%"
|
||||
class="mailbox-select"
|
||||
multiple
|
||||
name="mailbox">
|
||||
{% for mailbox in mailboxes %}
|
||||
|
||||
<option value="{{ mailbox.id }}" {% if alias_info.contain_mailbox(mailbox.id) %}
|
||||
selected {% endif %}>
|
||||
{{ mailbox.email }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<a data-alias="{{ alias.id }}"
|
||||
class="save-mailbox btn btn-sm btn-outline-info w-100">
|
||||
Update
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% elif alias_info.mailbox != None and alias_info.mailbox.email != current_user.email %}
|
||||
<div class="small-text">
|
||||
Owned by <b>{{ alias_info.mailbox.email }}</b> mailbox
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="small-text mt-2"
|
||||
data-toogle="tooltip"
|
||||
title="When sending an email from this alias, the email will have 'Display Name <{{ alias.email }}>' as sender.">
|
||||
Display name
|
||||
<i class="fe fe-help-circle"></i>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1 mr-2">
|
||||
<input id="alias-name-{{ alias.id }}"
|
||||
value="{{ alias.name or '' }}"
|
||||
class="form-control"
|
||||
placeholder="{{ alias.custom_domain.name or "Alias name" }}">
|
||||
</div>
|
||||
<div>
|
||||
<a data-alias="{{ alias.id }}"
|
||||
class="save-alias-name btn btn-sm btn-outline-primary w-100">
|
||||
Save
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% if alias.mailbox_support_pgp() %}
|
||||
|
||||
<div class="small-text mt-2"
|
||||
data-toogle="tooltip"
|
||||
title="You can decide to turn off the PGP for an alias. This can be useful if the sender already encrypts the emails">
|
||||
PGP
|
||||
<i class="fe fe-help-circle"></i>
|
||||
</div>
|
||||
<div>
|
||||
<label class="custom-switch cursor pl-0">
|
||||
<input type="checkbox" class="enable-disable-pgp custom-switch-input" data-alias="{{ alias.id }}" data-alias-email="{{ alias.email }}" {{ "checked" if alias.pgp_enabled() else "" }}>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="small-text mt-2"
|
||||
data-toogle="tooltip"
|
||||
title="it's always pinned on top">
|
||||
Pin this alias
|
||||
<i class="fe fe-help-circle"></i>
|
||||
</div>
|
||||
<div>
|
||||
<label class="custom-switch cursor pl-0">
|
||||
<input type="checkbox" class="pin-alias custom-switch-input" data-alias="{{ alias.id }}" data-alias-email="{{ alias.email }}" {{ "checked" if alias.pinned else "" }}>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div class="btn-group float-right" role="group" aria-label="Basic example">
|
||||
<a href="{{ url_for('dashboard.alias_transfer_send_route', alias_id=alias.id) }}"
|
||||
class="btn btn-sm btn-link">
|
||||
Transfer
|
||||
<i class="ml-0 dropdown-icon fe fe-share-2 text-primary"></i>
|
||||
</a>
|
||||
<form method="post">
|
||||
<input type="hidden" name="form-name" value="delete-alias">
|
||||
<input type="hidden" name="alias-id" value="{{ alias.id }}">
|
||||
<input type="hidden" name="alias" class="alias" value="{{ alias.email }}">
|
||||
<span class="btn btn-link btn-sm float-right text-danger"
|
||||
onclick="confirmDeleteAlias.call(this)"
|
||||
{% if alias.custom_domain %} data-custom-domain-trash-url="{{ alias.custom_domain.get_trash_url() }}"{% endif %}
|
||||
data-alias="{{ alias.id }}"
|
||||
data-alias-email="{{ alias.email }}">
|
||||
Delete <i class="dropdown-icon fe fe-trash-2 text-danger"></i>
|
||||
</span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Collapse section -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Collapse section -->
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- END Alias list -->
|
||||
|
|
|
@ -229,5 +229,5 @@
|
|||
$(this).closest("form").submit();
|
||||
});
|
||||
enableDragDropForPGPKeys('#pgp-public-key');
|
||||
</script>
|
||||
{% endblock %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -113,9 +113,7 @@ Upgrade your SimpleLogin account
|
|||
<i class="fe fe-chevron-up"></i>
|
||||
</span>
|
||||
</a>
|
||||
<p class="mt-2 small">
|
||||
Starts at $2.5/month (billed yearly)
|
||||
</p>
|
||||
<p class="mt-2 small">Starts at $2.5/month (billed yearly)</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -100,5 +100,5 @@
|
|||
}
|
||||
$(this).next('.custom-file-label').html(files.join(', '));
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
You are about to block the alias
|
||||
<a href="mailto:{{ alias }}">{{ alias }}</a>
|
||||
</p>
|
||||
<p>
|
||||
After this, you will stop receiving all emails sent to this alias, please confirm.
|
||||
</p>
|
||||
<p>After this, you will stop receiving all emails sent to this alias, please confirm.</p>
|
||||
<form method="post">
|
||||
<button class="btn btn-warning">Confirm</button>
|
||||
</form>
|
||||
|
|
|
@ -2,18 +2,14 @@
|
|||
<p style="font-size: 16px;
|
||||
line-height: 1.625;
|
||||
color: #51545E;
|
||||
margin: .4em 0 1.1875em;">
|
||||
{{ text }}
|
||||
</p>
|
||||
margin: .4em 0 1.1875em;">{{ text }}</p>
|
||||
{% endmacro %}
|
||||
<!-- To be used instead of render_text, much better! -->
|
||||
{% macro text() %}
|
||||
<p style="font-size: 16px;
|
||||
line-height: 1.625;
|
||||
color: #51545E;
|
||||
margin: .4em 0 1.1875em;">
|
||||
{{ caller() }}
|
||||
</p>
|
||||
margin: .4em 0 1.1875em;">{{ caller() }}</p>
|
||||
{% endmacro %}
|
||||
{% macro render_button(button_text, link) %}
|
||||
<!-- Action -->
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
alt="SimpleLogin logo">
|
||||
</a>
|
||||
<!-- End Logo -->
|
||||
<p class="small text-white">
|
||||
SimpleLogin is an open-source email alias solution to protect your email address.
|
||||
</p>
|
||||
<p class="small text-white">SimpleLogin is an open-source email alias solution to protect your email address.</p>
|
||||
<p class="small text-white">
|
||||
SimpleLogin is the product of SimpleLogin SAS, registered in France under the SIREN number 884302134.
|
||||
</p>
|
||||
|
|
|
@ -26,159 +26,172 @@
|
|||
background-color: #0ff;
|
||||
border: 3px solid #88d748;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block single_content %}
|
||||
|
||||
<form class="card" method="post" data-parsley-validate style="max-width: 40rem; margin: auto; border-radius: 2%">
|
||||
{% if not client.approved %}
|
||||
<form class="card"
|
||||
method="post"
|
||||
data-parsley-validate
|
||||
style="max-width: 40rem; margin: auto; border-radius: 2%">
|
||||
{% if not client.approved %}
|
||||
|
||||
<div class="alert alert-warning" style="border-bottom: 3px solid;">
|
||||
<b>{{ client.name }}</b> is in Dev Mode and isn't approved (yet) by SimpleLogin. <b>Please make sure you trust {{ client.name }} before proceeding.</b>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body p-6">
|
||||
<!-- User has already authorized this client -->
|
||||
{% if client_user %}
|
||||
<div class="alert alert-warning" style="border-bottom: 3px solid;">
|
||||
<b>{{ client.name }}</b> is in Dev Mode and isn't approved (yet) by SimpleLogin. <b>Please make sure you trust {{ client.name }} before proceeding.</b>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card-body p-6">
|
||||
<!-- User has already authorized this client -->
|
||||
{% if client_user %}
|
||||
|
||||
<div class="card-title">
|
||||
You have already authorized <b>{{ client.name }}</b>.
|
||||
</div>
|
||||
<hr />
|
||||
<div class="mb-4">
|
||||
<b>{{ client.name }}</b> has access to the following info:
|
||||
</div>
|
||||
<div>
|
||||
{% for scope in client.get_scopes() %}
|
||||
<div class="card-title">
|
||||
You have already authorized <b>{{ client.name }}</b>.
|
||||
</div>
|
||||
<hr />
|
||||
<div class="mb-4">
|
||||
<b>{{ client.name }}</b> has access to the following info:
|
||||
</div>
|
||||
<div>
|
||||
{% for scope in client.get_scopes() %}
|
||||
|
||||
<div>
|
||||
{% if scope == Scope.AVATAR_URL and user_info[scope.value] %}
|
||||
<div>
|
||||
{% if scope == Scope.AVATAR_URL and user_info[scope.value] %}
|
||||
|
||||
avatar:
|
||||
<img src="{{ user_info[scope.value] }}" class="avatar">
|
||||
{% elif scope == Scope.EMAIL %}
|
||||
{{ scope.value }}:
|
||||
<a href="mailto:{{ user_info[scope.value] }}">{{ user_info[scope.value] }}</a>
|
||||
{% elif scope == Scope.NAME %}
|
||||
{{ scope.value }}: <b>{{ user_info[scope.value] }}</b>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% if client.icon_id %}
|
||||
avatar:
|
||||
<img src="{{ user_info[scope.value] }}" class="avatar">
|
||||
{% elif scope == Scope.EMAIL %}
|
||||
{{ scope.value }}:
|
||||
<a href="mailto:{{ user_info[scope.value] }}">{{ user_info[scope.value] }}</a>
|
||||
{% elif scope == Scope.NAME %}
|
||||
{{ scope.value }}: <b>{{ user_info[scope.value] }}</b>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% if client.icon_id %}
|
||||
|
||||
<div class="text-center">
|
||||
<img src="{{ client.get_icon_url() }}" class="small-client-icon">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="text-center" style="font-size: larger">
|
||||
<b>{{ client.name }}</b> will receive the following info
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row mt-4 md-4">
|
||||
<div class="col-md-3 text-left">
|
||||
<label style="padding-top: .5rem">Email</label>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<select class="form-control" name="suggested-email">
|
||||
<option selected value="{{ suggested_email }}">
|
||||
{{ suggested_email }}
|
||||
</option>
|
||||
<option value="{{ current_user.email }}">
|
||||
{{ current_user.email }} (Personal Email)
|
||||
</option>
|
||||
{% for email in other_emails %}
|
||||
<div class="text-center">
|
||||
<img src="{{ client.get_icon_url() }}" class="small-client-icon">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="text-center" style="font-size: larger">
|
||||
<b>{{ client.name }}</b> will receive the following info
|
||||
</div>
|
||||
<hr />
|
||||
<div class="row mt-4 md-4">
|
||||
<div class="col-md-3 text-left">
|
||||
<label style="padding-top: .5rem">Email</label>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<select class="form-control" name="suggested-email">
|
||||
<option selected value="{{ suggested_email }}">
|
||||
{{ suggested_email }}
|
||||
</option>
|
||||
<option value="{{ current_user.email }}">
|
||||
{{ current_user.email }} (Personal Email)
|
||||
</option>
|
||||
{% for email in other_emails %}
|
||||
|
||||
<option value="{{ email }}">
|
||||
{{ email }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if current_user.can_create_new_alias() %}
|
||||
<option value="{{ email }}">
|
||||
{{ email }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if current_user.can_create_new_alias() %}
|
||||
|
||||
<div class="mt-2 mb-2">OR</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6 pr-1 mb-1" style="min-width: 5em">
|
||||
<input name="prefix" class="form-control" type="text" maxlength="40" data-parsley-pattern="[0-9a-z-_.]{1,}" data-parsley-trigger="change" data-parsley-error-message="Only lowercase letters, dots, numbers, dashes (-) and underscores (_) are currently supported." placeholder="Alias prefix, for example newsletter.com-123_xyz" autofocus>
|
||||
</div>
|
||||
<div class="col-sm-6" style="padding-left: 5px">
|
||||
<select class="form-control" name="suffix">
|
||||
{% for suffix in suffixes %}
|
||||
<div class="mt-2 mb-2">OR</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6 pr-1 mb-1" style="min-width: 5em">
|
||||
<input name="prefix"
|
||||
class="form-control"
|
||||
type="text"
|
||||
maxlength="40"
|
||||
data-parsley-pattern="[0-9a-z-_.]{1,}"
|
||||
data-parsley-trigger="change"
|
||||
data-parsley-error-message="Only lowercase letters, dots, numbers, dashes (-) and underscores (_) are currently supported."
|
||||
placeholder="Alias prefix, for example newsletter.com-123_xyz"
|
||||
autofocus>
|
||||
</div>
|
||||
<div class="col-sm-6" style="padding-left: 5px">
|
||||
<select class="form-control" name="suffix">
|
||||
{% for suffix in suffixes %}
|
||||
|
||||
<option value="{{ suffix.signed_suffix }}">
|
||||
{% if suffix.is_custom %}
|
||||
<option value="{{ suffix.signed_suffix }}">
|
||||
{% if suffix.is_custom %}
|
||||
|
||||
{{ suffix.suffix }} (your domain)
|
||||
{% else %}
|
||||
{{ suffix.suffix }}
|
||||
{% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4 md-4">
|
||||
<div class="col-md-3 text-left">
|
||||
<label style="padding-top: .5rem">Name</label>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<select class="form-control" name="suggested-name">
|
||||
<option selected value="{{ suggested_name }}">
|
||||
{{ suggested_name }}
|
||||
</option>
|
||||
{% for name in other_names %}
|
||||
{{ suffix.suffix }} (your domain)
|
||||
{% else %}
|
||||
{{ suffix.suffix }}
|
||||
{% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4 md-4">
|
||||
<div class="col-md-3 text-left">
|
||||
<label style="padding-top: .5rem">Name</label>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<select class="form-control" name="suggested-name">
|
||||
<option selected value="{{ suggested_name }}">
|
||||
{{ suggested_name }}
|
||||
</option>
|
||||
{% for name in other_names %}
|
||||
|
||||
<option value="{{ name }}">
|
||||
{{ name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="mt-2">OR</div>
|
||||
<div class="mt-2">
|
||||
<input class="form-control" name="custom-name">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if current_user.profile_picture_id %}
|
||||
<option value="{{ name }}">
|
||||
{{ name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="mt-2">OR</div>
|
||||
<div class="mt-2">
|
||||
<input class="form-control" name="custom-name">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if current_user.profile_picture_id %}
|
||||
|
||||
<div class="row mt-4 md-4">
|
||||
<div class="col-md-3 text-left">
|
||||
<label style="padding-top: 2rem">Avatar</label>
|
||||
</div>
|
||||
<div class="col-md-9" style="display: flex; align-items: center">
|
||||
<label>
|
||||
<input type="radio" name="avatar-choice" value="real" checked>
|
||||
<img src="{{ current_user.profile_picture_url() }}" class="small-profile-picture">
|
||||
</label>
|
||||
<div style="margin: 0 1rem">OR</div>
|
||||
<label>
|
||||
<input type="radio" name="avatar-choice" value="default">
|
||||
<img src="{{ url_for('static', filename='default-avatar.png') }}" class="small-profile-picture">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if client_user %}
|
||||
<div class="row mt-4 md-4">
|
||||
<div class="col-md-3 text-left">
|
||||
<label style="padding-top: 2rem">Avatar</label>
|
||||
</div>
|
||||
<div class="col-md-9" style="display: flex; align-items: center">
|
||||
<label>
|
||||
<input type="radio" name="avatar-choice" value="real" checked>
|
||||
<img src="{{ current_user.profile_picture_url() }}"
|
||||
class="small-profile-picture">
|
||||
</label>
|
||||
<div style="margin: 0 1rem">OR</div>
|
||||
<label>
|
||||
<input type="radio" name="avatar-choice" value="default">
|
||||
<img src="{{ url_for('static', filename='default-avatar.png') }}"
|
||||
class="small-profile-picture">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if client_user %}
|
||||
|
||||
<div class="form-footer">
|
||||
<div class="btn-group" role="group" aria-label="Basic example">
|
||||
<button type="submit" name="button" value="allow" class="btn btn-success">Allow</button>
|
||||
<button type="submit" name="button" value="deny" class="btn btn-light">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-footer">
|
||||
<div class="btn-group btn-block" role="group" aria-label="Basic example">
|
||||
<button type="submit" name="button" value="allow" class="btn btn-success">Allow</button>
|
||||
<button type="submit" name="button" value="deny" class="btn btn-light">Deny</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
<div class="form-footer">
|
||||
<div class="btn-group" role="group" aria-label="Basic example">
|
||||
<button type="submit" name="button" value="allow" class="btn btn-success">Allow</button>
|
||||
<button type="submit" name="button" value="deny" class="btn btn-light">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-footer">
|
||||
<div class="btn-group btn-block" role="group" aria-label="Basic example">
|
||||
<button type="submit" name="button" value="allow" class="btn btn-success">Allow</button>
|
||||
<button type="submit" name="button" value="deny" class="btn btn-light">Deny</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
</div>
|
||||
<div class="px-8" style="width:675px;margin:auto;">
|
||||
<div class="my-6">
|
||||
<p style="font-size: 1.2em;">
|
||||
Quickly create aliases everywhere using our {{ browser_name }} extension
|
||||
</p>
|
||||
<p style="font-size: 1.2em;">Quickly create aliases everywhere using our {{ browser_name }} extension</p>
|
||||
<a class="px-4 py-3 mt-4 text-decoration-none text-center"
|
||||
style="background:black;
|
||||
color:white;
|
||||
|
@ -32,9 +30,7 @@
|
|||
</div>
|
||||
<hr style="margin-top: 75px">
|
||||
<div style="margin-top: 75px">
|
||||
<p style="font-size: 1.2em;">
|
||||
Or install the extension later and start discovering our features on our web app
|
||||
</p>
|
||||
<p style="font-size: 1.2em;">Or install the extension later and start discovering our features on our web app</p>
|
||||
<a class="px-4 py-3 mt-4 text-decoration-none text-center"
|
||||
style="background:white;
|
||||
color:black;
|
||||
|
|
|
@ -53,8 +53,7 @@
|
|||
</p>
|
||||
<p id="extension-version-text"
|
||||
class="font-weight-light"
|
||||
style="display:none;">
|
||||
</p>
|
||||
style="display:none;"></p>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
X-SimpleLogin-Client-IP: 40.92.66.13
|
||||
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=40.92.66.13;
|
||||
helo=eur01-ve1-obe.outbound.protection.outlook.com;
|
||||
envelope-from=staff@hotmail.com; receiver=<UNKNOWN>
|
||||
envelope-from=staff@hotmail.com; receiver=<UNKNOWN>
|
||||
Received: from EUR01-VE1-obe.outbound.protection.outlook.com
|
||||
(mail-oln040092066013.outbound.protection.outlook.com [40.92.66.13])
|
||||
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
|
||||
|
@ -42,30 +42,30 @@ Date: Mon, 9 May 2022 13:10:08 +0000
|
|||
From: <staff@hotmail.com>
|
||||
Subject: complaint about message from 176.119.200.162
|
||||
To: {{ postmaster }}
|
||||
MIME-Version: 1.0
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="31A9507D-D0B3-4DCD-AFBB-413468892CFE"
|
||||
X-IncomingHeaderCount: 6
|
||||
Message-ID:
|
||||
Message-ID:
|
||||
<1d63d9ee-8f3e-4876-955c-1807db5ad138@AM6EUR05FT047.eop-eur05.prod.protection.outlook.com>
|
||||
X-EOPAttributedMessage: 0
|
||||
X-MS-PublicTrafficType: Email
|
||||
X-MS-Office365-Filtering-Correlation-Id: 44e9ec0b-6c5d-4cea-6417-08da31bd7000
|
||||
X-MS-TrafficTypeDiagnostic: AM0PR02MB4563:EE_
|
||||
X-Microsoft-Antispam: BCL:0;
|
||||
X-Microsoft-Antispam-Message-Info:
|
||||
X-Microsoft-Antispam-Message-Info:
|
||||
lK5xD4UZS47NfR0tHc3wEp4HHOifZ4SDBb8aKx7H/vEW8Rg8rXXH12G4lWdpzr8qTsCmvzuhj5x6IAumOKQ8lWLj5Lp3jyml91wVnwCtUnk5cTXpQwDZd9QMgtEW07GoLdWjkbShAhLRDf+9Y4DxidHCacOAYxcNX42wo3vYZOEHDzVRUxSmY0c7Km60pDtiYzEk+P9AoE2YKYG2rDwDx0vgoLgqFspGqQ+2OeHD2ZAEyATHR/sQy6tf5S2d4wA3HcHrwrGMlz/4d9VbT5h9a5cqj9S59wpuc6g8nyYhmK3AHJkB5nXmpBZBihTw5X/Qh5PZqUYwPxkwpq3WlaEuXvzaKFiwJFvtuRGX+mEioClCxiwPROb7sI9ZHWPw48AHysF+whYGBfleRy4c2SuW6e1D5uewGry+lXVljxg7qKo=
|
||||
X-OriginatorOrg: sct-15-20-4755-11-msonline-outlook-ab7de.templateTenant
|
||||
X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 May 2022 13:11:32.0875
|
||||
(UTC)
|
||||
X-MS-Exchange-CrossTenant-Network-Message-Id:
|
||||
X-MS-Exchange-CrossTenant-Network-Message-Id:
|
||||
44e9ec0b-6c5d-4cea-6417-08da31bd7000
|
||||
X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa
|
||||
X-MS-Exchange-CrossTenant-AuthSource:
|
||||
X-MS-Exchange-CrossTenant-AuthSource:
|
||||
AM6EUR05FT047.eop-eur05.prod.protection.outlook.com
|
||||
X-MS-Exchange-CrossTenant-AuthAs: Anonymous
|
||||
X-MS-Exchange-CrossTenant-FromEntityHeader: Internet
|
||||
X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg:
|
||||
X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg:
|
||||
00000000-0000-0000-0000-000000000000
|
||||
X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR02MB4563
|
||||
X-Spamd-Result: default: False [-1.75 / 13.00];
|
||||
|
@ -126,7 +126,7 @@ Received: from mail-200162.simplelogin.co (176.119.200.162) by
|
|||
BN8NAM11FT053.mail.protection.outlook.com (10.13.177.209) with Microsoft SMTP
|
||||
Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
|
||||
15.20.5227.15 via Frontend Transport; Mon, 9 May 2022 04:30:44 +0000
|
||||
X-IncomingTopHeaderMarker:
|
||||
X-IncomingTopHeaderMarker:
|
||||
OriginalChecksum:5EBD8C309CA888838EDC898C63E28E1EC00EF74772276A54C08DA83D658756F4;UpperCasedChecksum:E102374CD208D4ACB2034F1A17F76DA6345BD176395C6D4EADEC3B47BFF41ECC;SizeAsReceived:1262;Count:15
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=simplelogin.co;
|
||||
s=dkim; t=1652070640; h=From:To:Subject:Message-ID:Date;
|
||||
|
@ -135,7 +135,7 @@ DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=simplelogin.co;
|
|||
5NybKJmB6B6KL5hl5LG3KzCdaWfe3dAAhD4e2gIU80dal596dlzluyvLR1k+6rdM4JvlGq
|
||||
OVWLR42Oj4anrnOqLCUkL44ILIhLpAE=
|
||||
Date: Mon, 9 May 2022 00:30:38 -0400 (EDT)
|
||||
Message-ID:
|
||||
Message-ID:
|
||||
<10627474.1041327707.1652070638478.JavaMail.cloud@p2-mta-0301.p2.messagegears.net>
|
||||
Subject: Original Subject
|
||||
Content-Type: multipart/mixed;
|
||||
|
@ -156,13 +156,13 @@ X-MS-Exchange-Organization-ExpirationStartTime: 09 May 2022 04:30:45.1195
|
|||
X-MS-Exchange-Organization-ExpirationStartTimeReason: OriginalSubmit
|
||||
X-MS-Exchange-Organization-ExpirationInterval: 1:00:00:00.0000000
|
||||
X-MS-Exchange-Organization-ExpirationIntervalReason: OriginalSubmit
|
||||
X-MS-Exchange-Organization-Network-Message-Id:
|
||||
X-MS-Exchange-Organization-Network-Message-Id:
|
||||
ede92e41-5acb-4474-c5be-08da3174af2b
|
||||
X-EOPAttributedMessage: 0
|
||||
X-EOPTenantAttributedMessage: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa:0
|
||||
X-MS-Exchange-Organization-MessageDirectionality: Incoming
|
||||
X-MS-PublicTrafficType: Email
|
||||
X-MS-Exchange-Organization-AuthSource:
|
||||
X-MS-Exchange-Organization-AuthSource:
|
||||
BN8NAM11FT053.eop-nam11.prod.protection.outlook.com
|
||||
X-MS-Exchange-Organization-AuthAs: Anonymous
|
||||
X-MS-UserLastLogonTime: 5/9/2022 3:30:52 AM
|
||||
|
@ -177,24 +177,24 @@ X-MS-Exchange-Organization-SCL: 1
|
|||
X-Microsoft-Antispam: BCL:0;
|
||||
X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 May 2022 04:30:44.9945
|
||||
(UTC)
|
||||
X-MS-Exchange-CrossTenant-Network-Message-Id:
|
||||
X-MS-Exchange-CrossTenant-Network-Message-Id:
|
||||
ede92e41-5acb-4474-c5be-08da3174af2b
|
||||
X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa
|
||||
X-MS-Exchange-CrossTenant-AuthSource:
|
||||
X-MS-Exchange-CrossTenant-AuthSource:
|
||||
BN8NAM11FT053.eop-nam11.prod.protection.outlook.com
|
||||
X-MS-Exchange-CrossTenant-AuthAs: Anonymous
|
||||
X-MS-Exchange-CrossTenant-FromEntityHeader: Internet
|
||||
X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg:
|
||||
X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg:
|
||||
00000000-0000-0000-0000-000000000000
|
||||
X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR11MB4958
|
||||
X-MS-Exchange-Transport-EndToEndLatency: 00:00:03.3271765
|
||||
X-MS-Exchange-Processed-By-BccFoldering: 15.20.5227.023
|
||||
X-Microsoft-Antispam-Mailbox-Delivery:
|
||||
X-Microsoft-Antispam-Mailbox-Delivery:
|
||||
abwl:0;wl:0;pcwl:0;kl:0;iwl:0;ijl:0;dwl:0;dkl:0;rwl:0;ucf:0;jmr:0;ex:0;auth:1;dest:I;ENG:(5062000285)(90000117)(90005022)(91005020)(91035115)(5061607266)(5061608174)(9050020)(9100338)(2008001134)(2008000189)(2008120399)(2008019284)(2008021020)(8390246)(8377080)(8386120)(4810004)(4910013)(9910022)(9510006)(10110021)(9320005);
|
||||
X-Message-Info:
|
||||
X-Message-Info:
|
||||
5vMbyqxGkdcvoPRAk5ACFywqndfpuBMcVz6K/12RtMALmdfGi+GpgO+lXQe3PiGwHtV5wXFRStQwg29XySZZo6tOyvshTSJ1uafhX53S93r5MaqDxJrR0UNGr2VYdKiAm1jYIYQm84v/mEbSAGjjBwEgS1PHlzM72I96JadXzfV9Fmsd5pHlfoLxEqXe6hBJAAQS99CcpwPDnaVA9UZUHA==
|
||||
X-Message-Delivery: Vj0xLjE7dXM9MDtsPTA7YT0wO0Q9MTtHRD0xO1NDTD0tMQ==
|
||||
X-Microsoft-Antispam-Message-Info:
|
||||
X-Microsoft-Antispam-Message-Info:
|
||||
=?utf-8?B?VjZIQkpKR05oRUo1Vzc0YTBDUW52S0lsYkJSMGRzY0hJMnRMOWdyRGowcGpk?=
|
||||
=?utf-8?B?SUJLSDRPaStzakpJUHlaWVFnNWpBSGRsZ1Z4aEFmaXJOR1ZMUWxTTnQ1SXg1?=
|
||||
=?utf-8?B?anhFNTJ5RGU2YjRiTWhWK3FvWXBJU29YSWdqM3VvUkZpY21aaW5lSkJ5WWph?=
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
X-SimpleLogin-Client-IP: 66.163.186.21
|
||||
Received-SPF: None (mailfrom) identity=mailfrom; client-ip=66.163.186.21;
|
||||
helo=sonic326-46.consmr.mail.ne1.yahoo.com;
|
||||
envelope-from=feedback@arf.mail.yahoo.com; receiver=<UNKNOWN>
|
||||
envelope-from=feedback@arf.mail.yahoo.com; receiver=<UNKNOWN>
|
||||
Received: from sonic326-46.consmr.mail.ne1.yahoo.com
|
||||
(sonic326-46.consmr.mail.ne1.yahoo.com [66.163.186.21])
|
||||
(using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)
|
||||
|
@ -24,7 +24,7 @@ Received: from sonic.gate.mail.ne1.yahoo.com by
|
|||
Date: Sun, 8 May 2022 13:31:28 +0000 (UTC)
|
||||
From: Yahoo! Mail AntiSpam Feedback <feedback@arf.mail.yahoo.com>
|
||||
To: {{ postmaster }}
|
||||
Message-ID:
|
||||
Message-ID:
|
||||
<1486688083.18136997.1652016688605@chakraconsumer2.asd.mail.ne1.yahoo.com>
|
||||
Subject: Original subject
|
||||
MIME-Version: 1.0
|
||||
|
@ -87,7 +87,7 @@ Content-Disposition: inline
|
|||
Received: from 10.217.151.74
|
||||
by atlas316.free.mail.ne1.yahoo.com with HTTPS;
|
||||
Sun, 8 May 2022 11:12:34 +0000
|
||||
Return-Path:
|
||||
Return-Path:
|
||||
<{{ return_path }}>
|
||||
X-Originating-Ip: [176.129.238.160]
|
||||
Received-SPF: pass (domain of simplelogin.co designates 176.119.200.160 as
|
||||
|
@ -131,7 +131,7 @@ DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=simplelogin.co;
|
|||
jQ8bqMZhCsN/xVpkMqJdNJefdkj3dP4=
|
||||
MIME-Version: 1.0
|
||||
Date: Sun, 8 May 2022 04:11:42 -0700
|
||||
Message-ID:
|
||||
Message-ID:
|
||||
<CAKGh96GHg2kuwvm4biQ-PF-4-8SPZ6JyPj-=GpoYZ6njctoRtg@mail.gmail.com>
|
||||
Subject: MF
|
||||
Content-Type: multipart/alternative; boundary="0000000000006dd95f05de7e2a70"
|
||||
|
|
Loading…
Reference in a new issue