session-python 1.0.0__tar.gz → 1.0.2__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.
Files changed (20) hide show
  1. {session_python-1.0.0/session_python.egg-info → session_python-1.0.2}/PKG-INFO +3 -3
  2. {session_python-1.0.0 → session_python-1.0.2}/README.md +2 -2
  3. {session_python-1.0.0 → session_python-1.0.2}/pyproject.toml +4 -1
  4. session_python-1.0.2/session_python/cli.py +233 -0
  5. {session_python-1.0.0 → session_python-1.0.2/session_python.egg-info}/PKG-INFO +3 -3
  6. {session_python-1.0.0 → session_python-1.0.2}/session_python.egg-info/SOURCES.txt +2 -0
  7. session_python-1.0.2/session_python.egg-info/entry_points.txt +2 -0
  8. {session_python-1.0.0 → session_python-1.0.2}/LICENSE +0 -0
  9. {session_python-1.0.0 → session_python-1.0.2}/session_python/__init__.py +0 -0
  10. {session_python-1.0.0 → session_python-1.0.2}/session_python/client.py +0 -0
  11. {session_python-1.0.0 → session_python-1.0.2}/session_python/crypto.py +0 -0
  12. {session_python-1.0.0 → session_python-1.0.2}/session_python/mnemonic.py +0 -0
  13. {session_python-1.0.0 → session_python-1.0.2}/session_python/network.py +0 -0
  14. {session_python-1.0.0 → session_python-1.0.2}/session_python/polling.py +0 -0
  15. {session_python-1.0.0 → session_python-1.0.2}/session_python/protobuf/__init__.py +0 -0
  16. {session_python-1.0.0 → session_python-1.0.2}/session_python/protobuf/signalservice_pb2.py +0 -0
  17. {session_python-1.0.0 → session_python-1.0.2}/session_python.egg-info/dependency_links.txt +0 -0
  18. {session_python-1.0.0 → session_python-1.0.2}/session_python.egg-info/requires.txt +0 -0
  19. {session_python-1.0.0 → session_python-1.0.2}/session_python.egg-info/top_level.txt +0 -0
  20. {session_python-1.0.0 → session_python-1.0.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: session-python
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: A pure Python implementation of the Session Messenger protocol client
5
5
  Author-email: Towux <towux@users.noreply.github.com>
6
6
  Project-URL: Homepage, https://github.com/towux/session-python
@@ -51,10 +51,10 @@ This library is a 1-to-1 port of the official `@session.js` (Bun) client modules
51
51
 
52
52
  ## 📦 Installation
53
53
 
54
- To install `session-python` along with its dependencies:
54
+ To install `session-python`:
55
55
 
56
56
  ```bash
57
- pip install pynacl cryptography protobuf requests pysocks
57
+ pip install session-python
58
58
  ```
59
59
 
60
60
  ---
@@ -29,10 +29,10 @@ This library is a 1-to-1 port of the official `@session.js` (Bun) client modules
29
29
 
30
30
  ## 📦 Installation
31
31
 
32
- To install `session-python` along with its dependencies:
32
+ To install `session-python`:
33
33
 
34
34
  ```bash
35
- pip install pynacl cryptography protobuf requests pysocks
35
+ pip install session-python
36
36
  ```
37
37
 
38
38
  ---
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "session-python"
7
- version = "1.0.0"
7
+ version = "1.0.2"
8
8
  description = "A pure Python implementation of the Session Messenger protocol client"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -26,6 +26,9 @@ dependencies = [
26
26
  "pysocks>=1.7.1"
27
27
  ]
28
28
 
29
+ [project.scripts]
30
+ sscli = "session_python.cli:main"
31
+
29
32
  [project.urls]
30
33
  "Homepage" = "https://github.com/towux/session-python"
31
34
  "Bug Tracker" = "https://github.com/towux/session-python/issues"
@@ -0,0 +1,233 @@
1
+ import argparse
2
+ import time
3
+ import os
4
+ import binascii
5
+ import ctypes
6
+ import multiprocessing
7
+ import nacl.signing
8
+ from rich.console import Console
9
+ from rich.live import Live
10
+ from rich.text import Text
11
+ from .client import Session
12
+ from .mnemonic import encode as encode_mnemonic, decode as decode_mnemonic
13
+
14
+ def format_time(seconds: float) -> str:
15
+ if seconds <= 0:
16
+ return "0s"
17
+ MINUTE = 60
18
+ HOUR = 3600
19
+ DAY = 86400
20
+ MONTH = 2592000 # 30 days
21
+ YEAR = 31536000 # 365 days
22
+
23
+ if seconds < MINUTE:
24
+ return f"{seconds:.0f}s"
25
+ if seconds < HOUR:
26
+ m = int(seconds // MINUTE)
27
+ s = int(seconds % MINUTE)
28
+ return f"{m}m {s}s"
29
+ if seconds < DAY:
30
+ h = int(seconds // HOUR)
31
+ m = int((seconds % HOUR) // MINUTE)
32
+ return f"{h}h {m}m"
33
+ if seconds < MONTH:
34
+ d = int(seconds // DAY)
35
+ h = int((seconds % DAY) // HOUR)
36
+ return f"{d}d {h}h"
37
+ if seconds < YEAR:
38
+ mo = int(seconds // MONTH)
39
+ d = int((seconds % MONTH) // DAY)
40
+ return f"{mo}mo {d}d"
41
+
42
+ y = int(seconds // YEAR)
43
+ mo = int((seconds % YEAR) // MONTH)
44
+ return f"{y}y {mo}mo"
45
+
46
+ def search_worker(prefix: str, result_queue: multiprocessing.Queue, checked_counter: multiprocessing.Value, stop_event: multiprocessing.Event):
47
+ """
48
+ Worker process for brute-forcing vanity Session IDs.
49
+ """
50
+ import os
51
+ import binascii
52
+ import nacl.signing
53
+ from .mnemonic import encode as encode_mnemonic
54
+
55
+ local_checked = 0
56
+ while not stop_event.is_set():
57
+ local_checked += 1
58
+ seed_16 = os.urandom(16)
59
+
60
+ # Derive Session ID
61
+ seed_32_hex = binascii.hexlify(seed_16).decode('utf-8') + "00000000000000000000000000000000"
62
+ seed_32 = binascii.unhexlify(seed_32_hex)
63
+
64
+ signing_key = nacl.signing.SigningKey(seed_32)
65
+ x25519_pub = signing_key.verify_key.to_curve25519_public_key()
66
+ session_id = "05" + x25519_pub.encode().hex()
67
+
68
+ if session_id[2:].startswith(prefix):
69
+ mnemonic = encode_mnemonic(binascii.hexlify(seed_16).decode('utf-8'))
70
+ result_queue.put((session_id, mnemonic))
71
+ stop_event.set()
72
+ break
73
+
74
+ # Update shared counter periodically to avoid locking bottleneck
75
+ if local_checked >= 2000:
76
+ with checked_counter.get_lock():
77
+ checked_counter.value += local_checked
78
+ local_checked = 0
79
+
80
+ if local_checked > 0:
81
+ with checked_counter.get_lock():
82
+ checked_counter.value += local_checked
83
+
84
+ def main():
85
+ multiprocessing.freeze_support()
86
+
87
+ max_threads = os.cpu_count() or 1
88
+
89
+ parser = argparse.ArgumentParser(
90
+ description="Session Python CLI - Command Line interface for Session Messenger"
91
+ )
92
+ subparsers = parser.add_subparsers(dest="command", help="Sub-commands")
93
+
94
+ # 'mnemonic' group command
95
+ mnemonic_parser = subparsers.add_parser("mnemonic", help="Mnemonic and account key utilities")
96
+ mnemonic_subparsers = mnemonic_parser.add_subparsers(dest="subcommand", help="Sub-commands of mnemonic")
97
+
98
+ # 'mnemonic verify'
99
+ verify_parser = mnemonic_subparsers.add_parser("verify", help="Verify a 13-word mnemonic")
100
+ verify_parser.add_argument("words", type=str, help="The 13-word mnemonic to verify")
101
+
102
+ # 'mnemonic gen'
103
+ gen_parser = mnemonic_subparsers.add_parser("gen", help="Generate new mnemonics or derive ID from existing mnemonic")
104
+ gen_parser.add_argument("words", type=str, nargs="?", default=None, help="Optional existing 13-word mnemonic to derive ID from")
105
+ gen_parser.add_argument(
106
+ "-n",
107
+ type=int,
108
+ default=1,
109
+ help="Number of accounts to generate (1 to 100)"
110
+ )
111
+ gen_parser.add_argument(
112
+ "-p", "--prefix",
113
+ type=str,
114
+ default="",
115
+ help="Prefix the generated Session ID must start with (after 05, hex only, e.g. 'abc')"
116
+ )
117
+ gen_parser.add_argument(
118
+ "-t", "--threads",
119
+ type=int,
120
+ default=0,
121
+ help=f"Number of CPU threads to use (1 to {max_threads}, 0 for all cores, default: 0)"
122
+ )
123
+
124
+ args = parser.parse_args()
125
+ console = Console()
126
+
127
+ if args.command == "mnemonic":
128
+ if args.subcommand == "verify":
129
+ words = args.words.strip()
130
+ try:
131
+ seed_hex = decode_mnemonic(words)
132
+ # Derive Session ID
133
+ session = Session()
134
+ session.set_mnemonic(words)
135
+ session_id = session.get_session_id()
136
+ console.print("[bold green]Valid Mnemonic![/bold green]")
137
+ console.print(f"Session ID: {session_id}")
138
+ console.print(f"Hex Seed: {seed_hex}")
139
+ except ValueError as e:
140
+ console.print(f"[bold red]Invalid Mnemonic:[/bold red] {e}")
141
+
142
+ elif args.subcommand == "gen":
143
+ words = args.words.strip() if args.words else None
144
+
145
+ if words:
146
+ # Derive Session ID for provided mnemonic
147
+ try:
148
+ session = Session()
149
+ session.set_mnemonic(words)
150
+ session_id = session.get_session_id()
151
+ console.print(f"{session_id} - {words}")
152
+ except ValueError as e:
153
+ console.print(f"[bold red]Error deriving ID:[/bold red] {e}")
154
+ else:
155
+ # Generate new accounts (vanity search or instant)
156
+ count = args.n
157
+ if count < 1 or count > 100:
158
+ parser.error("The number of accounts (-n) must be between 1 and 100.")
159
+
160
+ threads_arg = args.threads
161
+ if threads_arg < 0 or threads_arg > max_threads:
162
+ parser.error(f"The number of threads (-t/--threads) must be between 0 and {max_threads} (your CPU has {max_threads} cores).")
163
+
164
+ num_workers = max_threads if threads_arg == 0 else threads_arg
165
+
166
+ prefix = args.prefix.lower() if args.prefix else ""
167
+ if prefix:
168
+ if not all(c in "0123456789abcdef" for c in prefix):
169
+ parser.error("The prefix (-p/--prefix) must contain only valid hex characters (0-9, a-f).")
170
+
171
+ for _ in range(count):
172
+ if prefix:
173
+ start_time = time.time()
174
+ total_expected = 16 ** len(prefix)
175
+
176
+ # Shared resources for multiprocessing
177
+ result_queue = multiprocessing.Queue()
178
+ checked_counter = multiprocessing.Value(ctypes.c_uint64, 0)
179
+ stop_event = multiprocessing.Event()
180
+
181
+ # Spawn workers
182
+ processes = []
183
+ for _ in range(num_workers):
184
+ p = multiprocessing.Process(
185
+ target=search_worker,
186
+ args=(prefix, result_queue, checked_counter, stop_event)
187
+ )
188
+ p.daemon = True
189
+ p.start()
190
+ processes.append(p)
191
+
192
+ with Live(Text("Initializing search...", style="yellow"), refresh_per_second=10) as live:
193
+ while not stop_event.is_set() and result_queue.empty():
194
+ time.sleep(0.1)
195
+ checked = checked_counter.value
196
+ elapsed = time.time() - start_time
197
+ speed = checked / elapsed if elapsed > 0 else 0
198
+
199
+ if checked < total_expected:
200
+ remaining_checks = total_expected - checked
201
+ remaining_seconds = remaining_checks / speed if speed > 0 else 0
202
+ eta_str = format_time(remaining_seconds)
203
+ else:
204
+ avg_seconds = total_expected / speed if speed > 0 else 0
205
+ eta_str = f"running over (avg {format_time(avg_seconds)})"
206
+
207
+ live.update(Text(
208
+ f"Searching for ID starting with '05{prefix}' ({num_workers} threads)...\n"
209
+ f"Speed: {speed:.1f} id/sec | Checked: {checked}/{total_expected} | Time: {elapsed:.1f}s | ETA: {eta_str}",
210
+ style="cyan"
211
+ ))
212
+
213
+ # Retrieve result and cleanup processes
214
+ session_id, mnemonic = result_queue.get()
215
+ for p in processes:
216
+ if p.is_alive():
217
+ p.terminate()
218
+
219
+ console.print(f"[bold green]{session_id}[/bold green] - [bold white]{mnemonic}[/bold white]")
220
+ else:
221
+ # Instant generation without prefix
222
+ mnemonic = Session.generate_mnemonic()
223
+ session = Session()
224
+ session.set_mnemonic(mnemonic)
225
+ session_id = session.get_session_id()
226
+ console.print(f"[bold green]{session_id}[/bold green] - [bold white]{mnemonic}[/bold white]")
227
+ else:
228
+ mnemonic_parser.print_help()
229
+ else:
230
+ parser.print_help()
231
+
232
+ if __name__ == "__main__":
233
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: session-python
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: A pure Python implementation of the Session Messenger protocol client
5
5
  Author-email: Towux <towux@users.noreply.github.com>
6
6
  Project-URL: Homepage, https://github.com/towux/session-python
@@ -51,10 +51,10 @@ This library is a 1-to-1 port of the official `@session.js` (Bun) client modules
51
51
 
52
52
  ## 📦 Installation
53
53
 
54
- To install `session-python` along with its dependencies:
54
+ To install `session-python`:
55
55
 
56
56
  ```bash
57
- pip install pynacl cryptography protobuf requests pysocks
57
+ pip install session-python
58
58
  ```
59
59
 
60
60
  ---
@@ -2,6 +2,7 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  session_python/__init__.py
5
+ session_python/cli.py
5
6
  session_python/client.py
6
7
  session_python/crypto.py
7
8
  session_python/mnemonic.py
@@ -10,6 +11,7 @@ session_python/polling.py
10
11
  session_python.egg-info/PKG-INFO
11
12
  session_python.egg-info/SOURCES.txt
12
13
  session_python.egg-info/dependency_links.txt
14
+ session_python.egg-info/entry_points.txt
13
15
  session_python.egg-info/requires.txt
14
16
  session_python.egg-info/top_level.txt
15
17
  session_python/protobuf/__init__.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sscli = session_python.cli:main
File without changes
File without changes