summaryrefslogtreecommitdiff
path: root/onionshare
diff options
context:
space:
mode:
authorMicah Lee <micah@micahflee.com>2020-08-19 18:56:55 -0400
committerMicah Lee <micah@micahflee.com>2020-08-19 18:56:55 -0400
commit8e1b34ce13b8134623c76274bfb494c4fb8857c7 (patch)
tree57ae825e69d16efb9a0814778cfc3f5094ec402b /onionshare
parent0b4821c905ecfefdf438e4c98e5e79592b390ced (diff)
parent992ced72f61446d41ce5e02cab83c805212968a0 (diff)
downloadonionshare-8e1b34ce13b8134623c76274bfb494c4fb8857c7.tar.gz
onionshare-8e1b34ce13b8134623c76274bfb494c4fb8857c7.zip
Merge branch 'chat' of https://github.com/SaptakS/onionshare into SaptakS-chat
Diffstat (limited to 'onionshare')
-rw-r--r--onionshare/__init__.py6
-rw-r--r--onionshare/common.py10
-rw-r--r--onionshare/mode_settings.py1
-rw-r--r--onionshare/web/chat_mode.py141
-rw-r--r--onionshare/web/web.py14
5 files changed, 171 insertions, 1 deletions
diff --git a/onionshare/__init__.py b/onionshare/__init__.py
index e82c7929..9946a700 100644
--- a/onionshare/__init__.py
+++ b/onionshare/__init__.py
@@ -87,6 +87,9 @@ def main(cwd=None):
parser.add_argument(
"--website", action="store_true", dest="website", help="Publish website"
)
+ parser.add_argument(
+ "--chat", action="store_true", dest="chat", help="Start chat server"
+ )
# Tor connection-related args
parser.add_argument(
"--local-only",
@@ -196,6 +199,7 @@ def main(cwd=None):
receive = bool(args.receive)
website = bool(args.website)
+ chat = bool(args.chat)
local_only = bool(args.local_only)
connect_timeout = int(args.connect_timeout)
config_filename = args.config
@@ -214,6 +218,8 @@ def main(cwd=None):
mode = "receive"
elif website:
mode = "website"
+ elif chat:
+ mode = "chat"
else:
mode = "share"
diff --git a/onionshare/common.py b/onionshare/common.py
index b74534ff..18e4841d 100644
--- a/onionshare/common.py
+++ b/onionshare/common.py
@@ -221,6 +221,16 @@ class Common:
r = random.SystemRandom()
return "-".join(r.choice(wordlist) for _ in range(word_count))
+ def build_username(self, word_count=2):
+ """
+ Returns a random string made of words from the wordlist, such as "deter-trig".
+ """
+ with open(self.get_resource_path("wordlist.txt")) as f:
+ wordlist = f.read().split()
+
+ r = random.SystemRandom()
+ return "-".join(r.choice(wordlist) for _ in range(word_count))
+
@staticmethod
def random_string(num_bytes, output_len=None):
"""
diff --git a/onionshare/mode_settings.py b/onionshare/mode_settings.py
index 9201721e..8216c1d8 100644
--- a/onionshare/mode_settings.py
+++ b/onionshare/mode_settings.py
@@ -49,6 +49,7 @@ class ModeSettings:
"share": {"autostop_sharing": True, "filenames": []},
"receive": {"data_dir": self.build_default_receive_data_dir()},
"website": {"disable_csp": False, "filenames": []},
+ "chat": {"room": "default"},
}
self._settings = {}
diff --git a/onionshare/web/chat_mode.py b/onionshare/web/chat_mode.py
new file mode 100644
index 00000000..d07eba81
--- /dev/null
+++ b/onionshare/web/chat_mode.py
@@ -0,0 +1,141 @@
+from flask import (
+ Request,
+ request,
+ render_template,
+ make_response,
+ jsonify,
+ redirect,
+ session,
+)
+from werkzeug.utils import secure_filename
+from flask_socketio import emit, join_room, leave_room
+
+
+class ChatModeWeb:
+ """
+ All of the web logic for chat mode
+ """
+
+ def __init__(self, common, web):
+ self.common = common
+ self.common.log("ChatModeWeb", "__init__")
+
+ self.web = web
+
+ # This tracks users in the room
+ self.connected_users = []
+
+ # This tracks the history id
+ self.cur_history_id = 0
+
+ self.define_routes()
+
+ def define_routes(self):
+ """
+ The web app routes for chatting
+ """
+
+ @self.web.app.route("/")
+ def index():
+ history_id = self.cur_history_id
+ self.cur_history_id += 1
+ session["name"] = (
+ session.get("name")
+ if session.get("name")
+ else self.common.build_username()
+ )
+ session["room"] = self.web.settings.default_settings["chat"]["room"]
+ self.web.add_request(
+ request.path, {"id": history_id, "status_code": 200},
+ )
+
+ self.web.add_request(self.web.REQUEST_LOAD, request.path)
+ r = make_response(
+ render_template(
+ "chat.html",
+ static_url_path=self.web.static_url_path,
+ username=session.get("name"),
+ )
+ )
+ return self.web.add_security_headers(r)
+
+ @self.web.app.route("/update-session-username", methods=["POST"])
+ def update_session_username():
+ history_id = self.cur_history_id
+ data = request.get_json()
+ session["name"] = data.get("username", session.get("name"))
+ self.web.add_request(
+ request.path, {"id": history_id, "status_code": 200},
+ )
+
+ self.web.add_request(self.web.REQUEST_LOAD, request.path)
+ r = make_response(
+ jsonify(
+ username=session.get("name"),
+ success=True,
+ )
+ )
+ return self.web.add_security_headers(r)
+
+ @self.web.socketio.on("joined", namespace="/chat")
+ def joined(message):
+ """Sent by clients when they enter a room.
+ A status message is broadcast to all people in the room."""
+ self.connected_users.append(session.get("name"))
+ join_room(session.get("room"))
+ emit(
+ "status",
+ {
+ "msg": "{} has joined.".format(session.get("name")),
+ "connected_users": self.connected_users,
+ "user": session.get("name"),
+ },
+ room=session.get("room"),
+ )
+
+ @self.web.socketio.on("text", namespace="/chat")
+ def text(message):
+ """Sent by a client when the user entered a new message.
+ The message is sent to all people in the room."""
+ emit(
+ "message",
+ {"msg": "{}: {}".format(session.get("name"), message["msg"])},
+ room=session.get("room"),
+ )
+
+ @self.web.socketio.on("update_username", namespace="/chat")
+ def update_username(message):
+ """Sent by a client when the user updates their username.
+ The message is sent to all people in the room."""
+ current_name = session.get("name")
+ session["name"] = message["username"]
+ self.connected_users[
+ self.connected_users.index(current_name)
+ ] = session.get("name")
+ emit(
+ "status",
+ {
+ "msg": "{} has updated their username to: {}".format(
+ current_name, session.get("name")
+ ),
+ "connected_users": self.connected_users,
+ "old_name": current_name,
+ "new_name": session.get("name"),
+ },
+ room=session.get("room"),
+ )
+
+ @self.web.socketio.on("disconnect", namespace="/chat")
+ def disconnect():
+ """Sent by clients when they disconnect from a room.
+ A status message is broadcast to all people in the room."""
+ self.connected_users.remove(session.get("name"))
+ leave_room(session.get("room"))
+ emit(
+ "status",
+ {
+ "msg": "{} has left the room.".format(session.get("name")),
+ "connected_users": self.connected_users,
+ },
+ room=session.get("room"),
+ )
diff --git a/onionshare/web/web.py b/onionshare/web/web.py
index 8582e694..3a22c789 100644
--- a/onionshare/web/web.py
+++ b/onionshare/web/web.py
@@ -20,12 +20,14 @@ from flask import (
__version__ as flask_version,
)
from flask_httpauth import HTTPBasicAuth
+from flask_socketio import SocketIO
from .. import strings
from .share_mode import ShareModeWeb
from .receive_mode import ReceiveModeWeb, ReceiveModeWSGIMiddleware, ReceiveModeRequest
from .website_mode import WebsiteModeWeb
+from .chat_mode import ChatModeWeb
# Stub out flask's show_server_banner function, to avoiding showing warnings that
# are not applicable to OnionShare
@@ -134,12 +136,17 @@ class Web:
self.share_mode = None
self.receive_mode = None
self.website_mode = None
+ self.chat_mode = None
if self.mode == "share":
self.share_mode = ShareModeWeb(self.common, self)
elif self.mode == "receive":
self.receive_mode = ReceiveModeWeb(self.common, self)
elif self.mode == "website":
self.website_mode = WebsiteModeWeb(self.common, self)
+ elif self.mode == "chat":
+ self.socketio = SocketIO()
+ self.socketio.init_app(self.app)
+ self.chat_mode = ChatModeWeb(self.common, self)
def get_mode(self):
if self.mode == "share":
@@ -148,6 +155,8 @@ class Web:
return self.receive_mode
elif self.mode == "website":
return self.website_mode
+ elif self.mode == "chat":
+ return self.chat_mode
else:
return None
@@ -366,7 +375,10 @@ class Web:
host = "127.0.0.1"
self.running = True
- self.app.run(host=host, port=port, threaded=True)
+ if self.mode == "chat":
+ self.socketio.run(self.app, host=host, port=port)
+ else:
+ self.app.run(host=host, port=port, threaded=True)
def stop(self, port):
"""