-
Notifications
You must be signed in to change notification settings - Fork 25
/
trojan-url.py
executable file
·124 lines (116 loc) · 4.25 KB
/
trojan-url.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env python3
# Trojan-url is a tool for encoding and decoding trojan URLs from and to trojan
# config. Trojan is an unidentifiable mechanism that helps you bypass GFW.
# Copyright (C) 2018 GreaterFire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import argparse
import json
import qrcode
import urllib.parse as urlparse
DEFAULT_CONFIG = """{
"run_type": "client",
"local_addr": "127.0.0.1",
"local_port": 1080,
"remote_addr": "example.com",
"remote_port": 443,
"password": [
"password1"
],
"log_level": 1,
"ssl": {
"verify": true,
"verify_hostname": true,
"cert": "",
"cipher": "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
"cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
"sni": "",
"alpn": [
"h2",
"http/1.1"
],
"reuse_session": true,
"session_ticket": false,
"curves": ""
},
"tcp": {
"no_delay": true,
"keep_alive": true,
"reuse_port": false,
"fast_open": false,
"fast_open_qlen": 20
}
}
"""
def fail(msg):
print(msg, file=sys.stderr)
sys.exit(1)
def encode(qr):
try:
config = json.load(sys.stdin)
if config['run_type'] != 'client':
fail('Please provide a client config')
if ':' in config['remote_addr']:
config['remote_addr'] = '[{}]'.format(config['remote_addr'])
url = 'trojan://{}@{}:{}'.format(urlparse.quote(config['password'][0], safe=':') ,config['remote_addr'], config['remote_port'])
except:
fail('Invalid config')
if qr:
qrcode.make(url).save(sys.stdout, 'PNG')
else:
print(url)
def decode():
url = urlparse.urlparse(sys.stdin.read().strip('\n'))
if url.scheme != 'trojan':
fail('Not trojan URL')
try:
password, addr_port = url.netloc.split('@')
password = urlparse.unquote(password)
addr, port = addr_port.rsplit(':', 1)
if addr[0] == '[':
addr = addr[1:-1]
port = int(port)
except:
fail('Invalid trojan URL')
config = json.loads(DEFAULT_CONFIG)
config['remote_addr'] = addr
config['remote_port'] = port
config['password'][0] = password
json.dump(config, sys.stdout, indent=4)
def main():
parser = argparse.ArgumentParser(description='Encode and decode trojan URLs from and to trojan config.')
parser.add_argument('-d', '--decode', action='store_true', help='decode input')
parser.add_argument('-q', '--qrcode', action='store_true', help='output qrcode')
parser.add_argument('-i', '--input', default='-', metavar='in_file', help='input file (default: "-" for stdin)')
parser.add_argument('-o', '--output', default='-', metavar='out_file', help='output file (default: "-" for stdout)')
args = parser.parse_args()
if args.qrcode:
if args.decode:
fail('Decoding QRCode is not supported')
if args.output == '-':
fail('Please output QRCode to a file')
if args.input != '-':
sys.stdin = open(args.input, 'r')
if args.output != '-':
if args.qrcode:
sys.stdout = open(args.output, 'wb')
else:
sys.stdout = open(args.output, 'w')
if args.decode:
decode()
else:
encode(args.qrcode)
if __name__ == '__main__':
main()