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 +41 -0
- {v2kit-0.1 → v2kit-0.2}/PKG-INFO +72 -11
- {v2kit-0.1 → v2kit-0.2}/README.md +50 -8
- {v2kit-0.1 → v2kit-0.2}/SECURITY.md +2 -2
- {v2kit-0.1 → v2kit-0.2}/setup.py +2 -2
- v2kit-0.2/tests/test_errors.py +168 -0
- {v2kit-0.1 → v2kit-0.2}/tests/test_functions.py +78 -3
- v2kit-0.2/tests/test_models.py +114 -0
- {v2kit-0.1 → v2kit-0.2}/v2kit/__init__.py +17 -1
- v2kit-0.2/v2kit/errors.py +14 -0
- v2kit-0.2/v2kit/functions.py +127 -0
- v2kit-0.2/v2kit/models.py +735 -0
- v2kit-0.2/v2kit/params.py +30 -0
- v2kit-0.2/v2kit/parsers.py +169 -0
- v2kit-0.2/v2kit/utils.py +67 -0
- v2kit-0.2/v2kit/validators.py +169 -0
- {v2kit-0.1 → v2kit-0.2}/v2kit.egg-info/PKG-INFO +72 -11
- {v2kit-0.1 → v2kit-0.2}/v2kit.egg-info/SOURCES.txt +5 -0
- v2kit-0.1/CHANGELOG.md +0 -22
- v2kit-0.1/tests/test_errors.py +0 -85
- v2kit-0.1/v2kit/functions.py +0 -106
- v2kit-0.1/v2kit/params.py +0 -19
- v2kit-0.1/v2kit/utils.py +0 -162
- {v2kit-0.1 → v2kit-0.2}/AUTHORS.md +0 -0
- {v2kit-0.1 → v2kit-0.2}/LICENSE +0 -0
- {v2kit-0.1 → v2kit-0.2}/MANIFEST.in +0 -0
- {v2kit-0.1 → v2kit-0.2}/dev-requirements.txt +0 -0
- {v2kit-0.1 → v2kit-0.2}/requirements.txt +0 -0
- {v2kit-0.1 → v2kit-0.2}/setup.cfg +0 -0
- {v2kit-0.1 → v2kit-0.2}/v2kit/__main__.py +0 -0
- {v2kit-0.1 → v2kit-0.2}/v2kit.egg-info/dependency_links.txt +0 -0
- {v2kit-0.1 → v2kit-0.2}/v2kit.egg-info/top_level.txt +0 -0
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
|
+
|
{v2kit-0.1 → v2kit-0.2}/PKG-INFO
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: v2kit
|
|
3
|
-
Version: 0.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
138
|
+
config = parse(new_uri)
|
|
111
139
|
|
|
112
|
-
|
|
113
|
-
print("VMESS config detected")
|
|
140
|
+
config.update_label("Germany-2")
|
|
114
141
|
|
|
115
|
-
subscription = encode_subscription([
|
|
142
|
+
subscription = encode_subscription([config])
|
|
116
143
|
|
|
117
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
86
|
+
uri = "vmess://eyJhZGQiOiIxMjcuMC4wLjEiLCJwcyI6Im9sZCJ9"
|
|
87
|
+
|
|
88
|
+
new_uri = relabel(uri, "Germany-1")
|
|
64
89
|
|
|
65
|
-
|
|
90
|
+
if is_vmess(new_uri):
|
|
91
|
+
print("VMESS URI detected")
|
|
66
92
|
|
|
67
|
-
|
|
68
|
-
print("VMESS config detected")
|
|
93
|
+
config = parse(new_uri)
|
|
69
94
|
|
|
70
|
-
|
|
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
|
-
|
|
114
|
+
uri = config.to_uri()
|
|
73
115
|
```
|
|
74
116
|
|
|
75
117
|
## Issues & Bug Reports
|
{v2kit-0.1 → v2kit-0.2}/setup.py
RENAMED
|
@@ -33,7 +33,7 @@ def read_description() -> str:
|
|
|
33
33
|
setup(
|
|
34
34
|
name='v2kit',
|
|
35
35
|
packages=['v2kit'],
|
|
36
|
-
version='0.
|
|
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.
|
|
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": "
|
|
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://
|
|
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
|
+
)
|