voidnote 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.
@@ -0,0 +1,26 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Claude
5
+ .claude/
6
+ # Build output
7
+ dist/
8
+
9
+ # Astro
10
+ .astro/
11
+
12
+ # Wrangler
13
+ .wrangler/
14
+
15
+ # Environment
16
+ .env
17
+ .env.*
18
+ .dev.vars
19
+
20
+ # OS
21
+ .DS_Store
22
+
23
+ # IDE
24
+ .vscode/
25
+ .idea/
26
+ node_modules
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: voidnote
3
+ Version: 0.1.0
4
+ Summary: Official SDK for VoidNote — zero-knowledge self-destructing notes
5
+ Project-URL: Homepage, https://voidnote.net
6
+ Project-URL: Repository, https://github.com/quantum-encoding/voidnote-python
7
+ Project-URL: Documentation, https://voidnote.net/docs
8
+ License-Expression: MIT
9
+ Keywords: encryption,one-time,secrets,voidnote,zero-knowledge
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Security :: Cryptography
15
+ Requires-Python: >=3.9
16
+ Requires-Dist: cryptography>=41.0.0
17
+ Provides-Extra: dev
18
+ Requires-Dist: mypy; extra == 'dev'
19
+ Requires-Dist: pytest; extra == 'dev'
20
+ Description-Content-Type: text/markdown
21
+
22
+ # voidnote
23
+
24
+ Official Python SDK for [VoidNote](https://voidnote.net) — zero-knowledge self-destructing notes.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pip install voidnote
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Read a note
35
+
36
+ ```python
37
+ import voidnote
38
+
39
+ result = voidnote.read("https://voidnote.net/note/abc123...")
40
+ print(result.content) # decrypted content
41
+ print(result.destroyed) # True if view limit was reached
42
+ ```
43
+
44
+ ### Create a note (requires API key)
45
+
46
+ ```python
47
+ import voidnote
48
+
49
+ result = voidnote.create(
50
+ "my secret value",
51
+ api_key="vn_...",
52
+ max_views=1,
53
+ title="Deploy key",
54
+ )
55
+ print(result.url) # share this link
56
+ ```
57
+
58
+ ## Requirements
59
+
60
+ - Python 3.9+
61
+ - `cryptography >= 41.0.0`
62
+
63
+ ## Links
64
+
65
+ - [voidnote.net](https://voidnote.net)
66
+ - [How it works](https://voidnote.net/how-it-works)
67
+ - [GitHub](https://github.com/quantum-encoding/voidnote-python)
@@ -0,0 +1,46 @@
1
+ # voidnote
2
+
3
+ Official Python SDK for [VoidNote](https://voidnote.net) — zero-knowledge self-destructing notes.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install voidnote
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Read a note
14
+
15
+ ```python
16
+ import voidnote
17
+
18
+ result = voidnote.read("https://voidnote.net/note/abc123...")
19
+ print(result.content) # decrypted content
20
+ print(result.destroyed) # True if view limit was reached
21
+ ```
22
+
23
+ ### Create a note (requires API key)
24
+
25
+ ```python
26
+ import voidnote
27
+
28
+ result = voidnote.create(
29
+ "my secret value",
30
+ api_key="vn_...",
31
+ max_views=1,
32
+ title="Deploy key",
33
+ )
34
+ print(result.url) # share this link
35
+ ```
36
+
37
+ ## Requirements
38
+
39
+ - Python 3.9+
40
+ - `cryptography >= 41.0.0`
41
+
42
+ ## Links
43
+
44
+ - [voidnote.net](https://voidnote.net)
45
+ - [How it works](https://voidnote.net/how-it-works)
46
+ - [GitHub](https://github.com/quantum-encoding/voidnote-python)
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "voidnote"
7
+ version = "0.1.0"
8
+ description = "Official SDK for VoidNote — zero-knowledge self-destructing notes"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ keywords = ["voidnote", "secrets", "encryption", "zero-knowledge", "one-time"]
13
+ classifiers = [
14
+ "Development Status :: 4 - Beta",
15
+ "Intended Audience :: Developers",
16
+ "Topic :: Security :: Cryptography",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ ]
20
+ dependencies = [
21
+ "cryptography>=41.0.0",
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ dev = ["pytest", "mypy"]
26
+
27
+ [project.urls]
28
+ Homepage = "https://voidnote.net"
29
+ Repository = "https://github.com/quantum-encoding/voidnote-python"
30
+ Documentation = "https://voidnote.net/docs"
31
+
32
+ [tool.hatch.build.targets.wheel]
33
+ packages = ["voidnote"]
@@ -0,0 +1,166 @@
1
+ """
2
+ VoidNote SDK — Python
3
+
4
+ pip install voidnote
5
+
6
+ Works with Python 3.9+. Requires: cryptography
7
+
8
+ pip install voidnote cryptography
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import hashlib
14
+ import os
15
+ import re
16
+ import urllib.request
17
+ import json
18
+ from dataclasses import dataclass
19
+ from typing import Optional
20
+
21
+ try:
22
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
23
+ _HAS_CRYPTO = True
24
+ except ImportError:
25
+ _HAS_CRYPTO = False
26
+
27
+ DEFAULT_BASE = "https://voidnote.net"
28
+
29
+
30
+ @dataclass
31
+ class ReadResult:
32
+ content: str
33
+ title: Optional[str]
34
+ view_count: int
35
+ max_views: int
36
+ destroyed: bool
37
+
38
+
39
+ @dataclass
40
+ class CreateResult:
41
+ url: str
42
+ expires_at: str
43
+
44
+
45
+ # --- internal helpers ---
46
+
47
+ def _extract_token(url_or_token: str) -> str:
48
+ match = re.search(r"[0-9a-f]{64}", url_or_token, re.IGNORECASE)
49
+ if not match:
50
+ raise ValueError("No valid 64-char token found in input")
51
+ return match.group(0).lower()
52
+
53
+
54
+ def _generate_token() -> tuple[str, str, str]:
55
+ token_bytes = os.urandom(32)
56
+ full_token = token_bytes.hex()
57
+ return full_token, full_token[:32], full_token[32:]
58
+
59
+
60
+ def _encrypt(content: str, secret: str) -> tuple[str, str]:
61
+ if not _HAS_CRYPTO:
62
+ raise ImportError(
63
+ "The 'cryptography' package is required to create notes: "
64
+ "pip install cryptography"
65
+ )
66
+ secret_bytes = bytes.fromhex(secret)
67
+ key = hashlib.sha256(secret_bytes).digest()
68
+ iv = os.urandom(12)
69
+ aesgcm = AESGCM(key)
70
+ ciphertext = aesgcm.encrypt(iv, content.encode("utf-8"), None)
71
+ return ciphertext.hex(), iv.hex()
72
+
73
+
74
+ def _fetch(url: str, *, method: str = "GET", headers: dict | None = None, body: bytes | None = None):
75
+ req = urllib.request.Request(url, data=body, method=method, headers=headers or {})
76
+ with urllib.request.urlopen(req) as resp:
77
+ return json.loads(resp.read().decode("utf-8")), resp.status
78
+
79
+
80
+ # --- public API ---
81
+
82
+ def read(url_or_token: str, base: str = DEFAULT_BASE) -> ReadResult:
83
+ """
84
+ Read a VoidNote. Consumes one view.
85
+
86
+ Args:
87
+ url_or_token: Full VoidNote URL or raw 64-char hex token
88
+ base: Override base URL (default: https://voidnote.net)
89
+
90
+ Returns:
91
+ ReadResult with .content, .title, .view_count, .max_views, .destroyed
92
+
93
+ Example:
94
+ result = voidnote.read("https://voidnote.net/note/abc123...")
95
+ print(result.content)
96
+ """
97
+ token = _extract_token(url_or_token)
98
+ data, status = _fetch(f"{base}/api/note/{token}")
99
+ if status >= 400:
100
+ raise RuntimeError(data.get("error", f"HTTP {status}"))
101
+ return ReadResult(
102
+ content=data["content"],
103
+ title=data.get("title"),
104
+ view_count=data["viewCount"],
105
+ max_views=data["maxViews"],
106
+ destroyed=data["destroyed"],
107
+ )
108
+
109
+
110
+ def create(
111
+ content: str,
112
+ *,
113
+ api_key: str,
114
+ title: Optional[str] = None,
115
+ max_views: int = 1,
116
+ base: str = DEFAULT_BASE,
117
+ ) -> CreateResult:
118
+ """
119
+ Create a VoidNote. Encrypts content client-side — the server never sees plaintext.
120
+
121
+ Args:
122
+ content: The secret text to encrypt and store
123
+ api_key: Your API key from dashboard (vn_...)
124
+ title: Optional plaintext title (keep non-sensitive)
125
+ max_views: How many times the note can be read (1–100)
126
+ base: Override base URL (default: https://voidnote.net)
127
+
128
+ Returns:
129
+ CreateResult with .url (shareable link) and .expires_at
130
+
131
+ Example:
132
+ result = voidnote.create("my-secret-api-key", api_key="vn_...")
133
+ print(result.url)
134
+ """
135
+ if not 1 <= max_views <= 100:
136
+ raise ValueError("max_views must be between 1 and 100")
137
+
138
+ full_token, token_id, secret = _generate_token()
139
+ encrypted_content, iv = _encrypt(content, secret)
140
+
141
+ payload = {
142
+ "tokenId": token_id,
143
+ "encryptedContent": encrypted_content,
144
+ "iv": iv,
145
+ "maxViews": max_views,
146
+ }
147
+ if title:
148
+ payload["title"] = title
149
+
150
+ body = json.dumps(payload).encode("utf-8")
151
+ headers = {
152
+ "Content-Type": "application/json",
153
+ "Authorization": f"Bearer {api_key}",
154
+ }
155
+
156
+ data, status = _fetch(f"{base}/api/notes", method="POST", headers=headers, body=body)
157
+ if status >= 400 or not data.get("success"):
158
+ raise RuntimeError(data.get("error", f"HTTP {status}"))
159
+
160
+ return CreateResult(
161
+ url=f"{data['siteUrl']}/note/{full_token}",
162
+ expires_at=data["expiresAt"],
163
+ )
164
+
165
+
166
+ __all__ = ["read", "create", "ReadResult", "CreateResult"]