mirror of
https://github.com/onionshare/onionshare.git
synced 2025-01-13 08:19:28 -05:00
Create web UI and socket code for the chat interface
This commit is contained in:
parent
a217e54d28
commit
2c938fd777
@ -63,6 +63,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",
|
||||
@ -172,6 +175,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
|
||||
@ -190,6 +194,8 @@ def main(cwd=None):
|
||||
mode = "receive"
|
||||
elif website:
|
||||
mode = "website"
|
||||
elif chat:
|
||||
mode = "chat"
|
||||
else:
|
||||
mode = "share"
|
||||
|
||||
|
@ -215,6 +215,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):
|
||||
"""
|
||||
|
@ -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 = {}
|
||||
|
||||
|
75
onionshare/web/chat_mode.py
Normal file
75
onionshare/web/chat_mode.py
Normal file
@ -0,0 +1,75 @@
|
||||
import os
|
||||
import tempfile
|
||||
import json
|
||||
from datetime import datetime
|
||||
from flask import Request, request, render_template, make_response, flash, redirect, session
|
||||
from werkzeug.utils import secure_filename
|
||||
from flask_socketio import emit, join_room, leave_room
|
||||
|
||||
from .. import strings
|
||||
|
||||
|
||||
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
|
||||
|
||||
self.can_upload = True
|
||||
self.uploads_in_progress = []
|
||||
|
||||
# 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
|
||||
self.web.add_request(
|
||||
self.web.REQUEST_INDIVIDUAL_FILE_STARTED,
|
||||
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
|
||||
)
|
||||
)
|
||||
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."""
|
||||
session["name"] = self.common.build_username()
|
||||
session["room"] = self.web.settings.default_settings["chat"]["room"]
|
||||
join_room(session.get("room"))
|
||||
emit(
|
||||
"status",
|
||||
{"msg": session.get("name") + " has entered the room."},
|
||||
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": session.get("name") + ": " + message["msg"]},
|
||||
room=session.get("room")
|
||||
)
|
@ -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):
|
||||
"""
|
||||
|
31
share/static/js/chat.js
Normal file
31
share/static/js/chat.js
Normal file
@ -0,0 +1,31 @@
|
||||
$(function(){
|
||||
var socket;
|
||||
$(document).ready(function(){
|
||||
socket = io.connect('http://' + document.domain + ':' + location.port + '/chat');
|
||||
socket.on('connect', function() {
|
||||
socket.emit('joined', {});
|
||||
});
|
||||
socket.on('status', function(data) {
|
||||
console.log("received")
|
||||
$('#chat').append('<p><small><i>' + data.msg + '</i></small></p>');
|
||||
$('#chat').scrollTop($('#chat')[0].scrollHeight);
|
||||
});
|
||||
socket.on('message', function(data) {
|
||||
$('#chat').append('<p>' + data.msg + '</p>');
|
||||
$('#chat').scrollTop($('#chat')[0].scrollHeight);
|
||||
});
|
||||
$('#new-message').on('keypress', function(e) {
|
||||
var code = e.keyCode || e.which;
|
||||
if (code == 13) {
|
||||
emitMessage(socket);
|
||||
}
|
||||
});
|
||||
$('#send-button').on('click', emitMessage);
|
||||
});
|
||||
});
|
||||
|
||||
function emitMessage(socket) {
|
||||
text = $('#new-message').val();
|
||||
$('#new-message').val('');
|
||||
socket.emit('text', {msg: text});
|
||||
}
|
3
share/static/js/socket.io.min.js
vendored
Normal file
3
share/static/js/socket.io.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
47
share/templates/chat.html
Normal file
47
share/templates/chat.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OnionShare</title>
|
||||
<link href="{{ static_url_path }}/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<link rel="stylesheet" rel="subresource" type="text/css" href="{{ static_url_path }}/css/style.css" media="all">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header class="clearfix">
|
||||
<img class="logo" src="{{ static_url_path }}/img/logo.png" title="OnionShare">
|
||||
<h1>OnionShare</h1>
|
||||
</header>
|
||||
|
||||
<div>
|
||||
<ul id="flashes" class="flashes">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<li class="{{ category }}">{{ message }}</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="chat-container">
|
||||
<div class="chat-users">
|
||||
|
||||
</div>
|
||||
<div class="chat-wrapper">
|
||||
<p class="chat-header">Chat Messages</p>
|
||||
|
||||
<div id="chat"></div>
|
||||
|
||||
<div class="chat-form">
|
||||
<p><input type="text" id="new-message" name="new-message" placeholder="Type your message"/></p>
|
||||
<p><button type="button" id="send-button" class="button">Send Message</button></p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="{{ static_url_path }}/js/jquery-3.4.0.min.js"></script>
|
||||
<script src="{{ static_url_path }}/js/socket.io.min.js"></script>
|
||||
<script async src="{{ static_url_path }}/js/chat.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user