flask-tor 1.0.3__tar.gz → 1.1.0__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.
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flask-tor
3
- Version: 1.0.3
3
+ Version: 1.1.0
4
4
  Summary: A simple way to run Flask apps on tor from your machine.
5
5
  Home-page: https://github.com/jakbin/flask-tor
6
6
  Author: Jak Bin
7
7
  License: MIT License
8
8
  Project-URL: Bug Tracker, https://github.com/jakbin/flask-tor/issues
9
9
  Keywords: flask,tor,onion
10
- Platform: UNKNOWN
11
10
  Classifier: Development Status :: 4 - Beta
12
11
  Classifier: Programming Language :: Python :: 3.6
13
12
  Classifier: License :: OSI Approved :: MIT License
@@ -32,6 +31,7 @@ Use it only for educational purpose.
32
31
  ## Features
33
32
  - No need root permission
34
33
  - Multiple instances
34
+ - Optional persistent onion address (reuse the same .onion between runs)
35
35
 
36
36
  ## Compatability
37
37
  Python 3.6+ is required.
@@ -52,7 +52,7 @@ from flask import Flask
52
52
  from flask_tor import run_with_tor
53
53
 
54
54
  app = Flask(__name__)
55
- port = run_with_tor()
55
+ port = run_with_tor(persistent_key_file='~/.flask_tor/hidden_service_key')
56
56
 
57
57
  @app.route("/")
58
58
  def hello():
@@ -70,7 +70,11 @@ connecting_to_tor: 100% - Done
70
70
  * Serving Flask app "main"
71
71
  * Debug mode: off
72
72
  * Running on http://127.0.0.1:<port>/
73
+
74
+ If you pass a persistent_key_file path, the first run will create a key file and subsequent runs will reuse it so the onion address stays the same. Set reuse_key=False to force a new address while still updating the stored key.
73
75
  ```
74
76
 
75
- ### Credit :- [onionshare](https://github.com/onionshare/onionshare)
77
+ ## Tutorial
78
+ [Watch Here](https://youtu.be/gmssaGzRT8M)
76
79
 
80
+ ### Credit :- [onionshare](https://github.com/onionshare/onionshare)
@@ -14,6 +14,7 @@ Use it only for educational purpose.
14
14
  ## Features
15
15
  - No need root permission
16
16
  - Multiple instances
17
+ - Optional persistent onion address (reuse the same .onion between runs)
17
18
 
18
19
  ## Compatability
19
20
  Python 3.6+ is required.
@@ -34,7 +35,7 @@ from flask import Flask
34
35
  from flask_tor import run_with_tor
35
36
 
36
37
  app = Flask(__name__)
37
- port = run_with_tor()
38
+ port = run_with_tor(persistent_key_file='~/.flask_tor/hidden_service_key')
38
39
 
39
40
  @app.route("/")
40
41
  def hello():
@@ -52,6 +53,11 @@ connecting_to_tor: 100% - Done
52
53
  * Serving Flask app "main"
53
54
  * Debug mode: off
54
55
  * Running on http://127.0.0.1:<port>/
56
+
57
+ If you pass a persistent_key_file path, the first run will create a key file and subsequent runs will reuse it so the onion address stays the same. Set reuse_key=False to force a new address while still updating the stored key.
55
58
  ```
56
59
 
57
- ### Credit :- [onionshare](https://github.com/onionshare/onionshare)
60
+ ## Tutorial
61
+ [Watch Here](https://youtu.be/gmssaGzRT8M)
62
+
63
+ ### Credit :- [onionshare](https://github.com/onionshare/onionshare)
@@ -1,3 +1,3 @@
1
1
  from .flask_tor import run_with_tor
2
2
 
3
- __version__ = '1.0.3'
3
+ __version__ = '1.1.0'
@@ -1,8 +1,18 @@
1
1
  from .onion import *
2
2
  from .onionstart import OnionStart
3
- import sys, threading
3
+ import sys, threading, os
4
4
 
5
- def run_with_tor():
5
+ def run_with_tor(persistent_key_file=None, reuse_key=True):
6
+ """
7
+ Start Flask app with Tor hidden service.
8
+
9
+ Args:
10
+ persistent_key_file (str, optional): Path to a file for saving/loading the onion service private key. If provided, the same onion address will be reused across runs (unless reuse_key is False). If None, a new address is generated each run.
11
+ reuse_key (bool, optional): If True (default), reuse the key in persistent_key_file for the onion address. If False, always generate a new address and overwrite the file.
12
+
13
+ Returns:
14
+ int: The port number to use for the Flask app.
15
+ """
6
16
  # Start the Onion object
7
17
  onion = Onion()
8
18
  try:
@@ -15,7 +25,7 @@ def run_with_tor():
15
25
 
16
26
  # Start the onionshare app
17
27
  try:
18
- app_tor = OnionStart(onion)
28
+ app_tor = OnionStart(onion, persistent_key_file=persistent_key_file, reuse_key=reuse_key)
19
29
  # app_tor.set_stealth(stealth)
20
30
  app_tor.start_onion_service()
21
31
  except KeyboardInterrupt:
@@ -105,9 +105,11 @@ class Onion(object):
105
105
  is necessary for status updates to reach the GUI.
106
106
  """
107
107
  def __init__(self):
108
-
109
108
  self.stealth = False
110
109
  self.service_id = None
110
+ # Private key (eg: 'ED25519-V3:AAAA....') captured from ADD_ONION so it can
111
+ # optionally be reused to get the same onion address in future runs.
112
+ self.private_key = None
111
113
 
112
114
  self.system = platform.system()
113
115
 
@@ -342,7 +344,7 @@ class Onion(object):
342
344
  # ephemeral stealth onion services are not supported
343
345
  self.supports_stealth = False
344
346
 
345
- def start_onion_service(self, port):
347
+ def start_onion_service(self, port, existing_key=None):
346
348
  """
347
349
  Start a onion service on port 80, pointing to the given port, and
348
350
  return the onion hostname.
@@ -362,11 +364,22 @@ class Onion(object):
362
364
  basic_auth = None
363
365
 
364
366
  try:
365
- if basic_auth != None :
366
- res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=True, basic_auth=basic_auth)
367
- else :
368
- # if the stem interface is older than 1.5.0, basic_auth isn't a valid keyword arg
369
- res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=True)
367
+ if existing_key:
368
+ # Re-create an onion service using a previously saved key
369
+ try:
370
+ key_type, key_content = existing_key.split(':', 1)
371
+ except ValueError:
372
+ raise TorErrorInvalidSetting('invalid_saved_private_key')
373
+ if basic_auth is not None:
374
+ res = self.c.create_ephemeral_hidden_service({80: port}, key_type=key_type, key_content=key_content, await_publication=True, basic_auth=basic_auth)
375
+ else:
376
+ res = self.c.create_ephemeral_hidden_service({80: port}, key_type=key_type, key_content=key_content, await_publication=True)
377
+ else:
378
+ if basic_auth is not None:
379
+ res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=True, basic_auth=basic_auth)
380
+ else:
381
+ # if the stem interface is older than 1.5.0, basic_auth isn't a valid keyword arg
382
+ res = self.c.create_ephemeral_hidden_service({ 80: port }, await_publication=True)
370
383
 
371
384
  except ProtocolError:
372
385
  raise TorErrorProtocolError('error_tor_protocol_error')
@@ -374,6 +387,16 @@ class Onion(object):
374
387
  self.service_id = res.content()[0][2].split('=')[1]
375
388
  onion_host = self.service_id + '.onion'
376
389
 
390
+ # Extract and store the private key if Tor returned it (Tor omits this
391
+ # line when we supplied our own existing key).
392
+ try:
393
+ for line in res.content():
394
+ if line[2].startswith('PrivateKey='):
395
+ self.private_key = line[2].split('=',1)[1]
396
+ break
397
+ except Exception:
398
+ pass
399
+
377
400
  if self.stealth:
378
401
  auth_cookie = res.content()[2][2].split('=')[1].split(':')[1]
379
402
  self.auth_string = 'HidServAuth {} {}'.format(onion_host, auth_cookie)
@@ -0,0 +1,67 @@
1
+ import os, shutil
2
+
3
+ from . import common
4
+
5
+ class OnionStart(object):
6
+ """
7
+ OnionShare is the main application class. Pass in options and run
8
+ start_onion_service and it will do the magic.
9
+ """
10
+ def __init__(self, onion, local_only=False, stay_open=False, persistent_key_file=None, reuse_key=True):
11
+ """
12
+ Args:
13
+ onion (Onion): The Onion controller object.
14
+ local_only (bool): If True, only bind to localhost (no Tor).
15
+ stay_open (bool): Unused, for compatibility.
16
+ persistent_key_file (str, optional): Path to file for saving/loading the onion service private key. If provided, the same onion address will be reused across runs (unless reuse_key is False).
17
+ reuse_key (bool, optional): If True (default), reuse the key in persistent_key_file for the onion address. If False, always generate a new address and overwrite the file.
18
+ """
19
+ # The Onion object
20
+ self.onion = onion
21
+ self.hidserv_dir = None
22
+ self.onion_host = None
23
+ self.stealth = None
24
+ self.local_only = local_only
25
+ # Path to store/load persistent onion private key (text file containing 'ED25519-V3:...' format)
26
+ self.persistent_key_file = os.path.expanduser(persistent_key_file) if persistent_key_file else None
27
+ print(self.persistent_key_file)
28
+ self.reuse_key = reuse_key
29
+
30
+ def start_onion_service(self):
31
+ """
32
+ Start the onionshare onion service.
33
+ """
34
+
35
+ # Choose a random port
36
+ self.port = common.get_available_port(17600, 17650)
37
+
38
+ if self.local_only:
39
+ self.onion_host = '127.0.0.1:{0:d}'.format(self.port)
40
+ return
41
+
42
+ existing_key = None
43
+ if self.persistent_key_file and self.reuse_key and os.path.exists(self.persistent_key_file):
44
+ try:
45
+ with open(self.persistent_key_file, 'r') as f:
46
+ existing_key = f.read().strip() or None
47
+ except Exception:
48
+ existing_key = None
49
+
50
+ self.onion_host = self.onion.start_onion_service(self.port, existing_key=existing_key)
51
+
52
+ # Save newly generated key if we didn't reuse one
53
+ if self.persistent_key_file and (self.onion.private_key is not None):
54
+ # Only save if either no existing file or we generated a new key
55
+ if (not existing_key) or (existing_key and existing_key != self.onion.private_key):
56
+ try:
57
+ parent_dir = os.path.dirname(self.persistent_key_file)
58
+ if parent_dir:
59
+ os.makedirs(parent_dir, exist_ok=True)
60
+ with open(self.persistent_key_file, 'w') as f:
61
+ f.write(self.onion.private_key)
62
+ except Exception as e:
63
+ print(f"[flask-tor] Failed to save persistent key file '{self.persistent_key_file}': {e}")
64
+
65
+ if self.stealth:
66
+ self.auth_string = self.onion.auth_string
67
+
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flask-tor
3
- Version: 1.0.3
3
+ Version: 1.1.0
4
4
  Summary: A simple way to run Flask apps on tor from your machine.
5
5
  Home-page: https://github.com/jakbin/flask-tor
6
6
  Author: Jak Bin
7
7
  License: MIT License
8
8
  Project-URL: Bug Tracker, https://github.com/jakbin/flask-tor/issues
9
9
  Keywords: flask,tor,onion
10
- Platform: UNKNOWN
11
10
  Classifier: Development Status :: 4 - Beta
12
11
  Classifier: Programming Language :: Python :: 3.6
13
12
  Classifier: License :: OSI Approved :: MIT License
@@ -32,6 +31,7 @@ Use it only for educational purpose.
32
31
  ## Features
33
32
  - No need root permission
34
33
  - Multiple instances
34
+ - Optional persistent onion address (reuse the same .onion between runs)
35
35
 
36
36
  ## Compatability
37
37
  Python 3.6+ is required.
@@ -52,7 +52,7 @@ from flask import Flask
52
52
  from flask_tor import run_with_tor
53
53
 
54
54
  app = Flask(__name__)
55
- port = run_with_tor()
55
+ port = run_with_tor(persistent_key_file='~/.flask_tor/hidden_service_key')
56
56
 
57
57
  @app.route("/")
58
58
  def hello():
@@ -70,7 +70,11 @@ connecting_to_tor: 100% - Done
70
70
  * Serving Flask app "main"
71
71
  * Debug mode: off
72
72
  * Running on http://127.0.0.1:<port>/
73
+
74
+ If you pass a persistent_key_file path, the first run will create a key file and subsequent runs will reuse it so the onion address stays the same. Set reuse_key=False to force a new address while still updating the stored key.
73
75
  ```
74
76
 
75
- ### Credit :- [onionshare](https://github.com/onionshare/onionshare)
77
+ ## Tutorial
78
+ [Watch Here](https://youtu.be/gmssaGzRT8M)
76
79
 
80
+ ### Credit :- [onionshare](https://github.com/onionshare/onionshare)
@@ -1,36 +0,0 @@
1
- import os, shutil
2
-
3
- from . import common
4
-
5
- class OnionStart(object):
6
- """
7
- OnionShare is the main application class. Pass in options and run
8
- start_onion_service and it will do the magic.
9
- """
10
- def __init__(self, onion, local_only=False, stay_open=False):
11
-
12
- # The Onion object
13
- self.onion = onion
14
-
15
- self.hidserv_dir = None
16
- self.onion_host = None
17
- self.stealth = None
18
- self.local_only = local_only
19
-
20
- def start_onion_service(self):
21
- """
22
- Start the onionshare onion service.
23
- """
24
-
25
- # Choose a random port
26
- self.port = common.get_available_port(17600, 17650)
27
-
28
- if self.local_only:
29
- self.onion_host = '127.0.0.1:{0:d}'.format(self.port)
30
- return
31
-
32
- self.onion_host = self.onion.start_onion_service(self.port)
33
-
34
- if self.stealth:
35
- self.auth_string = self.onion.auth_string
36
-
File without changes
File without changes
File without changes
File without changes