-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Etherwvlf
committed
Apr 22, 2018
0 parents
commit f5a2c97
Showing
7 changed files
with
297 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Copyright 2018 Chlorine, Inc. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
Description | ||
============ | ||
|
||
Teardrop is a memory dwelling webchat running over Tor. | ||
The server creates a temporary URL which can be accessed through Tor browser. | ||
No information is stored on disk. | ||
|
||
- Runs on Tor network. | ||
- No JS, can be used with NoScript | ||
- Nothing touches storage, everything happens in memory | ||
- No configuration | ||
- No need for a client | ||
- Chats are deleted every 3 minutes | ||
- Randomized usernames - decreasing chance of username reuse | ||
- New service URL upon each server restart | ||
|
||
Requirements | ||
======= | ||
|
||
flask, stem | ||
|
||
Install | ||
======= | ||
|
||
Install Tor | ||
|
||
Activate some virtual environment and install: | ||
|
||
`apt-get install python-virtualenv` | ||
|
||
`virtualenv sandboxme` | ||
|
||
`source sandboxme/bin/activate` | ||
|
||
`pip install git+https://github.com/etherwvlf/teardrop.git` | ||
|
||
|
||
Usage | ||
===== | ||
|
||
Start Tor or Tor Browser, make Control Port open and listening on its default port. | ||
|
||
`teardrop` | ||
|
||
Share the service URL with clients to open in Tor Browser. | ||
|
||
Bundle | ||
===== | ||
|
||
Create Windows bundle: | ||
|
||
`pyinstaller -F --icon=raindrop.ico --upx-dir=../upx394w teardrop.py` | ||
|
||
Create Linux bundle: | ||
|
||
`pyinstaller -F --upx-dir=/upx394w teardrop.py` |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import os | ||
from setuptools import setup, find_packages | ||
|
||
setup( | ||
name = 'teardrop', | ||
version = '0.5.2', | ||
description = 'Teardrop', | ||
long_description = 'Teardrop - Memory Dwelling Webchat', | ||
url = '', | ||
license = 'Chlorine, Inc.', | ||
author = '', | ||
author_email = '', | ||
packages = [''], | ||
include_package_data = True, | ||
package_data = {'': ['templates/*.html']}, | ||
install_requires = ["flask", "stem"], | ||
classifiers = [ 'Development Status :: 7 - Beta', | ||
'Programming Language :: Python'], | ||
entry_points = { 'console_scripts': | ||
[ 'teardrop = teardrop:main']} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
from flask import Flask | ||
from flask import render_template | ||
from flask import request, session, url_for, redirect, abort | ||
import traceback | ||
import sys | ||
import string | ||
from stem.control import Controller | ||
from hashlib import sha224 | ||
import random | ||
import datetime | ||
from stem import SocketError | ||
import textwrap | ||
app = Flask(__name__) | ||
import logging | ||
log = logging.getLogger('werkzeug') | ||
log.setLevel(logging.ERROR) | ||
|
||
|
||
chatters = [] | ||
global chatlines | ||
chatlines = [] | ||
|
||
def id_generator(size=6, | ||
chars=string.ascii_uppercase + string.digits + | ||
string.ascii_lowercase): | ||
|
||
return ''.join(random.choice(chars) for i in range(size)) | ||
|
||
|
||
app.secret_key = id_generator(size=64) | ||
|
||
|
||
def check_older_than(chat_dic, secs_to_live = 180): | ||
now = datetime.datetime.now() | ||
timestamp = chat_dic["timestamp"] | ||
diff = now - timestamp | ||
secs = diff.total_seconds() | ||
|
||
if secs >= secs_to_live: | ||
return True | ||
|
||
return False | ||
|
||
|
||
def process_chat(chat_dic): | ||
|
||
chats = [] | ||
max_chat_len = 69 | ||
if len(chat_dic["msg"]) > max_chat_len: | ||
|
||
for message in textwrap.wrap(chat_dic["msg"], width = max_chat_len): | ||
partial_chat = {} | ||
partial_chat["msg"] = message.strip() | ||
partial_chat["timestamp"] = datetime.datetime.now() | ||
partial_chat["username"] = session["_id"] | ||
chats.append(partial_chat) | ||
|
||
else: | ||
chats = [chat_dic] | ||
|
||
return chats | ||
|
||
|
||
# Remove headers | ||
@app.after_request | ||
def remove_headers(response): | ||
response.headers["Server"] = "" | ||
response.headers["Date"] = "" | ||
return response | ||
|
||
|
||
# Empty Index page to avoid Flask fingerprinting | ||
@app.route('/', methods=["GET"]) | ||
def index(): | ||
return ('', 200) | ||
|
||
|
||
@app.route('/<string:url_addition>', methods=["GET"]) | ||
def drop(url_addition): | ||
|
||
if url_addition != app.config["path"]: | ||
return ('', 404) | ||
|
||
if "_id" not in session: | ||
session["_id"] = id_generator() | ||
chatters.append(session["_id"]) | ||
|
||
if request.method == "GET": | ||
full_path = app.config["hostname"] + "/" + app.config["path"] | ||
return render_template("drop.html", | ||
hostname=app.config["hostname"], | ||
path=app.config["path"]) | ||
|
||
|
||
@app.route('/<string:url_addition>/rooms', methods=["GET", "POST"]) | ||
def chat_messages(url_addition): | ||
|
||
global chatlines | ||
more_chats = False | ||
if url_addition != app.config["path"]: | ||
return ('', 404) | ||
|
||
to_delete = [] | ||
c = 0 | ||
for chatline_dic in chatlines: | ||
if check_older_than(chatline_dic): | ||
to_delete.append(c) | ||
|
||
c += 1 | ||
|
||
for _del in to_delete: | ||
chatlines.pop(_del) | ||
|
||
if request.method == "POST": | ||
|
||
if request.form["dropdata"].strip(): | ||
|
||
chat = {} | ||
chat["msg"] = request.form["dropdata"].strip() | ||
chat["timestamp"] = datetime.datetime.now() | ||
chat["username"] = session["_id"] | ||
chats = process_chat(chat) | ||
chatlines = chatlines + chats | ||
chatlines = chatlines[-13:] | ||
more_chats = True | ||
|
||
return redirect(app.config["path"], code=302) | ||
|
||
return render_template("rooms.html", | ||
chatlines=chatlines, num_people = len(chatters)) | ||
|
||
def main(): | ||
|
||
try: | ||
controller = Controller.from_port() | ||
except SocketError: | ||
sys.stderr.write(' * Tor proxy or Control Port not running. Start the Tor Browser or Tor daemon and ensure the ControlPort is open.\n') | ||
sys.exit(1) | ||
|
||
|
||
print(' * Connecting to tor') | ||
with controller: | ||
controller.authenticate() | ||
|
||
# Redirect port 80 to 5000(where Flask runs). | ||
print(' * Creating teardrop service...') | ||
result = controller.create_ephemeral_hidden_service({80: 5000}, await_publication = True) | ||
|
||
print(" * New teardrop service started.URL: %s.onion" % result.service_id) | ||
###result = controller.create_hidden_service(hidden_service_dir, 80, target_port = 5000) | ||
|
||
if not result: | ||
print(" * Something went wrong, shutting down") | ||
###controller.remove_hidden_service(hidden_service_dir) | ||
###shutil.rmtree(hidden_service_dir) | ||
|
||
if result.service_id: | ||
app.config["hostname"] = result.service_id | ||
app.config["path"] = id_generator(size = 64) | ||
app.config["full_path"] = app.config["hostname"] + ".onion" + "/" + app.config["path"] | ||
print(' * Press ctrl+c to quit') | ||
print(" * Service address: %s" % app.config["full_path"]) | ||
else: | ||
print(" * Unable to determine service's hostname") | ||
|
||
try: | ||
app.run(debug=False, threaded = True) | ||
finally: | ||
|
||
print(" * Shutting down service") | ||
controller.remove_ephemeral_hidden_service(result.service_id) | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<!doctype html> | ||
<title>Teardrop</title> | ||
<style> | ||
*{ | ||
padding-top:3px; | ||
font-family: Lucida Sans Typewriter,Lucida Console,monaco,Bitstream Vera Sans Mono,monospace; | ||
font-size:22px; | ||
background-color:black; | ||
color:lime; | ||
} | ||
</style> | ||
|
||
<div id="welcome" style="text-align:right;">Server: {{ hostname }}<br /> | ||
</div> | ||
|
||
<div style="overflow: auto;text-align:center;"> | ||
<iframe src="/{{path}}/rooms" name="chatframe" style="width:90vw; height:90vh;" frameBorder=0></iframe> | ||
</div> | ||
|
||
<div style="position: fixed; bottom: 5px;"> | ||
<form id="deadform" action="/{{ path }}/rooms" method="POST"> | ||
<input type="text" placeholder="Type message and press enter..." name="dropdata" style="width:90vw; height:40px;border:none;" autofocus required> | ||
<input type="submit" value="Send" style="margin-top:5px; float:right; display:none;"> | ||
</form> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<html> | ||
<meta http-equiv="refresh" content="1" > | ||
<style> | ||
*{ | ||
padding-top:3px; | ||
font-family: Lucida Sans Typewriter,Lucida Console,monaco,Bitstream Vera Sans Mono,monospace; | ||
font-size:22px; | ||
} | ||
</style> | ||
|
||
<div style="float:right;font-size:14px;color:lime;font-weight:bold;">Entities: {{ num_people }}</div> | ||
<table> | ||
{% for message_dic in chatlines %} | ||
<tr> | ||
<td name="msg" class="msg" style="color:red;"><b>{{ message_dic["username"] }}</b>: {{ message_dic["msg"] }}</td> | ||
</tr> | ||
{% endfor %} | ||
</table> | ||
|
||
</html> |