wnum commited on
Commit
ddfa897
1 Parent(s): efd3c2b

Upload 2 files

Browse files
Files changed (2) hide show
  1. Dockerfile +1 -0
  2. settings.py +198 -0
Dockerfile CHANGED
@@ -3,6 +3,7 @@ FROM python:3-alpine
3
  LABEL maintainer='<author>'
4
  LABEL version='0.0.0-dev.0-build.0'
5
  RUN apk update && apk add git && git clone https://github.com/huashengdun/webssh.git /code
 
6
  WORKDIR /code
7
  RUN \
8
  apk add --no-cache libc-dev libffi-dev gcc && \
 
3
  LABEL maintainer='<author>'
4
  LABEL version='0.0.0-dev.0-build.0'
5
  RUN apk update && apk add git && git clone https://github.com/huashengdun/webssh.git /code
6
+ COPY settings.py /code/webssh/settings.py
7
  WORKDIR /code
8
  RUN \
9
  apk add --no-cache libc-dev libffi-dev gcc && \
settings.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os.path
3
+ import ssl
4
+ import sys
5
+
6
+ from tornado.options import define
7
+ from webssh.policy import (
8
+ load_host_keys, get_policy_class, check_policy_setting
9
+ )
10
+ from webssh.utils import (
11
+ to_ip_address, parse_origin_from_url, is_valid_encoding
12
+ )
13
+ from webssh._version import __version__
14
+
15
+
16
+ def print_version(flag):
17
+ if flag:
18
+ print(__version__)
19
+ sys.exit(0)
20
+
21
+
22
+ define('address', default='', help='Listen address')
23
+ define('port', type=int, default=8888, help='Listen port')
24
+ define('ssladdress', default='', help='SSL listen address')
25
+ define('sslport', type=int, default=4433, help='SSL listen port')
26
+ define('certfile', default='', help='SSL certificate file')
27
+ define('keyfile', default='', help='SSL private key file')
28
+ define('debug', type=bool, default=False, help='Debug mode')
29
+ define('policy', default='warning',
30
+ help='Missing host key policy, reject|autoadd|warning')
31
+ define('hostfile', default='', help='User defined host keys file')
32
+ define('syshostfile', default='', help='System wide host keys file')
33
+ define('tdstream', default='', help='Trusted downstream, separated by comma')
34
+ define('redirect', type=bool, default=True, help='Redirecting http to https')
35
+ define('fbidhttp', type=bool, default=True,
36
+ help='Forbid public plain http incoming requests')
37
+ define('xheaders', type=bool, default=True, help='Support xheaders')
38
+ define('xsrf', type=bool, default=True, help='CSRF protection')
39
+ define('origin', default='same', help='''Origin policy,
40
+ 'same': same origin policy, matches host name and port number;
41
+ 'primary': primary domain policy, matches primary domain only;
42
+ '<domains>': custom domains policy, matches any domain in the <domains> list
43
+ separated by comma;
44
+ '*': wildcard policy, matches any domain, allowed in debug mode only.''')
45
+ define('wpintvl', type=float, default=0, help='Websocket ping interval')
46
+ define('timeout', type=float, default=3, help='SSH connection timeout')
47
+ define('delay', type=float, default=3, help='The delay to call recycle_worker')
48
+ define('maxconn', type=int, default=20,
49
+ help='Maximum live connections (ssh sessions) per client')
50
+ define('font', default='', help='custom font filename')
51
+ define('encoding', default='utf-8',
52
+ help='''The default character encoding of ssh servers.
53
+ Example: --encoding='utf-8' to solve the problem with some switches&routers''')
54
+ define('version', type=bool, help='Show version information',
55
+ callback=print_version)
56
+
57
+
58
+ base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
59
+ font_dirs = ['webssh', 'static', 'css', 'fonts']
60
+ max_body_size = 1 * 1024 * 1024
61
+
62
+
63
+ class Font(object):
64
+
65
+ def __init__(self, filename, dirs):
66
+ self.family = self.get_family(filename)
67
+ self.url = self.get_url(filename, dirs)
68
+
69
+ def get_family(self, filename):
70
+ return filename.split('.')[0]
71
+
72
+ def get_url(self, filename, dirs):
73
+ return '/'.join(dirs + [filename])
74
+
75
+
76
+ def get_app_settings(options):
77
+ settings = dict(
78
+ template_path=os.path.join(base_dir, 'webssh', 'templates'),
79
+ static_path=os.path.join(base_dir, 'webssh', 'static'),
80
+ websocket_ping_interval=options.wpintvl,
81
+ debug=options.debug,
82
+ xsrf_cookies=options.xsrf,
83
+ font=Font(
84
+ get_font_filename(options.font,
85
+ os.path.join(base_dir, *font_dirs)),
86
+ font_dirs[1:]
87
+ ),
88
+ origin_policy=get_origin_setting(options)
89
+ )
90
+ return settings
91
+
92
+
93
+ def get_server_settings(options):
94
+ settings = dict(
95
+ xheaders=options.xheaders,
96
+ max_body_size=max_body_size,
97
+ trusted_downstream=get_trusted_downstream(options.tdstream)
98
+ )
99
+ return settings
100
+
101
+
102
+ def get_host_keys_settings(options):
103
+ if not options.hostfile:
104
+ host_keys_filename = os.path.join(base_dir, 'known_hosts')
105
+ else:
106
+ host_keys_filename = options.hostfile
107
+ host_keys = load_host_keys(host_keys_filename)
108
+
109
+ if not options.syshostfile:
110
+ filename = os.path.expanduser('~/.ssh/known_hosts')
111
+ else:
112
+ filename = options.syshostfile
113
+ system_host_keys = load_host_keys(filename)
114
+
115
+ settings = dict(
116
+ host_keys=host_keys,
117
+ system_host_keys=system_host_keys,
118
+ host_keys_filename=host_keys_filename
119
+ )
120
+ return settings
121
+
122
+
123
+ def get_policy_setting(options, host_keys_settings):
124
+ policy_class = get_policy_class(options.policy)
125
+ logging.info(policy_class.__name__)
126
+ check_policy_setting(policy_class, host_keys_settings)
127
+ return policy_class()
128
+
129
+
130
+ def get_ssl_context(options):
131
+ if not options.certfile and not options.keyfile:
132
+ return None
133
+ elif not options.certfile:
134
+ raise ValueError('certfile is not provided')
135
+ elif not options.keyfile:
136
+ raise ValueError('keyfile is not provided')
137
+ elif not os.path.isfile(options.certfile):
138
+ raise ValueError('File {!r} does not exist'.format(options.certfile))
139
+ elif not os.path.isfile(options.keyfile):
140
+ raise ValueError('File {!r} does not exist'.format(options.keyfile))
141
+ else:
142
+ ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
143
+ ssl_ctx.load_cert_chain(options.certfile, options.keyfile)
144
+ return ssl_ctx
145
+
146
+
147
+ def get_trusted_downstream(tdstream):
148
+ result = set()
149
+ for ip in tdstream.split(','):
150
+ ip = ip.strip()
151
+ if ip:
152
+ to_ip_address(ip)
153
+ result.add(ip)
154
+ return result
155
+
156
+
157
+ def get_origin_setting(options):
158
+ if options.origin == '*':
159
+ if not options.debug:
160
+ raise ValueError(
161
+ 'Wildcard origin policy is only allowed in debug mode.'
162
+ )
163
+ else:
164
+ return '*'
165
+
166
+ origin = options.origin.lower()
167
+ if origin in ['same', 'primary']:
168
+ return origin
169
+
170
+ origins = set()
171
+ for url in origin.split(','):
172
+ orig = parse_origin_from_url(url)
173
+ if orig:
174
+ origins.add(orig)
175
+
176
+ if not origins:
177
+ raise ValueError('Empty origin list')
178
+
179
+ return origins
180
+
181
+
182
+ def get_font_filename(font, font_dir):
183
+ filenames = {f for f in os.listdir(font_dir) if not f.startswith('.')
184
+ and os.path.isfile(os.path.join(font_dir, f))}
185
+ if font:
186
+ if font not in filenames:
187
+ raise ValueError(
188
+ 'Font file {!r} not found'.format(os.path.join(font_dir, font))
189
+ )
190
+ elif filenames:
191
+ font = filenames.pop()
192
+
193
+ return font
194
+
195
+
196
+ def check_encoding_setting(encoding):
197
+ if encoding and not is_valid_encoding(encoding):
198
+ raise ValueError('Unknown character encoding {!r}.'.format(encoding))