v2kit 0.3__tar.gz → 0.4__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.3 → v2kit-0.4}/CHANGELOG.md +9 -1
- {v2kit-0.3 → v2kit-0.4}/PKG-INFO +14 -5
- {v2kit-0.3 → v2kit-0.4}/README.md +3 -2
- {v2kit-0.3 → v2kit-0.4}/SECURITY.md +2 -2
- {v2kit-0.3 → v2kit-0.4}/setup.py +3 -2
- {v2kit-0.3 → v2kit-0.4}/tests/test_errors.py +25 -3
- {v2kit-0.3 → v2kit-0.4}/tests/test_functions.py +11 -1
- v2kit-0.4/tests/test_http.py +194 -0
- v2kit-0.4/tests/test_shadowsocks.py +196 -0
- v2kit-0.4/tests/test_socks.py +192 -0
- v2kit-0.4/tests/test_trojan.py +161 -0
- v2kit-0.4/tests/test_vless.py +169 -0
- v2kit-0.4/tests/test_vmess.py +163 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/__init__.py +5 -2
- {v2kit-0.3 → v2kit-0.4}/v2kit/functions.py +9 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/models/__init__.py +2 -1
- {v2kit-0.3 → v2kit-0.4}/v2kit/models/base.py +2 -2
- v2kit-0.4/v2kit/models/http.py +166 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/params.py +2 -1
- {v2kit-0.3 → v2kit-0.4}/v2kit/parsers.py +22 -4
- {v2kit-0.3 → v2kit-0.4}/v2kit.egg-info/PKG-INFO +14 -5
- {v2kit-0.3 → v2kit-0.4}/v2kit.egg-info/SOURCES.txt +2 -0
- v2kit-0.3/tests/test_shadowsocks.py +0 -17
- v2kit-0.3/tests/test_socks.py +0 -69
- v2kit-0.3/tests/test_trojan.py +0 -17
- v2kit-0.3/tests/test_vless.py +0 -58
- v2kit-0.3/tests/test_vmess.py +0 -32
- {v2kit-0.3 → v2kit-0.4}/AUTHORS.md +0 -0
- {v2kit-0.3 → v2kit-0.4}/LICENSE +0 -0
- {v2kit-0.3 → v2kit-0.4}/MANIFEST.in +0 -0
- {v2kit-0.3 → v2kit-0.4}/requirements-dev.txt +0 -0
- {v2kit-0.3 → v2kit-0.4}/setup.cfg +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/__main__.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/errors.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/models/shadowsocks.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/models/socks.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/models/trojan.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/models/vless.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/models/vmess.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/utils.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit/validators.py +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit.egg-info/dependency_links.txt +0 -0
- {v2kit-0.3 → v2kit-0.4}/v2kit.egg-info/top_level.txt +0 -0
|
@@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
|
+
## [0.4] - 2026-07-02
|
|
9
|
+
### Added
|
|
10
|
+
- `HttpConfig` class
|
|
11
|
+
### Changed
|
|
12
|
+
- `parse` function modified
|
|
13
|
+
- `README.md` updated
|
|
14
|
+
- Test system modified
|
|
8
15
|
## [0.3] - 2026-06-16
|
|
9
16
|
### Added
|
|
10
17
|
- Logo
|
|
@@ -43,7 +50,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
43
50
|
- `encode_subscription` function
|
|
44
51
|
- `decode_subscription` function
|
|
45
52
|
|
|
46
|
-
[Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.
|
|
53
|
+
[Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.4...dev
|
|
54
|
+
[0.4]: https://github.com/sepandhaghighi/v2kit/compare/v0.3...v0.4
|
|
47
55
|
[0.3]: https://github.com/sepandhaghighi/v2kit/compare/v0.2...v0.3
|
|
48
56
|
[0.2]: https://github.com/sepandhaghighi/v2kit/compare/v0.1...v0.2
|
|
49
57
|
[0.1]: https://github.com/sepandhaghighi/v2kit/compare/bb5a2cb...v0.1
|
{v2kit-0.3 → v2kit-0.4}/PKG-INFO
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: v2kit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4
|
|
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.4
|
|
7
7
|
Author: Sepand Haghighi
|
|
8
8
|
Author-email: me@sepand.tech
|
|
9
9
|
License: MIT
|
|
@@ -96,13 +96,13 @@ V2Kit is a lightweight and extensible Python toolkit for working with V2Ray prox
|
|
|
96
96
|
## Installation
|
|
97
97
|
|
|
98
98
|
### Source Code
|
|
99
|
-
- Download [Version 0.
|
|
99
|
+
- Download [Version 0.4](https://github.com/sepandhaghighi/v2kit/archive/v0.4.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
|
|
100
100
|
- `pip install .`
|
|
101
101
|
|
|
102
102
|
### PyPI
|
|
103
103
|
|
|
104
104
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
105
|
-
- `pip install v2kit==0.
|
|
105
|
+
- `pip install v2kit==0.4`
|
|
106
106
|
|
|
107
107
|
## Supported Protocols
|
|
108
108
|
|
|
@@ -115,6 +115,7 @@ V2Kit currently supports the following protocols:
|
|
|
115
115
|
| Trojan | ✅ | ✅ | ✅ | ✅ |
|
|
116
116
|
| Shadowsocks | ✅ | ✅ | ✅ | ✅ |
|
|
117
117
|
| SOCKS | ✅ | ✅ | ✅ | ✅ |
|
|
118
|
+
| HTTP | ✅ | ✅ | ✅ | ✅ |
|
|
118
119
|
|
|
119
120
|
|
|
120
121
|
## Usage
|
|
@@ -210,6 +211,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
210
211
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
211
212
|
|
|
212
213
|
## [Unreleased]
|
|
214
|
+
## [0.4] - 2026-07-02
|
|
215
|
+
### Added
|
|
216
|
+
- `HttpConfig` class
|
|
217
|
+
### Changed
|
|
218
|
+
- `parse` function modified
|
|
219
|
+
- `README.md` updated
|
|
220
|
+
- Test system modified
|
|
213
221
|
## [0.3] - 2026-06-16
|
|
214
222
|
### Added
|
|
215
223
|
- Logo
|
|
@@ -248,7 +256,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
248
256
|
- `encode_subscription` function
|
|
249
257
|
- `decode_subscription` function
|
|
250
258
|
|
|
251
|
-
[Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.
|
|
259
|
+
[Unreleased]: https://github.com/sepandhaghighi/v2kit/compare/v0.4...dev
|
|
260
|
+
[0.4]: https://github.com/sepandhaghighi/v2kit/compare/v0.3...v0.4
|
|
252
261
|
[0.3]: https://github.com/sepandhaghighi/v2kit/compare/v0.2...v0.3
|
|
253
262
|
[0.2]: https://github.com/sepandhaghighi/v2kit/compare/v0.1...v0.2
|
|
254
263
|
[0.1]: https://github.com/sepandhaghighi/v2kit/compare/bb5a2cb...v0.1
|
|
@@ -51,13 +51,13 @@ V2Kit is a lightweight and extensible Python toolkit for working with V2Ray prox
|
|
|
51
51
|
## Installation
|
|
52
52
|
|
|
53
53
|
### Source Code
|
|
54
|
-
- Download [Version 0.
|
|
54
|
+
- Download [Version 0.4](https://github.com/sepandhaghighi/v2kit/archive/v0.4.zip) or [Latest Source](https://github.com/sepandhaghighi/v2kit/archive/dev.zip)
|
|
55
55
|
- `pip install .`
|
|
56
56
|
|
|
57
57
|
### PyPI
|
|
58
58
|
|
|
59
59
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
60
|
-
- `pip install v2kit==0.
|
|
60
|
+
- `pip install v2kit==0.4`
|
|
61
61
|
|
|
62
62
|
## Supported Protocols
|
|
63
63
|
|
|
@@ -70,6 +70,7 @@ V2Kit currently supports the following protocols:
|
|
|
70
70
|
| Trojan | ✅ | ✅ | ✅ | ✅ |
|
|
71
71
|
| Shadowsocks | ✅ | ✅ | ✅ | ✅ |
|
|
72
72
|
| SOCKS | ✅ | ✅ | ✅ | ✅ |
|
|
73
|
+
| HTTP | ✅ | ✅ | ✅ | ✅ |
|
|
73
74
|
|
|
74
75
|
|
|
75
76
|
## Usage
|
{v2kit-0.3 → v2kit-0.4}/setup.py
RENAMED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""Setup module."""
|
|
3
3
|
from setuptools import setup
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
def read_description() -> str:
|
|
6
7
|
"""Read README.md and CHANGELOG.md."""
|
|
7
8
|
try:
|
|
@@ -22,7 +23,7 @@ def read_description() -> str:
|
|
|
22
23
|
setup(
|
|
23
24
|
name='v2kit',
|
|
24
25
|
packages=['v2kit', 'v2kit.models'],
|
|
25
|
-
version='0.
|
|
26
|
+
version='0.4',
|
|
26
27
|
description='V2Kit: A Lightweight Toolkit for V2Ray Config Manipulation',
|
|
27
28
|
long_description=read_description(),
|
|
28
29
|
long_description_content_type='text/markdown',
|
|
@@ -30,7 +31,7 @@ setup(
|
|
|
30
31
|
author='Sepand Haghighi',
|
|
31
32
|
author_email='me@sepand.tech',
|
|
32
33
|
url='https://github.com/sepandhaghighi/v2kit',
|
|
33
|
-
download_url='https://github.com/sepandhaghighi/v2kit/tarball/v0.
|
|
34
|
+
download_url='https://github.com/sepandhaghighi/v2kit/tarball/v0.4',
|
|
34
35
|
keywords='v2ray v2ray-config v2ray-tools vmess vless trojan shadowsocks proxy subscription network',
|
|
35
36
|
project_urls={
|
|
36
37
|
'Source': 'https://github.com/sepandhaghighi/v2kit'},
|
|
@@ -7,10 +7,12 @@ from v2kit import V2kitError, V2kitValidationError, V2kitParseError
|
|
|
7
7
|
from v2kit.validators import _validate_uri
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
INVALID_PROTOCOL = "
|
|
10
|
+
INVALID_PROTOCOL = "ftp://example.com"
|
|
11
11
|
|
|
12
12
|
INVALID_VMESS = "vmess://invalid-base64"
|
|
13
13
|
|
|
14
|
+
INVALID_SHADOWSOCKS = "ss://invalid-base64@example.com:8388#ss-test"
|
|
15
|
+
|
|
14
16
|
VALID_VLESS = (
|
|
15
17
|
"vless://1c4b4bca-e3ff-4ca8-a062-6f399ad3cf45@example.com:443"
|
|
16
18
|
"?security=tls#test"
|
|
@@ -61,7 +63,7 @@ def test_relabel_non_string_label():
|
|
|
61
63
|
relabel(VALID_VLESS, 123)
|
|
62
64
|
|
|
63
65
|
|
|
64
|
-
def
|
|
66
|
+
def test_encode_subscription_invalid_config1():
|
|
65
67
|
configs = [
|
|
66
68
|
VALID_VLESS,
|
|
67
69
|
"invalid-config",
|
|
@@ -71,6 +73,16 @@ def test_encode_subscription_invalid_config():
|
|
|
71
73
|
encode_subscription(configs)
|
|
72
74
|
|
|
73
75
|
|
|
76
|
+
def test_encode_subscription_invalid_config2():
|
|
77
|
+
configs = [
|
|
78
|
+
VALID_VLESS,
|
|
79
|
+
1,
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
with pytest.raises(V2kitValidationError):
|
|
83
|
+
encode_subscription(configs)
|
|
84
|
+
|
|
85
|
+
|
|
74
86
|
def test_decode_subscription_non_string():
|
|
75
87
|
with pytest.raises(V2kitValidationError):
|
|
76
88
|
decode_subscription(123)
|
|
@@ -109,7 +121,17 @@ def test_parse_invalid_uri():
|
|
|
109
121
|
|
|
110
122
|
def test_parse_unsupported_protocol():
|
|
111
123
|
with pytest.raises(V2kitParseError):
|
|
112
|
-
parse(
|
|
124
|
+
parse(INVALID_PROTOCOL)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_parse_invalid_vmess():
|
|
128
|
+
with pytest.raises(V2kitParseError):
|
|
129
|
+
parse(INVALID_VMESS)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_parse_invalid_shadowsocks():
|
|
133
|
+
with pytest.raises(V2kitParseError):
|
|
134
|
+
parse(INVALID_SHADOWSOCKS)
|
|
113
135
|
|
|
114
136
|
|
|
115
137
|
def test_vless_invalid_uuid():
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from v2kit import is_vmess, is_vless, is_trojan, is_shadowsocks, is_socks, parse
|
|
4
|
+
from v2kit import is_vmess, is_vless, is_trojan, is_shadowsocks, is_socks, is_http, parse
|
|
5
5
|
from v2kit import relabel, encode_subscription, decode_subscription
|
|
6
6
|
from v2kit import VMESSConfig, VLESSConfig, TrojanConfig, ShadowsocksConfig, SocksConfig
|
|
7
7
|
from v2kit.utils import _encode_base64
|
|
@@ -37,6 +37,8 @@ SHADOWSOCKS_CONFIG = "ss://YWVzLTI1Ni1nY206cGFzc3dvcmQ=@example.com:8388#ss-test
|
|
|
37
37
|
|
|
38
38
|
SOCKS_CONFIG = "socks://user:password@example.com:1080#socks-test"
|
|
39
39
|
|
|
40
|
+
HTTP_CONFIG = "http://user@example.com:1080#test"
|
|
41
|
+
|
|
40
42
|
|
|
41
43
|
def test_is_vmess():
|
|
42
44
|
assert is_vmess(VMESS_CONFIG) is True
|
|
@@ -54,6 +56,10 @@ def test_is_shadowsocks():
|
|
|
54
56
|
assert is_shadowsocks(SHADOWSOCKS_CONFIG) is True
|
|
55
57
|
|
|
56
58
|
|
|
59
|
+
def test_is_http():
|
|
60
|
+
assert is_http(HTTP_CONFIG) is True
|
|
61
|
+
|
|
62
|
+
|
|
57
63
|
def test_is_vmess_negative():
|
|
58
64
|
assert is_vmess(VLESS_CONFIG) is False
|
|
59
65
|
|
|
@@ -74,6 +80,10 @@ def test_is_shadowsocks_invalid():
|
|
|
74
80
|
assert is_shadowsocks("invalid") is False
|
|
75
81
|
|
|
76
82
|
|
|
83
|
+
def test_is_http_invalid():
|
|
84
|
+
assert is_http("invalid") is False
|
|
85
|
+
|
|
86
|
+
|
|
77
87
|
def test_is_socks():
|
|
78
88
|
assert is_socks(SOCKS_CONFIG) is True
|
|
79
89
|
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import pytest
|
|
3
|
+
from v2kit import parse
|
|
4
|
+
from v2kit import HttpConfig
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_defaults():
|
|
8
|
+
config = HttpConfig(
|
|
9
|
+
address="example.com",
|
|
10
|
+
port=1080,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
assert config.label is None
|
|
14
|
+
assert config.extra == {}
|
|
15
|
+
assert config.username is None
|
|
16
|
+
assert config.password is None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_to_dict():
|
|
20
|
+
config = HttpConfig(
|
|
21
|
+
address="example.com",
|
|
22
|
+
port=1080,
|
|
23
|
+
username="user",
|
|
24
|
+
password="password",
|
|
25
|
+
label="test",
|
|
26
|
+
extra={"foo": "bar"},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
assert config.to_dict() == {
|
|
30
|
+
"protocol": "http",
|
|
31
|
+
"address": "example.com",
|
|
32
|
+
"port": 1080,
|
|
33
|
+
"username": "user",
|
|
34
|
+
"password": "password",
|
|
35
|
+
"extra": {"foo": "bar"},
|
|
36
|
+
"label": "test",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_extra():
|
|
41
|
+
config = HttpConfig(
|
|
42
|
+
address="example.com",
|
|
43
|
+
port=1080,
|
|
44
|
+
extra={"foo": "bar"},
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
data = config.to_dict()
|
|
48
|
+
|
|
49
|
+
assert data["extra"]["foo"] == "bar"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_update_methods():
|
|
53
|
+
config = HttpConfig(
|
|
54
|
+
address="example.com",
|
|
55
|
+
port=1080,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
config.update_address("example.org")
|
|
59
|
+
config.update_port(8080)
|
|
60
|
+
config.update_username("user")
|
|
61
|
+
config.update_password("password")
|
|
62
|
+
|
|
63
|
+
assert config.address == "example.org"
|
|
64
|
+
assert config.port == 8080
|
|
65
|
+
assert config.username == "user"
|
|
66
|
+
assert config.password == "password"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_update_extra():
|
|
70
|
+
config = HttpConfig(
|
|
71
|
+
address="example.com",
|
|
72
|
+
port=1080,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
config.update_extra(
|
|
76
|
+
{"foo": "bar"}
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
assert config.extra["foo"] == "bar"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_method_chaining():
|
|
83
|
+
config = HttpConfig(
|
|
84
|
+
address="example.com",
|
|
85
|
+
port=1080,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
config.update_address(
|
|
89
|
+
"example.org"
|
|
90
|
+
).update_port(
|
|
91
|
+
8080
|
|
92
|
+
).update_username(
|
|
93
|
+
"user"
|
|
94
|
+
).update_password(
|
|
95
|
+
"password"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
assert config.address == "example.org"
|
|
99
|
+
assert config.port == 8080
|
|
100
|
+
assert config.username == "user"
|
|
101
|
+
assert config.password == "password"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@pytest.mark.parametrize(
|
|
105
|
+
"kwargs",
|
|
106
|
+
[
|
|
107
|
+
{"address": ""},
|
|
108
|
+
{"port": 0},
|
|
109
|
+
{"port": 1.2},
|
|
110
|
+
{"username": ""},
|
|
111
|
+
{"password": ""},
|
|
112
|
+
{"extra": 1},
|
|
113
|
+
],
|
|
114
|
+
)
|
|
115
|
+
def test_invalid_values(kwargs):
|
|
116
|
+
params = {
|
|
117
|
+
"address": "example.com",
|
|
118
|
+
"port": 1080,
|
|
119
|
+
}
|
|
120
|
+
params.update(kwargs)
|
|
121
|
+
|
|
122
|
+
with pytest.raises(ValueError):
|
|
123
|
+
HttpConfig(**params)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_to_uri_roundtrip():
|
|
127
|
+
config = HttpConfig(
|
|
128
|
+
address="example.com",
|
|
129
|
+
port=1080,
|
|
130
|
+
username="user",
|
|
131
|
+
password="password",
|
|
132
|
+
label="test",
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
parsed = parse(config.to_uri())
|
|
136
|
+
|
|
137
|
+
assert parsed == config
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_equality():
|
|
141
|
+
config1 = HttpConfig(
|
|
142
|
+
address="example.com",
|
|
143
|
+
port=1080,
|
|
144
|
+
username="user",
|
|
145
|
+
password="password",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
config2 = HttpConfig(
|
|
149
|
+
address="example.com",
|
|
150
|
+
port=1080,
|
|
151
|
+
username="user",
|
|
152
|
+
password="password",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
config3 = HttpConfig(
|
|
156
|
+
address="example.org",
|
|
157
|
+
port=1080,
|
|
158
|
+
username="user",
|
|
159
|
+
password="password",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
assert config1 == config2
|
|
163
|
+
assert config1 != config3
|
|
164
|
+
assert config1 != "config1"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_to_uri_without_auth():
|
|
168
|
+
config = HttpConfig(
|
|
169
|
+
address="example.com",
|
|
170
|
+
port=1080,
|
|
171
|
+
label="test",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
assert config.to_uri() == "http://example.com:1080#test"
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_to_uri_username_only():
|
|
178
|
+
config = HttpConfig(
|
|
179
|
+
address="example.com",
|
|
180
|
+
port=1080,
|
|
181
|
+
username="user",
|
|
182
|
+
label="test",
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
assert config.to_uri() == "http://user@example.com:1080#test"
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def test_repr():
|
|
189
|
+
config = HttpConfig(
|
|
190
|
+
address="example.com",
|
|
191
|
+
port=1080,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
assert repr(config) == "HttpConfig(protocol=<Protocol.HTTP: 'http'>, label=None)"
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import pytest
|
|
3
|
+
from v2kit import parse
|
|
4
|
+
from v2kit import ShadowsocksConfig
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_defaults():
|
|
8
|
+
config = ShadowsocksConfig(
|
|
9
|
+
encryption="aes-256-gcm",
|
|
10
|
+
password="password",
|
|
11
|
+
address="example.com",
|
|
12
|
+
port=8388,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
assert config.label is None
|
|
16
|
+
assert config.extra == {}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_to_dict():
|
|
20
|
+
config = ShadowsocksConfig(
|
|
21
|
+
encryption="aes-256-gcm",
|
|
22
|
+
password="password",
|
|
23
|
+
address="example.com",
|
|
24
|
+
port=8388,
|
|
25
|
+
label="test",
|
|
26
|
+
extra={"plugin": "v2ray-plugin"},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
assert config.to_dict() == {
|
|
30
|
+
"protocol": "shadowsocks",
|
|
31
|
+
"encryption": "aes-256-gcm",
|
|
32
|
+
"password": "password",
|
|
33
|
+
"address": "example.com",
|
|
34
|
+
"port": 8388,
|
|
35
|
+
"label": "test",
|
|
36
|
+
"extra": {"plugin": "v2ray-plugin"},
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_extra():
|
|
41
|
+
config = ShadowsocksConfig(
|
|
42
|
+
encryption="aes-256-gcm",
|
|
43
|
+
password="password",
|
|
44
|
+
address="example.com",
|
|
45
|
+
port=8388,
|
|
46
|
+
extra={"plugin": "v2ray-plugin"},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
data = config.to_dict()
|
|
50
|
+
|
|
51
|
+
assert data["extra"]["plugin"] == "v2ray-plugin"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_method_chaining():
|
|
55
|
+
config = ShadowsocksConfig(
|
|
56
|
+
encryption="aes-256-gcm",
|
|
57
|
+
password="password",
|
|
58
|
+
address="example.com",
|
|
59
|
+
port=8388,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
config.update_encryption(
|
|
63
|
+
"chacha20-ietf-poly1305"
|
|
64
|
+
).update_password(
|
|
65
|
+
"secret"
|
|
66
|
+
).update_address(
|
|
67
|
+
"example.org"
|
|
68
|
+
).update_port(
|
|
69
|
+
443
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
assert config.encryption == "chacha20-ietf-poly1305"
|
|
73
|
+
assert config.password == "secret"
|
|
74
|
+
assert config.address == "example.org"
|
|
75
|
+
assert config.port == 443
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@pytest.mark.parametrize(
|
|
79
|
+
"kwargs",
|
|
80
|
+
[
|
|
81
|
+
{"encryption": ""},
|
|
82
|
+
{"password": ""},
|
|
83
|
+
{"address": ""},
|
|
84
|
+
{"port": 0},
|
|
85
|
+
{"port": 1.2},
|
|
86
|
+
{"extra": 1},
|
|
87
|
+
],
|
|
88
|
+
)
|
|
89
|
+
def test_invalid_values(kwargs):
|
|
90
|
+
params = {
|
|
91
|
+
"encryption": "aes-256-gcm",
|
|
92
|
+
"password": "password",
|
|
93
|
+
"address": "example.com",
|
|
94
|
+
"port": 8388,
|
|
95
|
+
}
|
|
96
|
+
params.update(kwargs)
|
|
97
|
+
|
|
98
|
+
with pytest.raises(ValueError):
|
|
99
|
+
ShadowsocksConfig(**params)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_to_uri_roundtrip():
|
|
103
|
+
config = ShadowsocksConfig(
|
|
104
|
+
encryption="aes-256-gcm",
|
|
105
|
+
password="password",
|
|
106
|
+
address="example.com",
|
|
107
|
+
port=8388,
|
|
108
|
+
label="test",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
parsed = parse(config.to_uri())
|
|
112
|
+
|
|
113
|
+
assert parsed == config
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def test_equality():
|
|
117
|
+
config1 = ShadowsocksConfig(
|
|
118
|
+
encryption="aes-256-gcm",
|
|
119
|
+
password="password",
|
|
120
|
+
address="example.com",
|
|
121
|
+
port=8388,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
config2 = ShadowsocksConfig(
|
|
125
|
+
encryption="aes-256-gcm",
|
|
126
|
+
password="password",
|
|
127
|
+
address="example.com",
|
|
128
|
+
port=8388,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
config3 = ShadowsocksConfig(
|
|
132
|
+
encryption="aes-256-gcm",
|
|
133
|
+
password="password",
|
|
134
|
+
address="example.org",
|
|
135
|
+
port=8388,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
assert config1 == config2
|
|
139
|
+
assert config1 != config3
|
|
140
|
+
assert config1 != "config1"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_repr():
|
|
144
|
+
config = ShadowsocksConfig(
|
|
145
|
+
encryption="aes-256-gcm",
|
|
146
|
+
password="password",
|
|
147
|
+
address="example.com",
|
|
148
|
+
port=8388,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
assert repr(config) == (
|
|
152
|
+
"ShadowsocksConfig(protocol=<Protocol.SHADOWSOCKS: "
|
|
153
|
+
"'ss'>, label=None)"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_update_extra():
|
|
158
|
+
config = ShadowsocksConfig(
|
|
159
|
+
encryption="aes-256-gcm",
|
|
160
|
+
password="password",
|
|
161
|
+
address="example.com",
|
|
162
|
+
port=8388,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
config.update_extra(
|
|
166
|
+
{"plugin": "v2ray-plugin"}
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
assert config.extra["plugin"] == "v2ray-plugin"
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_update_methods():
|
|
173
|
+
config = ShadowsocksConfig(
|
|
174
|
+
encryption="aes-256-gcm",
|
|
175
|
+
password="password",
|
|
176
|
+
address="example.com",
|
|
177
|
+
port=8388,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
config.update_encryption(
|
|
181
|
+
"chacha20-ietf-poly1305"
|
|
182
|
+
)
|
|
183
|
+
config.update_password(
|
|
184
|
+
"secret"
|
|
185
|
+
)
|
|
186
|
+
config.update_address(
|
|
187
|
+
"example.org"
|
|
188
|
+
)
|
|
189
|
+
config.update_port(
|
|
190
|
+
443
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
assert config.encryption == "chacha20-ietf-poly1305"
|
|
194
|
+
assert config.password == "secret"
|
|
195
|
+
assert config.address == "example.org"
|
|
196
|
+
assert config.port == 443
|