diff options
author | Micah Lee <micah@micahflee.com> | 2020-08-19 18:56:55 -0400 |
---|---|---|
committer | Micah Lee <micah@micahflee.com> | 2020-08-19 18:56:55 -0400 |
commit | 8e1b34ce13b8134623c76274bfb494c4fb8857c7 (patch) | |
tree | 57ae825e69d16efb9a0814778cfc3f5094ec402b /onionshare | |
parent | 0b4821c905ecfefdf438e4c98e5e79592b390ced (diff) | |
parent | 992ced72f61446d41ce5e02cab83c805212968a0 (diff) | |
download | onionshare-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__.py | 6 | ||||
-rw-r--r-- | onionshare/common.py | 10 | ||||
-rw-r--r-- | onionshare/mode_settings.py | 1 | ||||
-rw-r--r-- | onionshare/web/chat_mode.py | 141 | ||||
-rw-r--r-- | onionshare/web/web.py | 14 |
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): """ |