mirror of
https://github.com/chatmail/relay.git
synced 2026-05-11 16:34:39 +00:00
Compare commits
1 Commits
dev-note
...
link2xt/se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1a9467942 |
4
.github/CODE_OF_CONDUCT.md
vendored
4
.github/CODE_OF_CONDUCT.md
vendored
@@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
Please refer to
|
|
||||||
[Delta Chat community standards and practices](https://delta.chat/en/community-standards)
|
|
||||||
which also apply for all chatmail developments.
|
|
||||||
21
LICENSE
21
LICENSE
@@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2023, chatmail and delta chat teams
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
19
README.md
19
README.md
@@ -25,56 +25,55 @@ DNS domain name (FQDN), for example `chat.example.org`.
|
|||||||
ssh root@CHATMAIL_DOMAIN
|
ssh root@CHATMAIL_DOMAIN
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Install the `cmdeploy` command in a virtualenv
|
2. Install the `cmdeploy` command in a virtualenv and activate it
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/deltachat/chatmail
|
|
||||||
cd chatmail
|
|
||||||
scripts/initenv.sh
|
scripts/initenv.sh
|
||||||
|
. venv/bin/activate
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Create chatmail configuration file `chatmail.ini`:
|
3. Create chatmail configuration file `chatmail.ini`:
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/cmdeploy init CHATMAIL_DOMAIN
|
cmdeploy init CHATMAIL_DOMAIN
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Deploy to the remote chatmail server:
|
4. Deploy to the remote chatmail server:
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/cmdeploy run
|
cmdeploy run
|
||||||
```
|
```
|
||||||
|
|
||||||
5. To output a DNS zone file from which you can transfer DNS records
|
5. To output a DNS zone file from which you can transfer DNS records
|
||||||
to your DNS provider:
|
to your DNS provider:
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/cmdeploy dns
|
cmdeploy dns
|
||||||
```
|
```
|
||||||
|
|
||||||
6. To check status of your remotely running chatmail service:
|
6. To check status of your remotely running chatmail service:
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/cmdeploy status
|
cmdeploy status
|
||||||
```
|
```
|
||||||
|
|
||||||
7. To test your chatmail service:
|
7. To test your chatmail service:
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/cmdeploy test
|
cmdeploy test
|
||||||
```
|
```
|
||||||
|
|
||||||
8. To benchmark your chatmail service:
|
8. To benchmark your chatmail service:
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/cmdeploy bench
|
cmdeploy bench
|
||||||
```
|
```
|
||||||
|
|
||||||
### Refining the web pages
|
### Refining the web pages
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
scripts/cmdeploy webdev
|
cmdeploy webdev
|
||||||
```
|
```
|
||||||
|
|
||||||
This starts a local live development cycle for chatmail Web pages:
|
This starts a local live development cycle for chatmail Web pages:
|
||||||
|
|||||||
@@ -130,15 +130,7 @@ def test_cmd(args, out):
|
|||||||
out.check_call(f"{sys.executable} -m pip install deltachat")
|
out.check_call(f"{sys.executable} -m pip install deltachat")
|
||||||
|
|
||||||
pytest_path = shutil.which("pytest")
|
pytest_path = shutil.which("pytest")
|
||||||
pytest_args = [
|
pytest_args = [pytest_path, "cmdeploy/src/", "-n4", "-rs", "-x", "-vrx", "--durations=5"]
|
||||||
pytest_path,
|
|
||||||
"cmdeploy/src/",
|
|
||||||
"-n4",
|
|
||||||
"-rs",
|
|
||||||
"-x",
|
|
||||||
"-vrx",
|
|
||||||
"--durations=5",
|
|
||||||
]
|
|
||||||
if args.slow:
|
if args.slow:
|
||||||
pytest_args.append("--slow")
|
pytest_args.append("--slow")
|
||||||
ret = out.run_ret(pytest_args)
|
ret = out.run_ret(pytest_args)
|
||||||
|
|||||||
@@ -30,31 +30,31 @@ def test_login_smtp(benchmark, smtp, gencreds):
|
|||||||
|
|
||||||
class TestDC:
|
class TestDC:
|
||||||
def test_autoconfigure(self, benchmark, cmfactory):
|
def test_autoconfigure(self, benchmark, cmfactory):
|
||||||
def dc_autoconfig_and_idle_ready():
|
def autoconfig_and_idle_ready():
|
||||||
cmfactory.get_online_accounts(1)
|
cmfactory.get_online_accounts(1)
|
||||||
|
|
||||||
benchmark(dc_autoconfig_and_idle_ready, 5)
|
benchmark(autoconfig_and_idle_ready, 5)
|
||||||
|
|
||||||
def test_ping_pong(self, benchmark, cmfactory):
|
def test_ping_pong(self, benchmark, cmfactory):
|
||||||
ac1, ac2 = cmfactory.get_online_accounts(2)
|
ac1, ac2 = cmfactory.get_online_accounts(2)
|
||||||
chat = cmfactory.get_accepted_chat(ac1, ac2)
|
chat = cmfactory.get_accepted_chat(ac1, ac2)
|
||||||
|
|
||||||
def dc_ping_pong():
|
def ping_pong():
|
||||||
chat.send_text("ping")
|
chat.send_text("ping")
|
||||||
msg = ac2.wait_next_incoming_message()
|
msg = ac2.wait_next_incoming_message()
|
||||||
msg.chat.send_text("pong")
|
msg.chat.send_text("pong")
|
||||||
ac1.wait_next_incoming_message()
|
ac1.wait_next_incoming_message()
|
||||||
|
|
||||||
benchmark(dc_ping_pong, 5)
|
benchmark(ping_pong, 5)
|
||||||
|
|
||||||
def test_send_10_receive_10(self, benchmark, cmfactory, lp):
|
def test_send_10_receive_10(self, benchmark, cmfactory, lp):
|
||||||
ac1, ac2 = cmfactory.get_online_accounts(2)
|
ac1, ac2 = cmfactory.get_online_accounts(2)
|
||||||
chat = cmfactory.get_accepted_chat(ac1, ac2)
|
chat = cmfactory.get_accepted_chat(ac1, ac2)
|
||||||
|
|
||||||
def dc_send_10_receive_10():
|
def send_10_receive_10():
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
chat.send_text(f"hello {i}")
|
chat.send_text(f"hello {i}")
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
ac2.wait_next_incoming_message()
|
ac2.wait_next_incoming_message()
|
||||||
|
|
||||||
benchmark(dc_send_10_receive_10, 5)
|
benchmark(send_10_receive_10, 5)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class TestEndToEndDeltaChat:
|
|||||||
Example input: 100M, 2.4T, 500 K
|
Example input: 100M, 2.4T, 500 K
|
||||||
"""
|
"""
|
||||||
units = {"B": 1, "K": 2**10, "M": 2**20, "G": 2**30, "T": 2**40}
|
units = {"B": 1, "K": 2**10, "M": 2**20, "G": 2**30, "T": 2**40}
|
||||||
size = re.sub(r"([KMGT])", r" \1", limit.upper())
|
size = re.sub(r'([KMGT])', r' \1', limit.upper())
|
||||||
number, unit = [string.strip() for string in size.split()]
|
number, unit = [string.strip() for string in size.split()]
|
||||||
return int(float(number) * units[unit])
|
return int(float(number) * units[unit])
|
||||||
|
|
||||||
|
|||||||
@@ -36,53 +36,6 @@ def build_webpages(src_dir, build_dir, config):
|
|||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
def timespan_to_english(timespan):
|
|
||||||
val = int(timespan[:-1])
|
|
||||||
c = timespan[-1].lower()
|
|
||||||
match c:
|
|
||||||
case "y":
|
|
||||||
return f"{val} years"
|
|
||||||
case "m":
|
|
||||||
return f"{val} months"
|
|
||||||
case "w":
|
|
||||||
return f"{val} weeks"
|
|
||||||
case "d":
|
|
||||||
return f"{val} days"
|
|
||||||
case "h":
|
|
||||||
return f"{val} hours"
|
|
||||||
case "c":
|
|
||||||
return f"{val} seconds"
|
|
||||||
case _:
|
|
||||||
raise ValueError(
|
|
||||||
c
|
|
||||||
+ " is not a valid time unit. Try [y]ears, [w]eeks, [d]ays, or [h]ours"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def int_to_english(number):
|
|
||||||
if number >= 0 and number <= 12:
|
|
||||||
a = [
|
|
||||||
"zero",
|
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three",
|
|
||||||
"four",
|
|
||||||
"five",
|
|
||||||
"six",
|
|
||||||
"seven",
|
|
||||||
"eight",
|
|
||||||
"nine",
|
|
||||||
"ten",
|
|
||||||
"eleven",
|
|
||||||
"twelve",
|
|
||||||
]
|
|
||||||
return a[number]
|
|
||||||
elif number <= 50:
|
|
||||||
return str(number)
|
|
||||||
if number > 50:
|
|
||||||
return "more"
|
|
||||||
|
|
||||||
|
|
||||||
def _build_webpages(src_dir, build_dir, config):
|
def _build_webpages(src_dir, build_dir, config):
|
||||||
mail_domain = config.mail_domain
|
mail_domain = config.mail_domain
|
||||||
assert src_dir.exists(), src_dir
|
assert src_dir.exists(), src_dir
|
||||||
@@ -95,18 +48,6 @@ def _build_webpages(src_dir, build_dir, config):
|
|||||||
for path in src_dir.iterdir():
|
for path in src_dir.iterdir():
|
||||||
if path.suffix == ".md":
|
if path.suffix == ".md":
|
||||||
render_vars, content = prepare_template(path)
|
render_vars, content = prepare_template(path)
|
||||||
render_vars["username_min_length"] = int_to_english(
|
|
||||||
config.username_min_length
|
|
||||||
)
|
|
||||||
render_vars["username_max_length"] = int_to_english(
|
|
||||||
config.username_max_length
|
|
||||||
)
|
|
||||||
render_vars["password_min_length"] = int_to_english(
|
|
||||||
config.password_min_length
|
|
||||||
)
|
|
||||||
render_vars["delete_mails_after"] = timespan_to_english(
|
|
||||||
config.delete_mails_after
|
|
||||||
)
|
|
||||||
target = build_dir.joinpath(path.stem + ".html")
|
target = build_dir.joinpath(path.stem + ".html")
|
||||||
|
|
||||||
# recursive jinja2 rendering
|
# recursive jinja2 rendering
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Wrapper for cmdelpoy to run it in activated virtualenv.
|
|
||||||
set -e
|
|
||||||
. venv/bin/activate
|
|
||||||
cmdeploy "$@"
|
|
||||||
@@ -14,6 +14,7 @@ Welcome to instant, interoperable and [privacy-preserving](privacy.html) messagi
|
|||||||
|
|
||||||
💬 **Start** chatting with any Delta Chat contacts using [QR invite codes](https://delta.chat/en/help#howtoe2ee)
|
💬 **Start** chatting with any Delta Chat contacts using [QR invite codes](https://delta.chat/en/help#howtoe2ee)
|
||||||
|
|
||||||
{% if config.mail_domain != "nine.testrun.org" %}
|
<div class="experimental">Note: this is an experimental service</div>
|
||||||
<div class="experimental">Note: this is only a temporary development chatmail service</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,21 +9,10 @@ In the Delta Chat account setup
|
|||||||
you may tap `LOG INTO YOUR E-MAIL ACCOUNT`
|
you may tap `LOG INTO YOUR E-MAIL ACCOUNT`
|
||||||
and fill the two fields like this:
|
and fill the two fields like this:
|
||||||
|
|
||||||
- `Address`: invent a word with
|
- `Address`: invent a word with *exactly* nine characters
|
||||||
{% if username_min_length == username_max_length %}
|
and append `@{{config.mail_domain}}` to it.
|
||||||
*exactly* {{ username_min_length }}
|
|
||||||
{% else %}
|
|
||||||
{{ username_min_length}}
|
|
||||||
{% if username_max_length == "more" %}
|
|
||||||
or more
|
|
||||||
{% else %}
|
|
||||||
to {{ username_max_length }}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
characters
|
|
||||||
and append `@{{config.mail_domain}}` to it.
|
|
||||||
|
|
||||||
- `Password`: invent at least {{ password_min_length }} characters.
|
- `Password`: invent at least 9 characters.
|
||||||
|
|
||||||
If the e-mail address is not yet taken, you'll get that account.
|
If the e-mail address is not yet taken, you'll get that account.
|
||||||
The first login sets your password.
|
The first login sets your password.
|
||||||
@@ -35,11 +24,11 @@ The first login sets your password.
|
|||||||
{{config.mail_domain}} but setting up contact via [QR invite codes](https://delta.chat/en/help#howtoe2ee)
|
{{config.mail_domain}} but setting up contact via [QR invite codes](https://delta.chat/en/help#howtoe2ee)
|
||||||
allows your messages to pass freely to any outside recipients.
|
allows your messages to pass freely to any outside recipients.
|
||||||
|
|
||||||
- You may send up to {{ config.max_user_send_per_minute }} messages per minute.
|
- You may send up to 60 messages per minute
|
||||||
|
|
||||||
- Seen messages are removed {{ delete_mails_after }} after arriving on the server.
|
- Seen messages are removed 40 days after arriving on the server
|
||||||
|
|
||||||
- You can store up to [{{ config.max_mailbox_size }} messages on the server](https://delta.chat/en/help#what-happens-if-i-turn-on-delete-old-messages-from-server).
|
- You can store up to [100MB messages on the server](https://delta.chat/en/help#what-happens-if-i-turn-on-delete-old-messages-from-server)
|
||||||
|
|
||||||
|
|
||||||
### Who are the operators? Which software is running?
|
### Who are the operators? Which software is running?
|
||||||
|
|||||||
@@ -1,47 +1,4 @@
|
|||||||
|
|
||||||
body {
|
|
||||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif;
|
|
||||||
line-height: 1.4;
|
|
||||||
font-size: 1.2em;
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 20px auto;
|
|
||||||
padding: 0 10px;
|
|
||||||
color: #363636;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2.2em;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
color: #000;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
margin-top: 24px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #0076d1;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
img, video {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
background: #efefef;
|
|
||||||
padding: 2.5px 5px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#menu {
|
#menu {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
{% if config.webdev %}
|
{% if config.webdev %}
|
||||||
<meta http-equiv="refresh" content="3">
|
<meta http-equiv="refresh" content="3">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
|
||||||
<title>{{ config.mail_domain }} {{ pagename }}</title>
|
<title>{{ config.mail_domain }} {{ pagename }}</title>
|
||||||
|
<link rel="stylesheet" href="./water.css">
|
||||||
<link rel="stylesheet" href="./main.css">
|
<link rel="stylesheet" href="./main.css">
|
||||||
<link rel="icon" href="/logo.svg">
|
<link rel="icon" href="/logo.svg">
|
||||||
<link rel=”mask-icon” href=”/logo.svg” color=”#000000">
|
<link rel=”mask-icon” href=”/logo.svg” color=”#000000">
|
||||||
|
|||||||
@@ -218,16 +218,97 @@ on these or possible objections.
|
|||||||
A deletion can be made
|
A deletion can be made
|
||||||
directly in the Delta Chat email messenger.
|
directly in the Delta Chat email messenger.
|
||||||
|
|
||||||
If you have any questions or complaints,
|
a) request information about your personal data processed by us
|
||||||
please feel free to contact us by email:
|
in accordance with Art. 15 GDPR.
|
||||||
{{ config.privacy_mail }}
|
In particular,
|
||||||
|
you can request information about the processing purposes,
|
||||||
|
the category of personal data,
|
||||||
|
the categories of recipients to whom your data have been or will be disclosed,
|
||||||
|
the planned storage period,
|
||||||
|
the existence of a right to rectification, erasure, restriction of processing or objection,
|
||||||
|
the existence of a right of complaint,
|
||||||
|
the origin of your data if it has not been collected by us,
|
||||||
|
as well as the existence of automated decision-making including profiling
|
||||||
|
and, if applicable,
|
||||||
|
meaningful information about its details;
|
||||||
|
|
||||||
As a rule, you can contact the supervisory authority of your usual place of residence
|
b) in accordance with Art. 16 of the GDPR,
|
||||||
|
immediately request the correction
|
||||||
|
of inaccurate or incomplete personal data stored by us;
|
||||||
|
|
||||||
|
c) pursuant to Article 17 of the GDPR,
|
||||||
|
to request the erasure of your personal data stored by us,
|
||||||
|
unless the processing is necessary
|
||||||
|
for the exercise of the right to freedom of expression and information,
|
||||||
|
for compliance with a legal obligation,
|
||||||
|
for reasons of public interest,
|
||||||
|
or for the establishment, exercise or defence of legal claims;
|
||||||
|
|
||||||
|
d) pursuant to Art. 18 GDPR,
|
||||||
|
to request the restriction of the processing of your personal data,
|
||||||
|
insofar as the accuracy of the data is disputed by you,
|
||||||
|
the processing is unlawful,
|
||||||
|
but you object to its erasure
|
||||||
|
and we no longer require the data,
|
||||||
|
but you need it for the assertion, exercise or defence of legal claims
|
||||||
|
or you have objected to the processing pursuant to Art. 21 GDPR;
|
||||||
|
|
||||||
|
e) pursuant to Art. 20 GDPR,
|
||||||
|
to receive your personal data that you have provided to us
|
||||||
|
in a structured, common and machine-readable format
|
||||||
|
or to request that it be transferred to another controller;
|
||||||
|
|
||||||
|
f) in accordance with Art. 7 (3) of the GDPR,
|
||||||
|
to revoke your consent given to us at any time.
|
||||||
|
This has the consequence that we may no longer continue the data processing
|
||||||
|
based on this consent in the future; and
|
||||||
|
|
||||||
|
g) complain to a supervisory authority
|
||||||
|
in accordance with Article 77 of the GDPR.
|
||||||
|
As a rule,
|
||||||
|
you can contact the supervisory authority of your usual place of residence
|
||||||
or workplace
|
or workplace
|
||||||
or our registered office for this purpose.
|
or our registered office for this purpose.
|
||||||
The supervisory authority responsible for our place of business
|
The supervisory authority responsible for our place of business
|
||||||
is the `{{ config.privacy_supervisor }}`.
|
is the `{{ config.privacy_supervisor }}`.
|
||||||
|
|
||||||
|
If you have any questions or complaints, please feel free to contact us by email:
|
||||||
|
{{ config.privacy_mail }}
|
||||||
|
|
||||||
|
|
||||||
|
### 5.1 Right to object
|
||||||
|
|
||||||
|
If your personal data is processed on the basis of our legitimate interests
|
||||||
|
in accordance with Art. 6 (1) lit. f GDPR,
|
||||||
|
you have the right to object to the processing of your personal data
|
||||||
|
in accordance with Art. 21 GDPR,
|
||||||
|
provided that there are grounds for this based on your particular situation
|
||||||
|
or the objection is directed against direct advertising.
|
||||||
|
In the latter case,
|
||||||
|
you have a general right of objection,
|
||||||
|
which will be implemented by us
|
||||||
|
without specifying a particular situation.
|
||||||
|
|
||||||
|
If you wish to exercise your right of objection,
|
||||||
|
simply send an e-mail to: {{ config.privacy_mail }}
|
||||||
|
|
||||||
|
### 5.2 Right to withdraw
|
||||||
|
|
||||||
|
If your personal data is processed on the basis of your consent
|
||||||
|
in accordance with Art. 6 (1) lit. a GDPR
|
||||||
|
(e.g. via the mailing list),
|
||||||
|
you can withdraw your consent at any time
|
||||||
|
and without any disadvantages.
|
||||||
|
As a result,
|
||||||
|
we may no longer continue the data processing
|
||||||
|
that was based on this consent for the future.
|
||||||
|
However,
|
||||||
|
the withdrawal of your consent
|
||||||
|
does not affect the lawfulness of the processing
|
||||||
|
carried out on the basis of the consent until the withdrawal.
|
||||||
|
|
||||||
|
If you wish to make use of your right of withdrawal,
|
||||||
|
simply send an e-mail to: {{ config.privacy_mail }}
|
||||||
|
|
||||||
## 6. Validity of this privacy policy
|
## 6. Validity of this privacy policy
|
||||||
|
|
||||||
|
|||||||
1690
www/src/water.css
Normal file
1690
www/src/water.css
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user