v2kit 0.1__tar.gz → 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.
v2kit-0.2/CHANGELOG.md ADDED
@@ -0,0 +1,41 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+ ## [0.2] - 2026-06-04
9
+ ### Added
10
+ - `VMESSConfig` class
11
+ - `VLESSConfig` class
12
+ - `TrojanConfig` class
13
+ - `ShadowsocksConfig` class
14
+ - `V2kitError` class
15
+ - `V2kitValidationError` class
16
+ - `V2kitParseError` class
17
+ - `parse` function
18
+ ### Changed
19
+ - `README.md` updated
20
+ - Test system modified
21
+ - `is_vmess` function `config` parameter renamed to `uri`
22
+ - `is_vless` function `config` parameter renamed to `uri`
23
+ - `is_trojan` function `config` parameter renamed to `uri`
24
+ - `is_shadowsocks` function `config` parameter renamed to `uri`
25
+ - `encode_subscription` function `configs` parameter renamed to `entries`
26
+ ## [0.1] - 2026-05-16
27
+ ### Added
28
+ - `is_vmess` function
29
+ - `is_vless` function
30
+ - `is_trojan` function
31
+ - `is_shadowsocks` function
32
+ - `relabel` function
33
+ - `encode_subscription` function
34
+ - `decode_subscription` function
35
+
36
+ [Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.2...dev
37
+ [0.2]: https://github.com/sepandhaghighi/v2kit/compare/v0.1...v0.2
38
+ [0.1]: https://github.com/sepandhaghighi/v2kit/compare/bb5a2cb...v0.1
39
+
40
+
41
+
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: v2kit
3
- Version: 0.1
3
+ Version: 0.2
4
4
  Summary: V2Kit: A Lightweight Toolkit for V2Ray Config Manipulation
5
5
  Home-page: https://github.com/sepandhaghighi/v2kit
6
- Download-URL: https://github.com/sepandhaghighi/v2kit/tarball/v0.1
6
+ Download-URL: https://github.com/sepandhaghighi/v2kit/tarball/v0.2
7
7
  Author: Sepand Haghighi
8
8
  Author-email: me@sepand.tech
9
9
  License: MIT
@@ -49,6 +49,7 @@ Dynamic: summary
49
49
  <a href="https://www.python.org/"><img src="https://img.shields.io/badge/built%20with-Python3-green.svg" alt="built with Python3"></a>
50
50
  <a href="https://github.com/sepandhaghighi/v2kit"><img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/sepandhaghighi/v2kit"></a>
51
51
  <a href="https://badge.fury.io/py/v2kit"><img src="https://badge.fury.io/py/v2kit.svg" alt="PyPI version"></a>
52
+ <a href="https://codecov.io/gh/sepandhaghighi/v2kit"><img src="https://codecov.io/gh/sepandhaghighi/v2kit/graph/badge.svg?token=ytuuYF0NmT"></a>
52
53
  </div>
53
54
 
54
55
  ## Overview
@@ -83,38 +84,79 @@ V2Kit is a lightweight and extensible Python toolkit for working with V2Ray prox
83
84
  </tr>
84
85
  </table>
85
86
 
87
+ <table>
88
+ <tr>
89
+ <td align="center">Code Quality</td>
90
+ <td align="center"><a href="https://app.codacy.com/gh/sepandhaghighi/v2kit/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img src="https://app.codacy.com/project/badge/Grade/c0b30b55e04740b2894fe1aa4eef6589"></a></td>
91
+ <td align="center"><a href="https://www.codefactor.io/repository/github/sepandhaghighi/v2kit"><img src="https://www.codefactor.io/repository/github/sepandhaghighi/v2kit/badge" alt="CodeFactor"></a></td>
92
+ </tr>
93
+ </table>
94
+
86
95
  ## Installation
87
96
 
88
97
  ### Source Code
89
- - Download [Version 0.1](https://github.com/sepandhaghighi/v2kit/archive/v0.1.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
98
+ - Download [Version 0.2](https://github.com/sepandhaghighi/v2kit/archive/v0.2.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
90
99
  - `pip install .`
91
100
 
92
101
  ### PyPI
93
102
 
94
103
  - Check [Python Packaging User Guide](https://packaging.python.org/installing/)
95
- - `pip install v2kit==0.1`
104
+ - `pip install v2kit==0.2`
105
+
106
+ ## Supported Protocols
107
+
108
+ V2Kit currently supports the following protocols:
109
+
110
+ | Protocol | Detection | Parsing | Relabeling | Config Model |
111
+ | ----------- | --------- | ------- | ---------- | ------------ |
112
+ | VMESS | ✅ | ✅ | ✅ | ✅ |
113
+ | VLESS | ✅ | ✅ | ✅ | ✅ |
114
+ | Trojan | ✅ | ✅ | ✅ | ✅ |
115
+ | Shadowsocks | ✅ | ✅ | ✅ | ✅ |
96
116
 
97
117
 
98
118
  ## Usage
99
119
 
120
+ ### URI Utilities
121
+
100
122
  ```python
101
123
  from v2kit import (
102
124
  decode_subscription,
103
125
  encode_subscription,
104
126
  is_vmess,
127
+ parse,
105
128
  relabel,
106
129
  )
107
130
 
108
- config = "vmess://eyJhZGQiOiIxMjcuMC4wLjEiLCJwcyI6Im9sZCJ9"
131
+ uri = "vmess://eyJhZGQiOiIxMjcuMC4wLjEiLCJwcyI6Im9sZCJ9"
132
+
133
+ new_uri = relabel(uri, "Germany-1")
134
+
135
+ if is_vmess(new_uri):
136
+ print("VMESS URI detected")
109
137
 
110
- new_config = relabel(config, "Germany-1")
138
+ config = parse(new_uri)
111
139
 
112
- if is_vmess(new_config):
113
- print("VMESS config detected")
140
+ config.update_label("Germany-2")
114
141
 
115
- subscription = encode_subscription([new_config])
142
+ subscription = encode_subscription([config])
116
143
 
117
- configs = decode_subscription(subscription)
144
+ uris = decode_subscription(subscription)
145
+ ```
146
+
147
+ ### Configs
148
+
149
+ ```python
150
+ from v2kit import VMESSConfig
151
+
152
+ config = VMESSConfig(
153
+ uuid="550e8400-e29b-41d4-a716-446655440000",
154
+ address="example.com",
155
+ port=443,
156
+ label="Germany-1",
157
+ )
158
+
159
+ uri = config.to_uri()
118
160
  ```
119
161
 
120
162
  ## Issues & Bug Reports
@@ -166,6 +208,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
166
208
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
167
209
 
168
210
  ## [Unreleased]
211
+ ## [0.2] - 2026-06-04
212
+ ### Added
213
+ - `VMESSConfig` class
214
+ - `VLESSConfig` class
215
+ - `TrojanConfig` class
216
+ - `ShadowsocksConfig` class
217
+ - `V2kitError` class
218
+ - `V2kitValidationError` class
219
+ - `V2kitParseError` class
220
+ - `parse` function
221
+ ### Changed
222
+ - `README.md` updated
223
+ - Test system modified
224
+ - `is_vmess` function `config` parameter renamed to `uri`
225
+ - `is_vless` function `config` parameter renamed to `uri`
226
+ - `is_trojan` function `config` parameter renamed to `uri`
227
+ - `is_shadowsocks` function `config` parameter renamed to `uri`
228
+ - `encode_subscription` function `configs` parameter renamed to `entries`
169
229
  ## [0.1] - 2026-05-16
170
230
  ### Added
171
231
  - `is_vmess` function
@@ -176,7 +236,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
176
236
  - `encode_subscription` function
177
237
  - `decode_subscription` function
178
238
 
179
- [Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.1...dev
239
+ [Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.2...dev
240
+ [0.2]: https://github.com/sepandhaghighi/v2kit/compare/v0.1...v0.2
180
241
  [0.1]: https://github.com/sepandhaghighi/v2kit/compare/bb5a2cb...v0.1
181
242
 
182
243
 
@@ -4,6 +4,7 @@
4
4
  <a href="https://www.python.org/"><img src="https://img.shields.io/badge/built%20with-Python3-green.svg" alt="built with Python3"></a>
5
5
  <a href="https://github.com/sepandhaghighi/v2kit"><img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/sepandhaghighi/v2kit"></a>
6
6
  <a href="https://badge.fury.io/py/v2kit"><img src="https://badge.fury.io/py/v2kit.svg" alt="PyPI version"></a>
7
+ <a href="https://codecov.io/gh/sepandhaghighi/v2kit"><img src="https://codecov.io/gh/sepandhaghighi/v2kit/graph/badge.svg?token=ytuuYF0NmT"></a>
7
8
  </div>
8
9
 
9
10
  ## Overview
@@ -38,38 +39,79 @@ V2Kit is a lightweight and extensible Python toolkit for working with V2Ray prox
38
39
  </tr>
39
40
  </table>
40
41
 
42
+ <table>
43
+ <tr>
44
+ <td align="center">Code Quality</td>
45
+ <td align="center"><a href="https://app.codacy.com/gh/sepandhaghighi/v2kit/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img src="https://app.codacy.com/project/badge/Grade/c0b30b55e04740b2894fe1aa4eef6589"></a></td>
46
+ <td align="center"><a href="https://www.codefactor.io/repository/github/sepandhaghighi/v2kit"><img src="https://www.codefactor.io/repository/github/sepandhaghighi/v2kit/badge" alt="CodeFactor"></a></td>
47
+ </tr>
48
+ </table>
49
+
41
50
  ## Installation
42
51
 
43
52
  ### Source Code
44
- - Download [Version 0.1](https://github.com/sepandhaghighi/v2kit/archive/v0.1.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
53
+ - Download [Version 0.2](https://github.com/sepandhaghighi/v2kit/archive/v0.2.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
45
54
  - `pip install .`
46
55
 
47
56
  ### PyPI
48
57
 
49
58
  - Check [Python Packaging User Guide](https://packaging.python.org/installing/)
50
- - `pip install v2kit==0.1`
59
+ - `pip install v2kit==0.2`
60
+
61
+ ## Supported Protocols
62
+
63
+ V2Kit currently supports the following protocols:
64
+
65
+ | Protocol | Detection | Parsing | Relabeling | Config Model |
66
+ | ----------- | --------- | ------- | ---------- | ------------ |
67
+ | VMESS | ✅ | ✅ | ✅ | ✅ |
68
+ | VLESS | ✅ | ✅ | ✅ | ✅ |
69
+ | Trojan | ✅ | ✅ | ✅ | ✅ |
70
+ | Shadowsocks | ✅ | ✅ | ✅ | ✅ |
51
71
 
52
72
 
53
73
  ## Usage
54
74
 
75
+ ### URI Utilities
76
+
55
77
  ```python
56
78
  from v2kit import (
57
79
  decode_subscription,
58
80
  encode_subscription,
59
81
  is_vmess,
82
+ parse,
60
83
  relabel,
61
84
  )
62
85
 
63
- config = "vmess://eyJhZGQiOiIxMjcuMC4wLjEiLCJwcyI6Im9sZCJ9"
86
+ uri = "vmess://eyJhZGQiOiIxMjcuMC4wLjEiLCJwcyI6Im9sZCJ9"
87
+
88
+ new_uri = relabel(uri, "Germany-1")
64
89
 
65
- new_config = relabel(config, "Germany-1")
90
+ if is_vmess(new_uri):
91
+ print("VMESS URI detected")
66
92
 
67
- if is_vmess(new_config):
68
- print("VMESS config detected")
93
+ config = parse(new_uri)
69
94
 
70
- subscription = encode_subscription([new_config])
95
+ config.update_label("Germany-2")
96
+
97
+ subscription = encode_subscription([config])
98
+
99
+ uris = decode_subscription(subscription)
100
+ ```
101
+
102
+ ### Configs
103
+
104
+ ```python
105
+ from v2kit import VMESSConfig
106
+
107
+ config = VMESSConfig(
108
+ uuid="550e8400-e29b-41d4-a716-446655440000",
109
+ address="example.com",
110
+ port=443,
111
+ label="Germany-1",
112
+ )
71
113
 
72
- configs = decode_subscription(subscription)
114
+ uri = config.to_uri()
73
115
  ```
74
116
 
75
117
  ## Issues & Bug Reports
@@ -4,8 +4,8 @@
4
4
 
5
5
  | Version | Supported |
6
6
  | ------------- | ------------------ |
7
- | 0.1 | :white_check_mark: |
8
- | < 0.1 | :x: |
7
+ | 0.2 | :white_check_mark: |
8
+ | < 0.2 | :x: |
9
9
 
10
10
  ## Reporting a Vulnerability
11
11
 
@@ -33,7 +33,7 @@ def read_description() -> str:
33
33
  setup(
34
34
  name='v2kit',
35
35
  packages=['v2kit'],
36
- version='0.1',
36
+ version='0.2',
37
37
  description='V2Kit: A Lightweight Toolkit for V2Ray Config Manipulation',
38
38
  long_description=read_description(),
39
39
  long_description_content_type='text/markdown',
@@ -41,7 +41,7 @@ setup(
41
41
  author='Sepand Haghighi',
42
42
  author_email='me@sepand.tech',
43
43
  url='https://github.com/sepandhaghighi/v2kit',
44
- download_url='https://github.com/sepandhaghighi/v2kit/tarball/v0.1',
44
+ download_url='https://github.com/sepandhaghighi/v2kit/tarball/v0.2',
45
45
  keywords="v2ray v2ray-config v2ray-tools vmess vless trojan shadowsocks proxy subscription network",
46
46
  project_urls={
47
47
  'Source': 'https://github.com/sepandhaghighi/v2kit'},
@@ -0,0 +1,168 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import pytest
4
+ from v2kit import VMESSConfig, VLESSConfig, TrojanConfig, ShadowsocksConfig
5
+ from v2kit import relabel, encode_subscription, decode_subscription, parse
6
+ from v2kit import V2kitError, V2kitValidationError, V2kitParseError
7
+ from v2kit.validators import _validate_uri
8
+
9
+
10
+ INVALID_PROTOCOL = "http://example.com"
11
+
12
+ INVALID_VMESS = "vmess://invalid-base64"
13
+
14
+ VALID_VLESS = (
15
+ "vless://1c4b4bca-e3ff-4ca8-a062-6f399ad3cf45@example.com:443"
16
+ "?security=tls#test"
17
+ )
18
+
19
+ VALID_UUID = (
20
+ "1c4b4bca-e3ff-4ca8-a062-6f399ad3cf45"
21
+ )
22
+
23
+
24
+ def test_validate_uri_non_string():
25
+ with pytest.raises(V2kitValidationError):
26
+ _validate_uri(123)
27
+
28
+
29
+ def test_validate_uri_empty():
30
+ with pytest.raises(V2kitValidationError):
31
+ _validate_uri("")
32
+
33
+
34
+ def test_validate_uri_missing_scheme():
35
+ with pytest.raises(V2kitValidationError):
36
+ _validate_uri("invalid-config")
37
+
38
+
39
+ def test_validate_uri_unsupported_protocol():
40
+ with pytest.raises(V2kitValidationError):
41
+ _validate_uri(INVALID_PROTOCOL)
42
+
43
+
44
+ def test_validate_invalid_vmess():
45
+ with pytest.raises(V2kitValidationError):
46
+ _validate_uri(INVALID_VMESS)
47
+
48
+
49
+ def test_relabel_invalid_config():
50
+ with pytest.raises(V2kitValidationError):
51
+ relabel("invalid", "label")
52
+
53
+
54
+ def test_relabel_empty_label():
55
+ with pytest.raises(V2kitValidationError):
56
+ relabel(VALID_VLESS, "")
57
+
58
+
59
+ def test_relabel_non_string_label():
60
+ with pytest.raises(V2kitValidationError):
61
+ relabel(VALID_VLESS, 123)
62
+
63
+
64
+ def test_encode_subscription_invalid_config():
65
+ configs = [
66
+ VALID_VLESS,
67
+ "invalid-config",
68
+ ]
69
+
70
+ with pytest.raises(V2kitValidationError):
71
+ encode_subscription(configs)
72
+
73
+
74
+ def test_decode_subscription_non_string():
75
+ with pytest.raises(V2kitValidationError):
76
+ decode_subscription(123)
77
+
78
+
79
+ def test_decode_subscription_invalid_data():
80
+ with pytest.raises(Exception):
81
+ decode_subscription("invalid-base64")
82
+
83
+
84
+ def test_decode_subscription_invalid_config():
85
+ invalid_subscription = (
86
+ "aW52YWxpZC1jb25maWc="
87
+ )
88
+
89
+ with pytest.raises(V2kitValidationError):
90
+ decode_subscription(invalid_subscription)
91
+
92
+
93
+ def test_exception_hierarchy():
94
+ assert issubclass(
95
+ V2kitValidationError,
96
+ V2kitError,
97
+ )
98
+
99
+ assert issubclass(
100
+ V2kitParseError,
101
+ V2kitValidationError,
102
+ )
103
+
104
+
105
+ def test_parse_invalid_uri():
106
+ with pytest.raises(V2kitParseError):
107
+ parse("invalid")
108
+
109
+
110
+ def test_parse_unsupported_protocol():
111
+ with pytest.raises(V2kitParseError):
112
+ parse("http://example.com")
113
+
114
+
115
+ def test_vless_invalid_uuid():
116
+ with pytest.raises(V2kitValidationError):
117
+ VLESSConfig(
118
+ uuid="invalid",
119
+ address="example.com",
120
+ port=443,
121
+ )
122
+
123
+
124
+ def test_vless_invalid_port():
125
+ with pytest.raises(V2kitValidationError):
126
+ VLESSConfig(
127
+ uuid=VALID_UUID,
128
+ address="example.com",
129
+ port=70000,
130
+ )
131
+
132
+
133
+ def test_vless_empty_address():
134
+ with pytest.raises(V2kitValidationError):
135
+ VLESSConfig(
136
+ uuid=VALID_UUID,
137
+ address="",
138
+ port=443,
139
+ )
140
+
141
+
142
+ def test_vmess_invalid_alter_id():
143
+ with pytest.raises(V2kitValidationError):
144
+ VMESSConfig(
145
+ uuid=VALID_UUID,
146
+ address="example.com",
147
+ port=443,
148
+ alter_id=-1,
149
+ )
150
+
151
+
152
+ def test_trojan_empty_password():
153
+ with pytest.raises(V2kitValidationError):
154
+ TrojanConfig(
155
+ password="",
156
+ address="example.com",
157
+ port=443,
158
+ )
159
+
160
+
161
+ def test_shadowsocks_empty_encryption():
162
+ with pytest.raises(V2kitValidationError):
163
+ ShadowsocksConfig(
164
+ encryption="",
165
+ password="secret",
166
+ address="example.com",
167
+ port=8388,
168
+ )
@@ -1,8 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  import json
4
- from v2kit import is_vmess, is_vless, is_trojan, is_shadowsocks
4
+ from v2kit import is_vmess, is_vless, is_trojan, is_shadowsocks, parse
5
5
  from v2kit import relabel, encode_subscription, decode_subscription
6
+ from v2kit import VMESSConfig, VLESSConfig, TrojanConfig, ShadowsocksConfig
6
7
  from v2kit.utils import _encode_base64
7
8
 
8
9
 
@@ -12,7 +13,7 @@ def create_vmess(label="test"):
12
13
  "ps": label,
13
14
  "add": "example.com",
14
15
  "port": "443",
15
- "id": "11111111-1111-1111-1111-111111111111",
16
+ "id": "1c4b4bca-e3ff-4ca8-a062-6f399ad3cf45",
16
17
  "aid": "0",
17
18
  "net": "ws",
18
19
  "type": "none",
@@ -29,7 +30,7 @@ def create_vmess(label="test"):
29
30
  VMESS_CONFIG = create_vmess()
30
31
 
31
32
  VLESS_CONFIG = (
32
- "vless://uuid@example.com:443"
33
+ "vless://1c4b4bca-e3ff-4ca8-a062-6f399ad3cf45@example.com:443"
33
34
  "?security=tls#vless-test"
34
35
  )
35
36
 
@@ -63,6 +64,22 @@ def test_is_vmess_negative():
63
64
  assert is_vmess(VLESS_CONFIG) is False
64
65
 
65
66
 
67
+ def test_is_vmess_invalid():
68
+ assert is_vmess("invalid") is False
69
+
70
+
71
+ def test_is_vless_invalid():
72
+ assert is_vless("invalid") is False
73
+
74
+
75
+ def test_is_trojan_invalid():
76
+ assert is_trojan("invalid") is False
77
+
78
+
79
+ def test_is_shadowsocks_invalid():
80
+ assert is_shadowsocks("invalid") is False
81
+
82
+
66
83
  def test_relabel_vmess():
67
84
  result = relabel(VMESS_CONFIG, "new-label")
68
85
 
@@ -131,3 +148,61 @@ def test_encode_decode_subscription_roundtrip():
131
148
  decoded = decode_subscription(encoded)
132
149
 
133
150
  assert decoded == configs
151
+
152
+
153
+ def test_encode_subscription_with_models():
154
+ config = parse(VLESS_CONFIG)
155
+
156
+ result = encode_subscription([config])
157
+
158
+ assert isinstance(result, str)
159
+
160
+
161
+ def test_encode_subscription_no_validation():
162
+ result = encode_subscription(
163
+ ["invalid-config"],
164
+ validate=False,
165
+ )
166
+
167
+ assert isinstance(result, str)
168
+
169
+
170
+ def test_decode_subscription_no_validation():
171
+ encoded = _encode_base64(
172
+ "invalid-config"
173
+ )
174
+
175
+ result = decode_subscription(
176
+ encoded,
177
+ validate=False,
178
+ )
179
+
180
+ assert result == ["invalid-config"]
181
+
182
+
183
+ def test_parse_vmess():
184
+ assert isinstance(
185
+ parse(VMESS_CONFIG),
186
+ VMESSConfig,
187
+ )
188
+
189
+
190
+ def test_parse_vless():
191
+ assert isinstance(
192
+ parse(VLESS_CONFIG),
193
+ VLESSConfig,
194
+ )
195
+
196
+
197
+ def test_parse_trojan():
198
+ assert isinstance(
199
+ parse(TROJAN_CONFIG),
200
+ TrojanConfig,
201
+ )
202
+
203
+
204
+ def test_parse_shadowsocks():
205
+ assert isinstance(
206
+ parse(SHADOWSOCKS_CONFIG),
207
+ ShadowsocksConfig,
208
+ )