onionshare_cli 2.6.1__py3-none-any.whl

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.
Files changed (48) hide show
  1. onionshare_cli/__init__.py +538 -0
  2. onionshare_cli/censorship.py +311 -0
  3. onionshare_cli/common.py +624 -0
  4. onionshare_cli/meek.py +199 -0
  5. onionshare_cli/mode_settings.py +150 -0
  6. onionshare_cli/onion.py +964 -0
  7. onionshare_cli/onionshare.py +91 -0
  8. onionshare_cli/resources/static/css/style.css +432 -0
  9. onionshare_cli/resources/static/img/ajax.gif +0 -0
  10. onionshare_cli/resources/static/img/favicon.ico +0 -0
  11. onionshare_cli/resources/static/img/logo.png +0 -0
  12. onionshare_cli/resources/static/img/logo_large.png +0 -0
  13. onionshare_cli/resources/static/img/web_file.png +0 -0
  14. onionshare_cli/resources/static/img/web_folder.png +0 -0
  15. onionshare_cli/resources/static/js/chat.js +188 -0
  16. onionshare_cli/resources/static/js/jquery-3.5.1.min.js +2 -0
  17. onionshare_cli/resources/static/js/receive.js +141 -0
  18. onionshare_cli/resources/static/js/send.js +79 -0
  19. onionshare_cli/resources/static/js/socket.io.js +9 -0
  20. onionshare_cli/resources/static/js/socket.io.min.js +7 -0
  21. onionshare_cli/resources/templates/403.html +21 -0
  22. onionshare_cli/resources/templates/404.html +21 -0
  23. onionshare_cli/resources/templates/405.html +21 -0
  24. onionshare_cli/resources/templates/500.html +21 -0
  25. onionshare_cli/resources/templates/chat.html +47 -0
  26. onionshare_cli/resources/templates/denied.html +14 -0
  27. onionshare_cli/resources/templates/listing.html +60 -0
  28. onionshare_cli/resources/templates/receive.html +66 -0
  29. onionshare_cli/resources/templates/send.html +70 -0
  30. onionshare_cli/resources/templates/thankyou.html +27 -0
  31. onionshare_cli/resources/torrc_template +12 -0
  32. onionshare_cli/resources/torrc_template-meek_lite_azure +2 -0
  33. onionshare_cli/resources/torrc_template-obfs4 +12 -0
  34. onionshare_cli/resources/torrc_template-snowflake +3 -0
  35. onionshare_cli/resources/version.txt +1 -0
  36. onionshare_cli/resources/wordlist.txt +7776 -0
  37. onionshare_cli/settings.py +209 -0
  38. onionshare_cli/web/__init__.py +21 -0
  39. onionshare_cli/web/chat_mode.py +190 -0
  40. onionshare_cli/web/receive_mode.py +630 -0
  41. onionshare_cli/web/send_base_mode.py +360 -0
  42. onionshare_cli/web/share_mode.py +599 -0
  43. onionshare_cli/web/web.py +409 -0
  44. onionshare_cli/web/website_mode.py +122 -0
  45. onionshare_cli-2.6.1.dist-info/METADATA +44 -0
  46. onionshare_cli-2.6.1.dist-info/RECORD +48 -0
  47. onionshare_cli-2.6.1.dist-info/WHEEL +4 -0
  48. onionshare_cli-2.6.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,538 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ OnionShare | https://onionshare.org/
4
+
5
+ Copyright (C) 2014-2022 Micah Lee, et al. <micah@micahflee.com>
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU General Public License for more details.
16
+
17
+ You should have received a copy of the GNU General Public License
18
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ """
20
+
21
+ import os
22
+ import sys
23
+ import time
24
+ import argparse
25
+ import threading
26
+ from datetime import datetime
27
+ from datetime import timedelta
28
+
29
+ from .common import Common, CannotFindTor
30
+ from .web import Web
31
+ from .onion import TorErrorProtocolError, TorTooOldEphemeral, TorTooOldStealth, Onion
32
+ from .onionshare import OnionShare
33
+ from .mode_settings import ModeSettings
34
+ from qrcode import QRCode
35
+
36
+ def main(cwd=None):
37
+ """
38
+ The main() function implements all of the logic that the command-line version of
39
+ onionshare uses.
40
+ """
41
+ common = Common()
42
+ common.display_banner()
43
+
44
+ # OnionShare CLI in OSX needs to change current working directory (#132)
45
+ if common.platform == "Darwin":
46
+ if cwd:
47
+ os.chdir(cwd)
48
+
49
+ # Parse arguments
50
+ parser = argparse.ArgumentParser(
51
+ formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=28)
52
+ )
53
+ # Select modes
54
+ parser.add_argument(
55
+ "--receive", action="store_true", dest="receive", help="Receive files"
56
+ )
57
+ parser.add_argument(
58
+ "--website", action="store_true", dest="website", help="Publish website"
59
+ )
60
+ parser.add_argument(
61
+ "--chat", action="store_true", dest="chat", help="Start chat server"
62
+ )
63
+ # Tor connection-related args
64
+ parser.add_argument(
65
+ "--local-only",
66
+ action="store_true",
67
+ dest="local_only",
68
+ default=False,
69
+ help="Don't use Tor (only for development)",
70
+ )
71
+ parser.add_argument(
72
+ "--connect-timeout",
73
+ metavar="SECONDS",
74
+ dest="connect_timeout",
75
+ default=120,
76
+ help="Give up connecting to Tor after a given amount of seconds (default: 120)",
77
+ )
78
+ parser.add_argument(
79
+ "--config",
80
+ metavar="FILENAME",
81
+ default=None,
82
+ help="Filename of custom global settings",
83
+ )
84
+ # Persistent file
85
+ parser.add_argument(
86
+ "--persistent",
87
+ metavar="FILENAME",
88
+ default=None,
89
+ help="Filename of persistent session",
90
+ )
91
+ # General args
92
+ parser.add_argument("--title", metavar="TITLE", default=None, help="Set a title")
93
+ parser.add_argument(
94
+ "--public",
95
+ action="store_true",
96
+ dest="public",
97
+ default=False,
98
+ help="Don't use a private key",
99
+ )
100
+ parser.add_argument(
101
+ "--auto-start-timer",
102
+ metavar="SECONDS",
103
+ dest="autostart_timer",
104
+ default=0,
105
+ help="Start onion service at scheduled time (N seconds from now)",
106
+ )
107
+ parser.add_argument(
108
+ "--auto-stop-timer",
109
+ metavar="SECONDS",
110
+ dest="autostop_timer",
111
+ default=0,
112
+ help="Stop onion service at schedule time (N seconds from now)",
113
+ )
114
+ # Share args
115
+ parser.add_argument(
116
+ "--no-autostop-sharing",
117
+ action="store_true",
118
+ dest="no_autostop_sharing",
119
+ default=False,
120
+ help="Share files: Continue sharing after files have been sent (default is to stop sharing)",
121
+ )
122
+ parser.add_argument(
123
+ "--qr",
124
+ action="store_true",
125
+ dest="qr",
126
+ default=False,
127
+ help="Display a QR code in the terminal for share links",
128
+ )
129
+ # Receive args
130
+ parser.add_argument(
131
+ "--data-dir",
132
+ metavar="data_dir",
133
+ default=None,
134
+ help="Receive files: Save files received to this directory",
135
+ )
136
+ parser.add_argument(
137
+ "--webhook-url",
138
+ metavar="webhook_url",
139
+ default=None,
140
+ help="Receive files: URL to receive webhook notifications",
141
+ )
142
+ parser.add_argument(
143
+ "--disable-text",
144
+ action="store_true",
145
+ dest="disable_text",
146
+ help="Receive files: Disable receiving text messages",
147
+ )
148
+ parser.add_argument(
149
+ "--disable-files",
150
+ action="store_true",
151
+ dest="disable_files",
152
+ help="Receive files: Disable receiving files",
153
+ )
154
+ # Website args
155
+ parser.add_argument(
156
+ "--disable_csp",
157
+ action="store_true",
158
+ dest="disable_csp",
159
+ default=False,
160
+ help="Publish website: Disable the default Content Security Policy header (allows your website to use third-party resources)",
161
+ )
162
+ parser.add_argument(
163
+ "--custom_csp",
164
+ metavar="custom_csp",
165
+ default=None,
166
+ help="Publish website: Set a custom Content Security Policy header",
167
+ )
168
+ # Other
169
+ parser.add_argument(
170
+ "-v",
171
+ "--verbose",
172
+ action="store_true",
173
+ dest="verbose",
174
+ help="Log OnionShare errors to stdout, and web errors to disk",
175
+ )
176
+ parser.add_argument(
177
+ "filename",
178
+ metavar="filename",
179
+ nargs="*",
180
+ help="List of files or folders to share",
181
+ )
182
+ args = parser.parse_args()
183
+
184
+ filenames = args.filename
185
+ for i in range(len(filenames)):
186
+ filenames[i] = os.path.abspath(filenames[i])
187
+
188
+ receive = bool(args.receive)
189
+ website = bool(args.website)
190
+ chat = bool(args.chat)
191
+ local_only = bool(args.local_only)
192
+ connect_timeout = int(args.connect_timeout)
193
+ config_filename = args.config
194
+ persistent_filename = args.persistent
195
+ title = args.title
196
+ public = bool(args.public)
197
+ autostart_timer = int(args.autostart_timer)
198
+ autostop_timer = int(args.autostop_timer)
199
+ autostop_sharing = not bool(args.no_autostop_sharing)
200
+ print_qr = bool(args.qr)
201
+ data_dir = args.data_dir
202
+ webhook_url = args.webhook_url
203
+ disable_text = args.disable_text
204
+ disable_files = args.disable_files
205
+ disable_csp = bool(args.disable_csp)
206
+ custom_csp = args.custom_csp
207
+ verbose = bool(args.verbose)
208
+
209
+ # Verbose mode?
210
+ common.verbose = verbose
211
+
212
+ # Re-load settings, if a custom config was passed in
213
+ if config_filename:
214
+ common.load_settings(config_filename)
215
+ else:
216
+ common.load_settings()
217
+
218
+ # Mode settings
219
+ if persistent_filename:
220
+ mode_settings = ModeSettings(common, persistent_filename)
221
+ mode_settings.set("persistent", "enabled", True)
222
+ else:
223
+ mode_settings = ModeSettings(common)
224
+
225
+ if receive:
226
+ mode = "receive"
227
+ elif website:
228
+ mode = "website"
229
+ elif chat:
230
+ mode = "chat"
231
+ else:
232
+ mode = "share"
233
+
234
+ if mode_settings.just_created:
235
+ # This means the mode settings were just created, not loaded from disk
236
+ mode_settings.set("general", "title", title)
237
+ mode_settings.set("general", "public", public)
238
+ mode_settings.set("general", "autostart_timer", autostart_timer)
239
+ mode_settings.set("general", "autostop_timer", autostop_timer)
240
+ mode_settings.set("general", "qr", print_qr)
241
+ if persistent_filename:
242
+ mode_settings.set("persistent", "mode", mode)
243
+ if mode == "share":
244
+ mode_settings.set("share", "autostop_sharing", autostop_sharing)
245
+ if mode == "receive":
246
+ if data_dir:
247
+ mode_settings.set("receive", "data_dir", data_dir)
248
+ if webhook_url:
249
+ mode_settings.set("receive", "webhook_url", webhook_url)
250
+ mode_settings.set("receive", "disable_text", disable_text)
251
+ mode_settings.set("receive", "disable_files", disable_files)
252
+ if mode == "website":
253
+ if disable_csp and custom_csp:
254
+ print("You cannot disable the CSP and set a custom one. Either set --disable-csp or --custom-csp but not both.")
255
+ sys.exit()
256
+ if disable_csp:
257
+ mode_settings.set("website", "disable_csp", True)
258
+ mode_settings.set("website", "custom_csp", None)
259
+ if custom_csp:
260
+ mode_settings.set("website", "custom_csp", custom_csp)
261
+ mode_settings.set("website", "disable_csp", False)
262
+ else:
263
+ # See what the persistent mode was
264
+ mode = mode_settings.get("persistent", "mode")
265
+
266
+ # In share and website mode, you must supply a list of filenames
267
+ if mode == "share" or mode == "website":
268
+ # Unless you passed in a persistent filename, in which case get the filenames from
269
+ # the mode settings
270
+ if (
271
+ persistent_filename
272
+ and not mode_settings.just_created
273
+ and len(filenames) != 0
274
+ ):
275
+ filenames = mode_settings.get(mode, "filenames")
276
+
277
+ else:
278
+ # Make sure filenames given if not using receiver mode
279
+ if len(filenames) == 0:
280
+ if persistent_filename:
281
+ mode_settings.delete()
282
+
283
+ parser.print_help()
284
+ sys.exit()
285
+
286
+ # Validate filenames
287
+ valid = True
288
+ for filename in filenames:
289
+ if not os.path.isfile(filename) and not os.path.isdir(filename):
290
+ print(f"{filename} is not a valid file.")
291
+ valid = False
292
+ if not os.access(filename, os.R_OK):
293
+ print(f"{filename} is not a readable file.")
294
+ valid = False
295
+ if not valid:
296
+ sys.exit()
297
+
298
+ # Save the filenames in persistent file
299
+ if persistent_filename:
300
+ mode_settings.set(mode, "filenames", filenames)
301
+
302
+ # In receive mode, you must allows either text, files, or both
303
+ if mode == "receive" and disable_text and disable_files:
304
+ print("You cannot disable both text and files")
305
+ sys.exit()
306
+
307
+ # Create the Web object
308
+ web = Web(common, False, mode_settings, mode)
309
+
310
+ # Start the Onion object
311
+ try:
312
+ onion = Onion(common, use_tmp_dir=True)
313
+ except CannotFindTor:
314
+ print("You must install tor to use OnionShare from the command line")
315
+ if common.platform == "Darwin":
316
+ print("In macOS, you can do this with Homebrew (https://brew.sh):")
317
+ print(" brew install tor")
318
+ sys.exit()
319
+
320
+ try:
321
+ onion.connect(
322
+ custom_settings=False,
323
+ config=config_filename,
324
+ connect_timeout=connect_timeout,
325
+ local_only=local_only,
326
+ )
327
+ except KeyboardInterrupt:
328
+ print("")
329
+ sys.exit()
330
+ except Exception:
331
+ sys.exit()
332
+
333
+ # Start the onionshare app
334
+ try:
335
+ common.settings.load()
336
+
337
+ # Receive mode needs to know the tor proxy details for webhooks
338
+ if mode == "receive":
339
+ if local_only:
340
+ web.proxies = None
341
+ else:
342
+ (socks_address, socks_port) = onion.get_tor_socks_port()
343
+ web.proxies = {
344
+ "http": f"socks5h://{socks_address}:{socks_port}",
345
+ "https": f"socks5h://{socks_address}:{socks_port}",
346
+ }
347
+
348
+ app = OnionShare(common, onion, local_only, autostop_timer)
349
+ app.choose_port()
350
+
351
+ # Delay the startup if a startup timer was set
352
+ if autostart_timer > 0:
353
+ # Can't set a schedule that is later than the auto-stop timer
354
+ if autostop_timer > 0 and autostop_timer < autostart_timer:
355
+ print(
356
+ "The auto-stop time can't be the same or earlier than the auto-start time. Please update it to start sharing."
357
+ )
358
+ sys.exit()
359
+
360
+ app.start_onion_service(mode, mode_settings, False)
361
+ url = f"http://{app.onion_host}"
362
+ schedule = datetime.now() + timedelta(seconds=autostart_timer)
363
+ if mode == "receive":
364
+ print(
365
+ f"Files sent to you appear in this folder: {mode_settings.get('receive', 'data_dir')}"
366
+ )
367
+ print("")
368
+ print(
369
+ "Warning: Receive mode lets people upload files to your computer. Some files can potentially take "
370
+ "control of your computer if you open them. Only open things from people you trust, or if you know "
371
+ "what you are doing."
372
+ )
373
+ print("")
374
+ if not mode_settings.get("general", "public"):
375
+ print(
376
+ f"Give this address and private key to your sender, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
377
+ )
378
+ print(f"Private key: {app.auth_string}")
379
+ else:
380
+ print(
381
+ f"Give this address to your sender, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
382
+ )
383
+ else:
384
+ if not mode_settings.get("general", "public"):
385
+ print(
386
+ f"Give this address and private key to your recipient, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
387
+ )
388
+ print(f"Private key: {app.auth_string}")
389
+ else:
390
+ print(
391
+ f"Give this address to your recipient, and tell them it won't be accessible until: {schedule.strftime('%I:%M:%S%p, %b %d, %y')}"
392
+ )
393
+ print(url)
394
+ if mode_settings.get("general", "qr"):
395
+ qr = QRCode()
396
+ qr.add_data(url)
397
+ print("Onion address as QR code:")
398
+ qr.print_ascii()
399
+ if not mode_settings.get("general", "public"):
400
+ qr.clear()
401
+ qr.add_data(app.auth_string)
402
+ print("Private key as QR code:")
403
+ qr.print_ascii()
404
+ print("")
405
+ print("Waiting for the scheduled time before starting...")
406
+ app.onion.cleanup(False)
407
+ time.sleep(autostart_timer)
408
+ app.start_onion_service(mode, mode_settings)
409
+ else:
410
+ app.start_onion_service(mode, mode_settings)
411
+ except KeyboardInterrupt:
412
+ print("")
413
+ sys.exit()
414
+ except (TorTooOldEphemeral, TorTooOldStealth, TorErrorProtocolError) as e:
415
+ print("")
416
+ sys.exit()
417
+
418
+ if mode == "website":
419
+ # Prepare files to share
420
+ try:
421
+ web.website_mode.set_file_info(filenames)
422
+ except OSError as e:
423
+ print(e.strerror)
424
+ sys.exit(1)
425
+
426
+ if mode == "share":
427
+ # Prepare files to share
428
+ print("Compressing files.")
429
+ try:
430
+ web.share_mode.set_file_info(filenames)
431
+ except OSError as e:
432
+ print(e.strerror)
433
+ sys.exit(1)
434
+
435
+ # Warn about sending large files over Tor
436
+ if web.share_mode.download_filesize >= 157_286_400: # 150mb
437
+ print("")
438
+ print("Warning: Sending a large share could take hours")
439
+ print("")
440
+
441
+ # Start OnionShare http service in new thread
442
+ t = threading.Thread(target=web.start, args=(app.port,))
443
+ t.daemon = True
444
+ t.start()
445
+
446
+ try: # Trap Ctrl-C
447
+ time.sleep(0.2)
448
+
449
+ # start auto-stop timer thread
450
+ if app.autostop_timer > 0:
451
+ app.autostop_timer_thread.start()
452
+
453
+ # Build the URL
454
+ url = f"http://{app.onion_host}"
455
+
456
+ print("")
457
+ if autostart_timer > 0:
458
+ print("Server started")
459
+ else:
460
+ if mode == "receive":
461
+ print(
462
+ f"Files sent to you appear in this folder: {mode_settings.get('receive', 'data_dir')}"
463
+ )
464
+ print("")
465
+ print(
466
+ "Warning: Receive mode lets people upload files to your computer. Some files can potentially take "
467
+ "control of your computer if you open them. Only open things from people you trust, or if you know "
468
+ "what you are doing."
469
+ )
470
+ print("")
471
+
472
+ if mode_settings.get("general", "public"):
473
+ print("Give this address to the sender:")
474
+ print(url)
475
+ else:
476
+ print("Give this address and private key to the sender:")
477
+ print(url)
478
+ print(f"Private key: {app.auth_string}")
479
+ else:
480
+ if mode_settings.get("general", "public"):
481
+ print("Give this address to the recipient:")
482
+ print(url)
483
+ else:
484
+ print("Give this address and private key to the recipient:")
485
+ print(url)
486
+ print(f"Private key: {app.auth_string}")
487
+ if mode_settings.get("general", "qr"):
488
+ qr = QRCode()
489
+ qr.add_data(url)
490
+ print("Onion address as QR code:")
491
+ qr.print_ascii()
492
+ if not mode_settings.get("general", "public"):
493
+ qr.clear()
494
+ qr.add_data(app.auth_string)
495
+ print("Private key as QR code:")
496
+ qr.print_ascii()
497
+
498
+ print("")
499
+ print("Press Ctrl+C to stop the server")
500
+
501
+ # Wait for app to close
502
+ while t.is_alive():
503
+ if app.autostop_timer > 0:
504
+ # if the auto-stop timer was set and has run out, stop the server
505
+ if not app.autostop_timer_thread.is_alive():
506
+ if mode == "share":
507
+ # If there were no attempts to download the share, or all downloads are done, we can stop
508
+ if web.share_mode.cur_history_id == 0 or web.done:
509
+ print("Stopped because auto-stop timer ran out")
510
+ web.stop(app.port)
511
+ break
512
+ elif mode == "receive":
513
+ if (
514
+ web.receive_mode.cur_history_id == 0
515
+ or not web.receive_mode.uploads_in_progress
516
+ ):
517
+ print("Stopped because auto-stop timer ran out")
518
+ web.stop(app.port)
519
+ break
520
+ web.receive_mode.can_upload = False
521
+ else:
522
+ # website or chat mode
523
+ print("Stopped because auto-stop timer ran out")
524
+ web.stop(app.port)
525
+ break
526
+ # Allow KeyboardInterrupt exception to be handled with threads
527
+ # https://stackoverflow.com/questions/3788208/python-threading-ignores-keyboardinterrupt-exception
528
+ time.sleep(0.2)
529
+ except KeyboardInterrupt:
530
+ web.stop(app.port)
531
+ finally:
532
+ # Shutdown
533
+ web.cleanup()
534
+ onion.cleanup()
535
+
536
+
537
+ if __name__ == "__main__":
538
+ main()