forked from NoiSek/whisper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.py
169 lines (129 loc) · 5.86 KB
/
app.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
from bottle import Bottle, TEMPLATE_PATH, static_file, request, template, run
from bottle_sqlite import SQLitePlugin
from whisper import _database
from whisper import _crypto
from whisper import _utils
from whisper import _init
import json, sys
# Extend the bottle class to initialize the DB and config
class WhisperApp(Bottle):
def __init__(self, catchall=True, autojson=True):
self.app_config = _init.init_config() # Necessary due to naming conflicts in the Bottle class
self.database = _database
self.utils = _utils
_init.init_db()
super().__init__()
app = WhisperApp()
app.install(SQLitePlugin(dbfile="whisper/db/whisper.db"))
TEMPLATE_PATH.insert(0, 'whisper/views')
# Todo: add cookies.
@app.route('/', template="index")
def index(db):
stats = app.database.get_stats(db)
if stats is None:
return dict(sent=None, opened=None)
else:
sent, opened = stats
return dict(sent=sent, opened=opened)
@app.route('/faq', template="faq")
def faq():
return dict()
# Todo: Allow the original sender to view and optionally destroy message using cookies.
@app.route('/disposable/<message_id>')
@app.route('/disposable/<message_id>/<auth>')
def view_whisper(message_id, db, auth=None):
message = app.database.get_disposable(message_id, db)
if message is None:
return template("disposable_expired")
sender, content, password = message
if password:
if auth is not None and auth == password:
app.database.delete_disposable(message_id, db)
app.database.update_stats("opened", db)
return template("disposable", sender=sender, content=content)
return template("disposable_auth", sender=sender, message_id=message_id)
app.database.delete_disposable(message_id, db)
app.database.update_stats("opened", db)
return template("disposable", sender=sender, content=content)
@app.post('/disposable/verify')
def verify_whisper(db):
query = request.forms.get('password')
message_id = request.forms.get('message_id')
message = app.database.get_disposable(message_id, db)
if message is None:
return json.JSONEncoder().encode({
"success": "false"
})
sender, content, password = message
result = "true" if password == query else "false"
return json.JSONEncoder().encode({
"success": result
})
@app.post('/send')
def send_whisper(db):
address = request.forms.get('address')
sender = request.forms.get('sender')
content = request.forms.get('content')
paranoia = request.forms.get('paranoia')
password = request.forms.get('password')
number = request.forms.get('number')
try:
sender = sender or "Anonymous"
message_id = app.utils.gen_id()
formatted_content = content
url = "http://%s/disposable/%s" % (app.app_config.get("domain"), message_id)
if int(paranoia) is 1:
password = None
url = None
app.database.update_stats("opened", db)
# Paranoia == Disposable Message
if int(paranoia) is 2:
password = None
formatted_content = ("Someone has sent you a whisper anonymously.\n"
"The contents of this message will be destroyed upon viewing: ")
# Paranoia == Two factor authentication over SMS
elif int(paranoia) is 3:
password = password or app.utils.gen_password()
number, country = app.utils.format_number(number=number)
sms_content = ("Someone has sent you a Whisper. "
"Use this code along with the URL sent to your email address to read your whisper: %s" % (password))
app.utils.send_sms(number=number, country=country, message=sms_content)
formatted_content = ("Someone has sent you a password protected whisper anonymously. "
"To open this message, use the confirmation code sent over SMS to (%s) *** %s.\n"
"The contents of this message will be destroyed upon viewing: " % (number[:3], number[6:]))
# Paranoia == Two factor authentication via password protection
elif int(paranoia) is 4:
pass
if int(paranoia) > 1:
app.database.create_disposable(unique_id=message_id, sender=sender, content=content, password=password, db=db)
html = template("email", sender=sender, content=formatted_content, url=url, domain=app.app_config.get("domain"))
response = app.utils.send_email(address=address, sender=sender, content=html, config=app.app_config)
app.database.update_stats("sent", paranoia, db)
return response
except Exception as e:
return json.JSONEncoder().encode({
"success": "false",
"response": str(e)
})
@app.route('/static/<filename:path>')
def serve_static(filename):
return static_file(filename, root='./whisper/static/')
@app.route('/test')
def test():
sender = "Gary Provost"
address = "[email protected]"
content = """“This sentence has five words. Here are five more words. Five-word sentences are fine. But several together become monotonous. Listen to what is happening. The writing is getting boring. The sound of it drones. It’s like a stuck record. The ear demands some variety.
Now listen.
I vary the sentence length, and I create music. Music. The writing sings.
It has a pleasant rhythm, a lilt, a harmony.
I use short sentences.
And I use sentences of medium length.
And sometimes, when I am certain the reader is rested, I will engage him with a sentence of considerable length, a sentence that burns with energy and builds with all the impetus of a crescendo, the roll of the drums, the crash of the cymbals–sounds that say listen to this, it is important.” """.encode('ascii', 'xmlcharrefreplace')
return template("email", sender=sender, content=content, url=None, domain=app.app_config.get("domain"))
#response = app.utils.send_email(address=address, sender=sender, content=html, config=app.app_config)
if "debug" in sys.argv:
# Run app locally for testing
app.run(host="localhost", port=8080, debug=True, reloader=True)
else:
# Run app in production
app.run(port=8080, workers=4, server='gunicorn')