-
Notifications
You must be signed in to change notification settings - Fork 1
/
mail.py
executable file
·177 lines (146 loc) · 6.32 KB
/
mail.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/python3
import re
import time
import random
import string
import logging
import subprocess
import email.mime.text
import os
def mail(recipient, subject, text):
msg = email.mime.text.MIMEText(text, "html")
msg["From"] = "[email protected]"
msg["To"] = recipient
msg["Subject"] = subject
try:
cmd = ["/usr/sbin/sendmail", "-t", "-oi"]
subprocess.run(cmd, input=msg.as_bytes(), check=True)
except Exception as e:
logging.error("could not mail \"%s...\" to %s", subject, anonymize_email(recipient))
logging.error(str(e))
return
logging.info("mailed \"%s...\" to %s", subject[:7], anonymize_email(recipient))
def is_valid_email(email):
return re.fullmatch("[^@\s]+@[^@\s]+\.[^@\s]+", email) is not None
def anonymize_email(email):
if not is_valid_email(email):
return "INVALIDEMAIL"
index_at = email.find("@")
if index_at >= 3:
return email[:3] + "..." + email[index_at:] # e.g. [email protected] -> [email protected]
else:
return email[:index_at] + "..." + email[index_at:] # e.g. [email protected] -> [email protected]
def read_subscribers(confirmed=True):
subscribers = []
filename = "subscribers" if confirmed else "subscribers_unconfirmed"
try:
file = open(filename, "r")
for line in file:
words = line.split()
code = words[0]
email = words[1]
subscribers.append((code, email))
file.close()
except IOError: # e.g. file doesn't exist
pass # subscribers remains an empty list
return subscribers
def read_subscribers_email(confirmed=True):
emails = []
subscribers = read_subscribers(confirmed)
for subscriber in subscribers:
email = subscriber[1]
emails.append(email)
return emails
def write_subscribers(subscribers, confirmed=True):
filename = "subscribers" if confirmed else "subscribers_unconfirmed"
file = open(filename, "w+")
for subscriber in subscribers:
code = subscriber[0]
email = subscriber[1]
line = code + " " + email + "\n"
file.write(line)
file.close()
def is_subscribed(email):
return email in read_subscribers_email()
def add_subscriber(email):
code = create_confirmation_code()
subscriber = (code, email)
subscribers = read_subscribers(confirmed=False)
subscribers.append(subscriber)
if len(subscribers) >= 1000: # keep at most 1000 last subscription requests
subscribers = subscribers[len(subscribers)-1000:]
write_subscribers(subscribers, confirmed=False)
link = f"{get_site_root()}/confirm_subscription.php"
link += "?email=" + email + "&code=" + code
subject = "Bekreftelse av varsling ved måling av lysslukking"
text = ""
text += "\"" + email + "\" har anmodet om å motta varsler hver gang lysslukking på Fysikkland måles.\n"
text += "For å bekrefte abonnementet, klikk <a href=\"" + link + "\">her</a>.\n"
mail(email, subject, text)
print("En bekreftelsesepost er sendt til " + email + ".")
logging.info("received subscription request from %s", email)
def confirm_subscription(code, email):
subscribers_unconfirmed = read_subscribers(confirmed=False)
for i, subscriber in enumerate(subscribers_unconfirmed):
if email == subscriber[1] and code == subscriber[0]:
subscribers_unconfirmed.pop(i)
write_subscribers(subscribers_unconfirmed, confirmed=False)
subscribers = read_subscribers()
subscribers.append(subscriber)
write_subscribers(subscribers)
print(email + " bekreftet.")
logging.info("confirmed subscription from %s", email)
return
print(email + " ikke bekreftet.")
logging.info("failed to confirm subscription from %s", email)
def confirm_unsubscription(code, email):
subscribers = read_subscribers()
for i, subscriber in enumerate(subscribers):
if email == subscriber[1] and code == subscriber[0]:
subscribers.pop(i)
write_subscribers(subscribers)
print("Avsluttet abonnement for %s." % email)
logging.info("unsubscribed %s", email)
return
print("Kunne ikke avslutte abonnement for %s." % email)
logging.info("failed to unsubscribe from %s", email)
def notify():
subject = "Noen målte nettopp lyset på Fysikkland!"
text_common = ""
text_common += f"Navigér til <a href=\"{get_site_root(prefix=True)}\">{get_site_root(prefix=False)}</a> for å se målingen!\n"
text_common += "\n"
text_common += "Som medlem av Fysikklandlysets epostliste bidrar du til sikker arkivering av lysloggen gjennom et distribuert blockchain-inspirert sikkerhetskopieringssystem.\n"
text_common += "Du vil derfor finne en kopi av lysloggen under.\n"
text_common += "Fysikkland anmoder deg om å ta godt vare på kopien i tilfelle noe ufysikalsk inntreffer og den sentrale loggen tilintetgjøres helt eller delvis.\n"
text_common += "\n"
text_common += "Fysikkland ønsker deg en fin dag videre.\n"
text_common += "\n"
text_common += "--- START LYSLOGG SIKKERHETSKOPI ---\n"
file = open("light.dat", "r")
for line in file:
text_common += line
file.close()
text_common += "--- SLUTT LYSLOGG SIKKERHETSKOPI ---\n"
for subscriber in read_subscribers():
code = subscriber[0]
recipient = subscriber[1]
link = f"{get_site_root()}/unsubscribe.php"
link += "?email=" + recipient + "&code=" + code
text_unique = "Dersom du ikke lenger ønsker å varsles når lysslukkingen på Fysikkland registreres, kan du avslutte ditt abonnement <a href=\"%s\">her</a>." % link
text = text_common + "\n" + text_unique
text = text.replace("\n", "<br>")
mail(recipient, subject, text)
def create_confirmation_code():
random.seed(time.time())
code = ""
for i in range(0, 30):
code += random.choice(string.ascii_lowercase)
return code
def get_ntnu_username():
cwd = os.getcwd() # e.g. /web/folk/hermasl/light
return cwd.split("/")[3] # e.g. hermasl
def get_site_root(prefix=True):
if prefix:
return f"http://folk.ntnu.no/{get_ntnu_username()}/light" # e.g. https://folk.ntnu.no/hermasl/light
else:
return f"folk.ntnu.no/{get_ntnu_username()}/light" # e.g. folk.ntnu.no/hermasl/light