onionshare_cli 2.6.1__tar.gz → 2.6.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/PKG-INFO +20 -18
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/__init__.py +27 -10
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/censorship.py +17 -15
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/common.py +10 -9
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/meek.py +2 -2
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/mode_settings.py +17 -3
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/onion.py +4 -2
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/static/css/style.css +17 -6
- onionshare_cli-2.6.4/onionshare_cli/resources/static/js/chat.js +251 -0
- onionshare_cli-2.6.4/onionshare_cli/resources/static/js/jquery-3.7.1.slim.min.js +2 -0
- onionshare_cli-2.6.4/onionshare_cli/resources/static/js/receive.js +176 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/static/js/send.js +32 -18
- onionshare_cli-2.6.4/onionshare_cli/resources/static/js/socket.io.min.js +7 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/chat.html +1 -1
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/receive.html +2 -2
- onionshare_cli-2.6.4/onionshare_cli/resources/torrc_template-meek_lite_azure +2 -0
- onionshare_cli-2.6.4/onionshare_cli/resources/torrc_template-snowflake +3 -0
- onionshare_cli-2.6.4/onionshare_cli/resources/version.txt +1 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/settings.py +6 -5
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/web/chat_mode.py +70 -23
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/web/receive_mode.py +144 -89
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/web/send_base_mode.py +92 -17
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/web/share_mode.py +32 -13
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/web/web.py +11 -14
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/pyproject.toml +17 -16
- onionshare_cli-2.6.1/onionshare_cli/resources/static/js/chat.js +0 -188
- onionshare_cli-2.6.1/onionshare_cli/resources/static/js/jquery-3.5.1.min.js +0 -2
- onionshare_cli-2.6.1/onionshare_cli/resources/static/js/receive.js +0 -141
- onionshare_cli-2.6.1/onionshare_cli/resources/static/js/socket.io.js +0 -9
- onionshare_cli-2.6.1/onionshare_cli/resources/static/js/socket.io.min.js +0 -7
- onionshare_cli-2.6.1/onionshare_cli/resources/torrc_template-meek_lite_azure +0 -2
- onionshare_cli-2.6.1/onionshare_cli/resources/torrc_template-snowflake +0 -3
- onionshare_cli-2.6.1/onionshare_cli/resources/version.txt +0 -1
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/onionshare.py +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/static/img/ajax.gif +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/static/img/favicon.ico +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/static/img/logo.png +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/static/img/logo_large.png +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/static/img/web_file.png +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/static/img/web_folder.png +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/403.html +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/404.html +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/405.html +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/500.html +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/denied.html +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/listing.html +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/send.html +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/templates/thankyou.html +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/torrc_template +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/torrc_template-obfs4 +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/resources/wordlist.txt +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/web/__init__.py +0 -0
- {onionshare_cli-2.6.1 → onionshare_cli-2.6.4}/onionshare_cli/web/website_mode.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: onionshare_cli
|
|
3
|
-
Version: 2.6.
|
|
3
|
+
Version: 2.6.4
|
|
4
4
|
Summary: OnionShare lets you securely and anonymously send and receive files. It works by starting a web server, making it accessible as a Tor onion service, and generating an unguessable web address so others can download files from you, or upload files to you. It does _not_ require setting up a separate server or using a third party file-sharing service.
|
|
5
5
|
License: GPLv3+
|
|
6
6
|
Author: Micah Lee
|
|
7
7
|
Author-email: micah@micahflee.com
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
9
|
Classifier: Environment :: Web Environment
|
|
10
10
|
Classifier: Framework :: Flask
|
|
11
11
|
Classifier: Intended Audience :: End Users/Desktop
|
|
@@ -13,32 +13,34 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (G
|
|
|
13
13
|
Classifier: License :: Other/Proprietary License
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.10
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
21
|
Classifier: Topic :: Communications :: File Sharing
|
|
21
22
|
Classifier: Topic :: Security :: Cryptography
|
|
22
|
-
Requires-Dist: cffi (>=
|
|
23
|
+
Requires-Dist: cffi (>=2,<3)
|
|
23
24
|
Requires-Dist: click
|
|
24
25
|
Requires-Dist: colorama
|
|
25
26
|
Requires-Dist: cython (>=3.0.2,<4.0.0)
|
|
26
27
|
Requires-Dist: eventlet
|
|
27
|
-
Requires-Dist: flask (==
|
|
28
|
-
Requires-Dist: flask-compress (>=1.
|
|
29
|
-
Requires-Dist: flask-socketio (
|
|
30
|
-
Requires-Dist: gevent (>=
|
|
28
|
+
Requires-Dist: flask (==3.1.3)
|
|
29
|
+
Requires-Dist: flask-compress (>=1.24,<2.0)
|
|
30
|
+
Requires-Dist: flask-socketio (>=5.6,<6.0)
|
|
31
|
+
Requires-Dist: gevent (>=26.5.0,<27.0.0)
|
|
31
32
|
Requires-Dist: gevent-websocket
|
|
32
|
-
Requires-Dist: packaging (>=
|
|
33
|
+
Requires-Dist: packaging (>=24)
|
|
34
|
+
Requires-Dist: pkgconfig (>=1.6.0,<2.0.0)
|
|
33
35
|
Requires-Dist: psutil
|
|
34
|
-
Requires-Dist: pynacl
|
|
36
|
+
Requires-Dist: pynacl (>=1.6.2,<2.0.0)
|
|
35
37
|
Requires-Dist: pysocks
|
|
36
38
|
Requires-Dist: qrcode (>=7.4.2,<8.0.0)
|
|
37
|
-
Requires-Dist: requests[socks]
|
|
38
|
-
Requires-Dist: setuptools
|
|
39
|
+
Requires-Dist: requests[socks] (>=2.32.3)
|
|
40
|
+
Requires-Dist: setuptools (>=80,<81)
|
|
39
41
|
Requires-Dist: stem (==1.8.1)
|
|
40
42
|
Requires-Dist: unidecode
|
|
41
|
-
Requires-Dist: urllib3
|
|
42
|
-
Requires-Dist: waitress (>=
|
|
43
|
-
Requires-Dist: werkzeug (
|
|
44
|
-
Requires-Dist: wheel (>=0.
|
|
43
|
+
Requires-Dist: urllib3 (>=2.7,<3.0)
|
|
44
|
+
Requires-Dist: waitress (>=3.0.1,<4.0.0)
|
|
45
|
+
Requires-Dist: werkzeug (==3.1.6)
|
|
46
|
+
Requires-Dist: wheel (>=0.46.2,<0.47.0)
|
|
@@ -33,6 +33,7 @@ from .onionshare import OnionShare
|
|
|
33
33
|
from .mode_settings import ModeSettings
|
|
34
34
|
from qrcode import QRCode
|
|
35
35
|
|
|
36
|
+
|
|
36
37
|
def main(cwd=None):
|
|
37
38
|
"""
|
|
38
39
|
The main() function implements all of the logic that the command-line version of
|
|
@@ -119,6 +120,13 @@ def main(cwd=None):
|
|
|
119
120
|
default=False,
|
|
120
121
|
help="Share files: Continue sharing after files have been sent (default is to stop sharing)",
|
|
121
122
|
)
|
|
123
|
+
parser.add_argument(
|
|
124
|
+
"--log-filenames",
|
|
125
|
+
action="store_true",
|
|
126
|
+
dest="log_filenames",
|
|
127
|
+
default=False,
|
|
128
|
+
help="Log file download activity to stdout",
|
|
129
|
+
)
|
|
122
130
|
parser.add_argument(
|
|
123
131
|
"--qr",
|
|
124
132
|
action="store_true",
|
|
@@ -204,6 +212,7 @@ def main(cwd=None):
|
|
|
204
212
|
disable_files = args.disable_files
|
|
205
213
|
disable_csp = bool(args.disable_csp)
|
|
206
214
|
custom_csp = args.custom_csp
|
|
215
|
+
log_filenames = bool(args.log_filenames)
|
|
207
216
|
verbose = bool(args.verbose)
|
|
208
217
|
|
|
209
218
|
# Verbose mode?
|
|
@@ -242,6 +251,7 @@ def main(cwd=None):
|
|
|
242
251
|
mode_settings.set("persistent", "mode", mode)
|
|
243
252
|
if mode == "share":
|
|
244
253
|
mode_settings.set("share", "autostop_sharing", autostop_sharing)
|
|
254
|
+
mode_settings.set("share", "log_filenames", log_filenames)
|
|
245
255
|
if mode == "receive":
|
|
246
256
|
if data_dir:
|
|
247
257
|
mode_settings.set("receive", "data_dir", data_dir)
|
|
@@ -251,7 +261,9 @@ def main(cwd=None):
|
|
|
251
261
|
mode_settings.set("receive", "disable_files", disable_files)
|
|
252
262
|
if mode == "website":
|
|
253
263
|
if disable_csp and custom_csp:
|
|
254
|
-
print(
|
|
264
|
+
print(
|
|
265
|
+
"You cannot disable the CSP and set a custom one. Either set --disable-csp or --custom-csp but not both."
|
|
266
|
+
)
|
|
255
267
|
sys.exit()
|
|
256
268
|
if disable_csp:
|
|
257
269
|
mode_settings.set("website", "disable_csp", True)
|
|
@@ -259,6 +271,7 @@ def main(cwd=None):
|
|
|
259
271
|
if custom_csp:
|
|
260
272
|
mode_settings.set("website", "custom_csp", custom_csp)
|
|
261
273
|
mode_settings.set("website", "disable_csp", False)
|
|
274
|
+
mode_settings.set("website", "log_filenames", log_filenames)
|
|
262
275
|
else:
|
|
263
276
|
# See what the persistent mode was
|
|
264
277
|
mode = mode_settings.get("persistent", "mode")
|
|
@@ -267,19 +280,18 @@ def main(cwd=None):
|
|
|
267
280
|
if mode == "share" or mode == "website":
|
|
268
281
|
# Unless you passed in a persistent filename, in which case get the filenames from
|
|
269
282
|
# the mode settings
|
|
270
|
-
if
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
):
|
|
283
|
+
if persistent_filename and not mode_settings.just_created:
|
|
284
|
+
# The assumption is that if we didn't just create the mode settings,
|
|
285
|
+
# this persistent json file already has validated the filenames
|
|
286
|
+
# defined therein.
|
|
275
287
|
filenames = mode_settings.get(mode, "filenames")
|
|
276
|
-
|
|
277
288
|
else:
|
|
278
|
-
# Make sure filenames given
|
|
289
|
+
# Make sure filenames given. If it is somehow empty yet we had a persistent
|
|
290
|
+
# json file, something has gone wrong with that file, just remove it.
|
|
279
291
|
if len(filenames) == 0:
|
|
280
292
|
if persistent_filename:
|
|
281
293
|
mode_settings.delete()
|
|
282
|
-
|
|
294
|
+
print("No file(s) were provided")
|
|
283
295
|
parser.print_help()
|
|
284
296
|
sys.exit()
|
|
285
297
|
|
|
@@ -505,7 +517,11 @@ def main(cwd=None):
|
|
|
505
517
|
if not app.autostop_timer_thread.is_alive():
|
|
506
518
|
if mode == "share":
|
|
507
519
|
# If there were no attempts to download the share, or all downloads are done, we can stop
|
|
508
|
-
if
|
|
520
|
+
if (
|
|
521
|
+
not web.share_mode.download_in_progress
|
|
522
|
+
or web.share_mode.cur_history_id == 0
|
|
523
|
+
or web.done
|
|
524
|
+
):
|
|
509
525
|
print("Stopped because auto-stop timer ran out")
|
|
510
526
|
web.stop(app.port)
|
|
511
527
|
break
|
|
@@ -531,6 +547,7 @@ def main(cwd=None):
|
|
|
531
547
|
finally:
|
|
532
548
|
# Shutdown
|
|
533
549
|
web.cleanup()
|
|
550
|
+
t.join()
|
|
534
551
|
onion.cleanup()
|
|
535
552
|
|
|
536
553
|
|
|
@@ -238,21 +238,23 @@ class CensorshipCircumvention(object):
|
|
|
238
238
|
bridges_ok = False
|
|
239
239
|
self.settings = settings
|
|
240
240
|
|
|
241
|
-
#
|
|
242
|
-
#
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
241
|
+
# We iterate over each group of bridges returned in settings.
|
|
242
|
+
# The first set of valid bridges are the ones we use.
|
|
243
|
+
if bridge_settings.get("settings", False):
|
|
244
|
+
for returned_bridge_settings in bridge_settings["settings"]:
|
|
245
|
+
if returned_bridge_settings.get("bridges", False):
|
|
246
|
+
bridges = returned_bridge_settings["bridges"]
|
|
247
|
+
bridge_strings = bridges["bridge_strings"]
|
|
248
|
+
|
|
249
|
+
self.settings.set("bridges_type", "custom")
|
|
250
|
+
|
|
251
|
+
# Sanity check the bridges provided from the Tor API before saving
|
|
252
|
+
bridges_checked = self.common.check_bridges_valid(bridge_strings)
|
|
253
|
+
|
|
254
|
+
if bridges_checked:
|
|
255
|
+
self.settings.set("bridges_custom", "\n".join(bridges_checked))
|
|
256
|
+
bridges_ok = True
|
|
257
|
+
break
|
|
256
258
|
|
|
257
259
|
# If we got any good bridges, save them to settings and return.
|
|
258
260
|
if bridges_ok:
|
|
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
19
19
|
"""
|
|
20
20
|
import base64
|
|
21
21
|
import hashlib
|
|
22
|
+
import importlib.resources as importlib_resources
|
|
22
23
|
import os
|
|
23
24
|
import platform
|
|
24
25
|
import random
|
|
@@ -29,7 +30,6 @@ import threading
|
|
|
29
30
|
import time
|
|
30
31
|
import shutil
|
|
31
32
|
import re
|
|
32
|
-
from pkg_resources import resource_filename
|
|
33
33
|
|
|
34
34
|
import colorama
|
|
35
35
|
from colorama import Fore, Back, Style
|
|
@@ -313,9 +313,10 @@ class Common:
|
|
|
313
313
|
"""
|
|
314
314
|
Returns the absolute path of a resource
|
|
315
315
|
"""
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
ref = importlib_resources.files("onionshare_cli.resources") / filename
|
|
317
|
+
with importlib_resources.as_file(ref) as path:
|
|
318
|
+
self.log("Common", "get_resource_path", f"filename={filename}, path={str(path)}")
|
|
319
|
+
return str(path)
|
|
319
320
|
|
|
320
321
|
def get_tor_paths(self):
|
|
321
322
|
if self.platform == "Linux":
|
|
@@ -484,16 +485,16 @@ class Common:
|
|
|
484
485
|
if bridge != "":
|
|
485
486
|
# Check the syntax of the custom bridge to make sure it looks legitimate
|
|
486
487
|
ipv4_pattern = re.compile(
|
|
487
|
-
"(obfs4\s+)?(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):([0-9]+)(\s+)([A-Z0-9]+)(.+)$"
|
|
488
|
+
r"(obfs4\s+)?(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):([0-9]+)(\s+)([A-Z0-9]+)(.+)$"
|
|
488
489
|
)
|
|
489
490
|
ipv6_pattern = re.compile(
|
|
490
|
-
"(obfs4\s+)?\[(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\]:[0-9]+\s+[A-Z0-9]+(.+)$"
|
|
491
|
+
r"(obfs4\s+)?\[(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\]:[0-9]+\s+[A-Z0-9]+(.+)$"
|
|
491
492
|
)
|
|
492
493
|
meek_lite_pattern = re.compile(
|
|
493
|
-
"(meek_lite)(\s)+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+)(\s)+([0-9A-Z]+)(\s)+url=(.+)(\s)+front=(.+)"
|
|
494
|
+
r"(meek_lite)(\s)+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+)(\s)+([0-9A-Z]+)(\s)+url=(.+)(\s)+front=(.+)"
|
|
494
495
|
)
|
|
495
496
|
snowflake_pattern = re.compile(
|
|
496
|
-
"(snowflake)(\s)+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+)(\s)+([0-9A-Z]+)"
|
|
497
|
+
r"(snowflake)(\s)+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+)(\s)+([0-9A-Z]+)"
|
|
497
498
|
)
|
|
498
499
|
if (
|
|
499
500
|
ipv4_pattern.match(bridge)
|
|
@@ -613,7 +614,7 @@ class AutoStopTimer(threading.Thread):
|
|
|
613
614
|
|
|
614
615
|
self.common = common
|
|
615
616
|
|
|
616
|
-
self.
|
|
617
|
+
self.daemon = True
|
|
617
618
|
self.time = time
|
|
618
619
|
|
|
619
620
|
def run(self):
|
|
@@ -51,8 +51,8 @@ class Meek(object):
|
|
|
51
51
|
) = get_tor_paths()
|
|
52
52
|
|
|
53
53
|
self.meek_proxies = {}
|
|
54
|
-
self.meek_url = "https://
|
|
55
|
-
self.meek_front = "
|
|
54
|
+
self.meek_url = "https://1723079976.rsc.cdn77.org/"
|
|
55
|
+
self.meek_front = "www.phpmyadmin.net"
|
|
56
56
|
self.meek_env = {
|
|
57
57
|
"TOR_PT_MANAGED_TRANSPORT_VER": "1",
|
|
58
58
|
"TOR_PT_CLIENT_TRANSPORTS": "meek",
|
|
@@ -40,22 +40,36 @@ class ModeSettings:
|
|
|
40
40
|
"client_auth_priv_key": None,
|
|
41
41
|
"client_auth_pub_key": None,
|
|
42
42
|
},
|
|
43
|
-
"persistent": {
|
|
43
|
+
"persistent": {
|
|
44
|
+
"mode": None,
|
|
45
|
+
"enabled": False,
|
|
46
|
+
"autostart_on_launch": False
|
|
47
|
+
},
|
|
44
48
|
"general": {
|
|
45
49
|
"title": None,
|
|
46
50
|
"public": False,
|
|
47
51
|
"autostart_timer": False,
|
|
48
52
|
"autostop_timer": False,
|
|
49
53
|
"service_id": None,
|
|
54
|
+
"qr": False
|
|
55
|
+
},
|
|
56
|
+
"share": {
|
|
57
|
+
"autostop_sharing": True,
|
|
58
|
+
"filenames": [],
|
|
59
|
+
"log_filenames": False,
|
|
50
60
|
},
|
|
51
|
-
"share": {"autostop_sharing": True, "filenames": []},
|
|
52
61
|
"receive": {
|
|
53
62
|
"data_dir": self.build_default_receive_data_dir(),
|
|
54
63
|
"webhook_url": None,
|
|
55
64
|
"disable_text": False,
|
|
56
65
|
"disable_files": False,
|
|
57
66
|
},
|
|
58
|
-
"website": {
|
|
67
|
+
"website": {
|
|
68
|
+
"disable_csp": False,
|
|
69
|
+
"custom_csp": None,
|
|
70
|
+
"log_filenames": False,
|
|
71
|
+
"filenames": []
|
|
72
|
+
},
|
|
59
73
|
"chat": {},
|
|
60
74
|
}
|
|
61
75
|
self._settings = {}
|
|
@@ -27,13 +27,14 @@ import base64
|
|
|
27
27
|
import nacl.public
|
|
28
28
|
import os
|
|
29
29
|
import psutil
|
|
30
|
+
import re
|
|
30
31
|
import shlex
|
|
31
32
|
import subprocess
|
|
32
33
|
import tempfile
|
|
33
34
|
import time
|
|
34
35
|
import traceback
|
|
35
36
|
|
|
36
|
-
from
|
|
37
|
+
from packaging.version import Version
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
class TorErrorAutomatic(Exception):
|
|
@@ -658,7 +659,8 @@ class Onion(object):
|
|
|
658
659
|
# Does this version of Tor support next-gen ('v3') onions?
|
|
659
660
|
# Note, this is the version of Tor where this bug was fixed:
|
|
660
661
|
# https://trac.torproject.org/projects/tor/ticket/28619
|
|
661
|
-
|
|
662
|
+
cleaned_tor_version = re.sub(r"\s*\(.*\)", "", self.tor_version)
|
|
663
|
+
self.supports_v3_onions = Version(cleaned_tor_version) >= Version("0.3.5.7")
|
|
662
664
|
|
|
663
665
|
# Now that we are connected to Tor, if we are using built-in bridges,
|
|
664
666
|
# update them with the latest copy available from the Tor API
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
.clearfix:after {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
content: ".";
|
|
3
|
+
display: block;
|
|
4
|
+
clear: both;
|
|
5
|
+
visibility: hidden;
|
|
6
|
+
line-height: 0;
|
|
7
|
+
height: 0;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
body {
|
|
@@ -369,6 +369,17 @@ div#uploads .upload progress {
|
|
|
369
369
|
height: 20px;
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
+
div#uploads .upload .upload-warning {
|
|
373
|
+
color: #c97000;
|
|
374
|
+
font-size: 0.85em;
|
|
375
|
+
font-weight: bold;
|
|
376
|
+
margin-top: 4px;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
div#uploads .upload .upload-warning.hidden {
|
|
380
|
+
display: none;
|
|
381
|
+
}
|
|
382
|
+
|
|
372
383
|
ul.flashes {
|
|
373
384
|
list-style: none;
|
|
374
385
|
margin: 0;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
$(function () {
|
|
2
|
+
const chatContainerEls = document.getElementsByClassName("chat-container");
|
|
3
|
+
for (const chatContainerEl of chatContainerEls) {
|
|
4
|
+
chatContainerEl.classList.remove("no-js");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const socket = io(`${location.origin}/chat`, { transports: ["websocket"] });
|
|
8
|
+
|
|
9
|
+
// Store current username received from app context
|
|
10
|
+
/** @type {HTMLInputElement} */
|
|
11
|
+
const usernameEl = document.getElementById("username");
|
|
12
|
+
var current_username = usernameEl.value.trim();
|
|
13
|
+
|
|
14
|
+
// Triggered on any status change by any user, such as some
|
|
15
|
+
// user joined, or changed username, or left, etc.
|
|
16
|
+
socket.on("status", function (data) {
|
|
17
|
+
addMessageToPanel(data, current_username, "status");
|
|
18
|
+
console.log(data, current_username);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Triggered when message is received from a user. Even when sent
|
|
22
|
+
// by self, it get triggered after the server sends back the emit.
|
|
23
|
+
socket.on("chat_message", function (data) {
|
|
24
|
+
addMessageToPanel(data, current_username, "chat");
|
|
25
|
+
console.log(data, current_username);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Triggered when disconnected either by server stop or timeout
|
|
29
|
+
socket.on("disconnect", function (_reason, _details) {
|
|
30
|
+
addMessageToPanel(
|
|
31
|
+
{ msg: "The chat server is disconnected." },
|
|
32
|
+
current_username,
|
|
33
|
+
"status",
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
socket.on("connect_error", function (error) {
|
|
37
|
+
console.error(error);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Trigger new message on enter or click of send message button.
|
|
41
|
+
document
|
|
42
|
+
.getElementById("new-message")
|
|
43
|
+
.addEventListener("keypress", function (e) {
|
|
44
|
+
if (e.key === "Enter") {
|
|
45
|
+
emitMessage(socket);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Keep buttons disabled unless changed or not empty
|
|
50
|
+
usernameEl.addEventListener("keyup", function (event) {
|
|
51
|
+
const username = event.currentTarget.value;
|
|
52
|
+
if (username !== "" && username !== current_username) {
|
|
53
|
+
if (event.key === "Enter") {
|
|
54
|
+
this.blur();
|
|
55
|
+
current_username = updateUsername(socket) || current_username;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Show warning of losing data
|
|
61
|
+
window.addEventListener("beforeunload", function (e) {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const addMessageToPanel = function (data, current_username, messageType) {
|
|
67
|
+
const scrollDiff = getScrollDiffBefore();
|
|
68
|
+
if (messageType === "status") {
|
|
69
|
+
addStatusMessage(data.msg);
|
|
70
|
+
if (data.connected_users) {
|
|
71
|
+
addUserList(data.connected_users, current_username);
|
|
72
|
+
}
|
|
73
|
+
} else if (messageType === "chat") {
|
|
74
|
+
addChatMessage(data.username, data.msg);
|
|
75
|
+
}
|
|
76
|
+
scrollBottomMaybe(scrollDiff);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const emitMessage = function (socket) {
|
|
80
|
+
const newMessageEl = document.getElementById("new-message");
|
|
81
|
+
const newMessage = newMessageEl.value;
|
|
82
|
+
newMessageEl.value = "";
|
|
83
|
+
|
|
84
|
+
const chatEl = document.getElementById("chat");
|
|
85
|
+
// $(chatEl).scrollTop(chatEl.scrollHeight);
|
|
86
|
+
chatEl.scrollTo({ top: chatEl.scrollHeight });
|
|
87
|
+
|
|
88
|
+
socket.emit("text", { msg: newMessage });
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const updateUsername = function (socket) {
|
|
92
|
+
const username = document.getElementById("username").value;
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
!checkUsernameExists(username) &&
|
|
96
|
+
!checkUsernameTooLong(username) &&
|
|
97
|
+
!checkUsernameAscii(username)
|
|
98
|
+
) {
|
|
99
|
+
fetch(`${location.origin}/update-session-username`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: {
|
|
102
|
+
"Content-Type": "application/json",
|
|
103
|
+
},
|
|
104
|
+
body: JSON.stringify({ username: username }),
|
|
105
|
+
})
|
|
106
|
+
.then(function (response) {
|
|
107
|
+
console.log(response);
|
|
108
|
+
return response.json();
|
|
109
|
+
})
|
|
110
|
+
.then(function (response) {
|
|
111
|
+
console.log(response);
|
|
112
|
+
if (response.success && response.username == username) {
|
|
113
|
+
socket.emit("update_username", { username: username });
|
|
114
|
+
} else {
|
|
115
|
+
throw new Error("Failed to update username.");
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
.catch(function () {
|
|
119
|
+
addStatusMessage("Failed to update username.");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return username;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/************************************/
|
|
128
|
+
/********* Util Functions ***********/
|
|
129
|
+
/************************************/
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param username {string}
|
|
133
|
+
* @returns {boolean}
|
|
134
|
+
*/
|
|
135
|
+
const checkUsernameAscii = function (username) {
|
|
136
|
+
// ASCII characters have code points in the range U+0000-U+007F.
|
|
137
|
+
const usernameErrorEl = document.getElementById("username-error");
|
|
138
|
+
usernameErrorEl.textContent = "";
|
|
139
|
+
|
|
140
|
+
if (!/^[\u0000-\u007f]*$/.test(username)) {
|
|
141
|
+
usernameErrorEl.textContent = "Non-ASCII usernames are not supported.";
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return false;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @param username {string}
|
|
150
|
+
* @returns {boolean}
|
|
151
|
+
*/
|
|
152
|
+
const checkUsernameExists = function (username) {
|
|
153
|
+
const usernameErrorEl = document.getElementById("username-error");
|
|
154
|
+
usernameErrorEl.textContent = "";
|
|
155
|
+
|
|
156
|
+
const userEls = document.querySelectorAll("#user-list li");
|
|
157
|
+
const userMatches = Array.from(userEls).some(function (el) {
|
|
158
|
+
return el.textContent === username;
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (userMatches) {
|
|
162
|
+
usernameErrorEl.textContent = "User with that username exists!";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return userMatches;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* @param username {string}
|
|
170
|
+
* @returns {boolean}
|
|
171
|
+
*/
|
|
172
|
+
const checkUsernameTooLong = function (username) {
|
|
173
|
+
const usernameErrorEl = document.getElementById("username-error");
|
|
174
|
+
usernameErrorEl.textContent = "";
|
|
175
|
+
|
|
176
|
+
if (username.length > 128) {
|
|
177
|
+
usernameErrorEl.textContent = "Please choose a shorter username.";
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return false;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @returns {number}
|
|
186
|
+
*/
|
|
187
|
+
const getScrollDiffBefore = function () {
|
|
188
|
+
const chatEl = document.getElementById("chat");
|
|
189
|
+
return chatEl.scrollTop - (chatEl.scrollHeight - chatEl.offsetHeight);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @param scrollDiff {number}
|
|
194
|
+
*/
|
|
195
|
+
const scrollBottomMaybe = function (scrollDiff) {
|
|
196
|
+
// Scrolls to bottom if the user is scrolled at bottom
|
|
197
|
+
// if the user has scrolled up, it won't scroll at bottom.
|
|
198
|
+
// Note: when a user themselves send a message, it will still
|
|
199
|
+
// scroll to the bottom even if they had scrolled up before.
|
|
200
|
+
const chatEl = document.getElementById("chat");
|
|
201
|
+
if (scrollDiff > 0) {
|
|
202
|
+
// $(chatEl).scrollTop(chatEl.scrollHeight);
|
|
203
|
+
chatEl.scrollTo({ top: chatEl.scrollHeight });
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @param message {string}
|
|
209
|
+
*/
|
|
210
|
+
const addStatusMessage = function (message) {
|
|
211
|
+
const messageEl = document.createElement("p");
|
|
212
|
+
messageEl.classList.add("status");
|
|
213
|
+
messageEl.textContent = message;
|
|
214
|
+
|
|
215
|
+
document.getElementById("chat").appendChild(messageEl);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @param username {string}
|
|
220
|
+
* @param message {string}
|
|
221
|
+
*/
|
|
222
|
+
const addChatMessage = function (username, message) {
|
|
223
|
+
const messageEl = document.createElement("p");
|
|
224
|
+
messageEl.innerHTML = `<span class="username"></span><span class="message"></span>`;
|
|
225
|
+
|
|
226
|
+
messageEl.getElementsByClassName("username")[0].textContent = username;
|
|
227
|
+
messageEl.getElementsByClassName("message")[0].textContent = message;
|
|
228
|
+
|
|
229
|
+
document.getElementById("chat").appendChild(messageEl);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @param connected_users {string[]}
|
|
234
|
+
* @param current_username {string}
|
|
235
|
+
*/
|
|
236
|
+
const addUserList = function (connected_users, current_username) {
|
|
237
|
+
connected_users.sort();
|
|
238
|
+
|
|
239
|
+
const liList = connected_users
|
|
240
|
+
.filter(function (username) {
|
|
241
|
+
return username !== current_username;
|
|
242
|
+
})
|
|
243
|
+
.map(function (username) {
|
|
244
|
+
const li = document.createElement("p");
|
|
245
|
+
li.textContent = username;
|
|
246
|
+
return li;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const userListEl = document.getElementById("user-list");
|
|
250
|
+
userListEl.replaceChildren(...liList);
|
|
251
|
+
};
|