InPanel 1.2.1__py3-none-any.whl

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.
Files changed (198) hide show
  1. inpanel/__init__.py +29 -0
  2. inpanel/acme.py +289 -0
  3. inpanel/aliyuncs.py +269 -0
  4. inpanel/app.py +514 -0
  5. inpanel/apt.py +223 -0
  6. inpanel/base.py +200 -0
  7. inpanel/config.py +139 -0
  8. inpanel/data/config.ini +29 -0
  9. inpanel/data/history +5 -0
  10. inpanel/data/runlogs.ini +12 -0
  11. inpanel/data/update_info.ini +4 -0
  12. inpanel/dnf.py +225 -0
  13. inpanel/lib/__init__.py +9 -0
  14. inpanel/lib/async_process.py +98 -0
  15. inpanel/lib/filelock.py +82 -0
  16. inpanel/lib/magic.py +233 -0
  17. inpanel/lib/pxssh.py +310 -0
  18. inpanel/lib/pyDes.py +867 -0
  19. inpanel/mod/__init__.py +0 -0
  20. inpanel/mod/apt.py +316 -0
  21. inpanel/mod/certificate.py +268 -0
  22. inpanel/mod/config.py +372 -0
  23. inpanel/mod/cron.py +315 -0
  24. inpanel/mod/disk.py +322 -0
  25. inpanel/mod/dnf.py +239 -0
  26. inpanel/mod/file.py +722 -0
  27. inpanel/mod/firewall.py +199 -0
  28. inpanel/mod/firewall_base.py +137 -0
  29. inpanel/mod/firewall_firewalld.py +170 -0
  30. inpanel/mod/firewall_iptables.py +176 -0
  31. inpanel/mod/firewall_macos.py +213 -0
  32. inpanel/mod/firewall_ufw.py +128 -0
  33. inpanel/mod/ftp.py +231 -0
  34. inpanel/mod/httpd.py +1205 -0
  35. inpanel/mod/lighttpd.py +26 -0
  36. inpanel/mod/login.py +98 -0
  37. inpanel/mod/mysql.py +577 -0
  38. inpanel/mod/named.py +26 -0
  39. inpanel/mod/nginx.py +2327 -0
  40. inpanel/mod/package.py +33 -0
  41. inpanel/mod/package_apt.py +62 -0
  42. inpanel/mod/package_base.py +77 -0
  43. inpanel/mod/package_dnf.py +62 -0
  44. inpanel/mod/package_map.py +366 -0
  45. inpanel/mod/package_yum.py +64 -0
  46. inpanel/mod/php.py +289 -0
  47. inpanel/mod/process.py +291 -0
  48. inpanel/mod/proftpd.py +26 -0
  49. inpanel/mod/pureftpd.py +26 -0
  50. inpanel/mod/query.py +108 -0
  51. inpanel/mod/server.py +1319 -0
  52. inpanel/mod/service.py +262 -0
  53. inpanel/mod/setting.py +228 -0
  54. inpanel/mod/shell.py +78 -0
  55. inpanel/mod/ssh.py +280 -0
  56. inpanel/mod/system.py +220 -0
  57. inpanel/mod/task.py +1337 -0
  58. inpanel/mod/ufw.py +14 -0
  59. inpanel/mod/user.py +306 -0
  60. inpanel/mod/vsftpd.py +67 -0
  61. inpanel/mod/yum.py +243 -0
  62. inpanel/plugins/__init__.py +10 -0
  63. inpanel/plugins/__pycache__/__init__.cpython-313.pyc +0 -0
  64. inpanel/plugins/acme/static/index.html +10 -0
  65. inpanel/plugins/acme/static/index.js +13 -0
  66. inpanel/plugins/shadowsocks-libev/__pycache__/info.cpython-313.pyc +0 -0
  67. inpanel/plugins/shadowsocks-libev/info.py +73 -0
  68. inpanel/plugins/shadowsocks-libev/static/index.html +70 -0
  69. inpanel/plugins/shadowsocks-libev/static/index.js +18 -0
  70. inpanel/public/css/global.css +138 -0
  71. inpanel/public/favicon.ico +0 -0
  72. inpanel/public/images/alipay.jpg +0 -0
  73. inpanel/public/images/loading.gif +0 -0
  74. inpanel/public/images/weixin.jpg +0 -0
  75. inpanel/public/index.html +94 -0
  76. inpanel/public/js/controllers/controllers.js +566 -0
  77. inpanel/public/js/controllers/database.js +590 -0
  78. inpanel/public/js/controllers/ecs.js +624 -0
  79. inpanel/public/js/controllers/file.js +940 -0
  80. inpanel/public/js/controllers/plugins.js +105 -0
  81. inpanel/public/js/controllers/service.js +1460 -0
  82. inpanel/public/js/controllers/site.js +1241 -0
  83. inpanel/public/js/controllers/utils.js +2319 -0
  84. inpanel/public/js/core.js +221 -0
  85. inpanel/public/js/directives.js +784 -0
  86. inpanel/public/js/filters.js +395 -0
  87. inpanel/public/js/services.js +257 -0
  88. inpanel/public/lib/angular/1.0.2/angular-resource.min.js +10 -0
  89. inpanel/public/lib/angular/1.0.2/angular.min.js +158 -0
  90. inpanel/public/lib/bootstrap/css/bootstrap-theme.css +587 -0
  91. inpanel/public/lib/bootstrap/css/bootstrap-theme.css.map +1 -0
  92. inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css +6 -0
  93. inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css.map +1 -0
  94. inpanel/public/lib/bootstrap/css/bootstrap.css +6757 -0
  95. inpanel/public/lib/bootstrap/css/bootstrap.css.map +1 -0
  96. inpanel/public/lib/bootstrap/css/bootstrap.min.css +6 -0
  97. inpanel/public/lib/bootstrap/css/bootstrap.min.css.map +1 -0
  98. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
  99. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
  100. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
  101. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
  102. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
  103. inpanel/public/lib/bootstrap/img/glyphicons-halflings-white.png +0 -0
  104. inpanel/public/lib/bootstrap/img/glyphicons-halflings.png +0 -0
  105. inpanel/public/lib/bootstrap/js/bootstrap.js +2377 -0
  106. inpanel/public/lib/bootstrap/js/bootstrap.min.js +7 -0
  107. inpanel/public/lib/bootstrap/js/npm.js +13 -0
  108. inpanel/public/lib/codemirror/codemirror-compressed.js +1 -0
  109. inpanel/public/lib/codemirror/codemirror.css +173 -0
  110. inpanel/public/lib/jquery/jquery-1.12.4.min.js +5 -0
  111. inpanel/public/lib/md5/md5.js +379 -0
  112. inpanel/public/lib/md5/md5.min.js +1 -0
  113. inpanel/public/partials/database/index.html +172 -0
  114. inpanel/public/partials/database/mysql/dbedit.html +462 -0
  115. inpanel/public/partials/database/mysql/dbnew.html +348 -0
  116. inpanel/public/partials/database/mysql/useredit.html +310 -0
  117. inpanel/public/partials/database/mysql/usernew.html +97 -0
  118. inpanel/public/partials/directives/message.html +20 -0
  119. inpanel/public/partials/directives/navbar.html +25 -0
  120. inpanel/public/partials/directives/selector.html +57 -0
  121. inpanel/public/partials/directives/srvbase.html +72 -0
  122. inpanel/public/partials/directives/srvext.html +34 -0
  123. inpanel/public/partials/directives/srvfile.html +23 -0
  124. inpanel/public/partials/directives/srvinstall.html +34 -0
  125. inpanel/public/partials/directives/srvlog.html +23 -0
  126. inpanel/public/partials/directives/srvminiop.html +28 -0
  127. inpanel/public/partials/directives/srvuninstall.html +38 -0
  128. inpanel/public/partials/directives/srvupdate.html +30 -0
  129. inpanel/public/partials/ecs/account.html +156 -0
  130. inpanel/public/partials/ecs/ecs.html +198 -0
  131. inpanel/public/partials/ecs/index.html +40 -0
  132. inpanel/public/partials/ecs/setings.html +459 -0
  133. inpanel/public/partials/file/file.html +501 -0
  134. inpanel/public/partials/file/trash.html +95 -0
  135. inpanel/public/partials/ftp.html +36 -0
  136. inpanel/public/partials/log.html +83 -0
  137. inpanel/public/partials/login.html +79 -0
  138. inpanel/public/partials/logout.html +22 -0
  139. inpanel/public/partials/main.html +534 -0
  140. inpanel/public/partials/plugins/index.html +55 -0
  141. inpanel/public/partials/plugins/plugins.html +13 -0
  142. inpanel/public/partials/secure.html +13 -0
  143. inpanel/public/partials/service/apache.html +147 -0
  144. inpanel/public/partials/service/cron.html +71 -0
  145. inpanel/public/partials/service/index.html +293 -0
  146. inpanel/public/partials/service/iptables.html +40 -0
  147. inpanel/public/partials/service/lighttpd.html +63 -0
  148. inpanel/public/partials/service/mariadb.html +113 -0
  149. inpanel/public/partials/service/memcache.html +36 -0
  150. inpanel/public/partials/service/minio.html +44 -0
  151. inpanel/public/partials/service/mongodb.html +44 -0
  152. inpanel/public/partials/service/mysql.html +113 -0
  153. inpanel/public/partials/service/named.html +61 -0
  154. inpanel/public/partials/service/nginx.html +296 -0
  155. inpanel/public/partials/service/ntp.html +40 -0
  156. inpanel/public/partials/service/php.html +250 -0
  157. inpanel/public/partials/service/proftpd.html +59 -0
  158. inpanel/public/partials/service/pureftpd.html +59 -0
  159. inpanel/public/partials/service/redis.html +40 -0
  160. inpanel/public/partials/service/samba.html +58 -0
  161. inpanel/public/partials/service/sendmail.html +40 -0
  162. inpanel/public/partials/service/ssh.html +186 -0
  163. inpanel/public/partials/service/tomcat.html +65 -0
  164. inpanel/public/partials/service/vsftpd.html +195 -0
  165. inpanel/public/partials/setting.html +299 -0
  166. inpanel/public/partials/site/apache/site.html +277 -0
  167. inpanel/public/partials/site/index.html +344 -0
  168. inpanel/public/partials/site/nginx/site.html +558 -0
  169. inpanel/public/partials/sorry.html +19 -0
  170. inpanel/public/partials/storage/autofm.html +103 -0
  171. inpanel/public/partials/storage/backup.html +42 -0
  172. inpanel/public/partials/storage/index.html +360 -0
  173. inpanel/public/partials/storage/migrate.html +93 -0
  174. inpanel/public/partials/storage/movedata.html +98 -0
  175. inpanel/public/partials/storage/remote.html +77 -0
  176. inpanel/public/partials/utils/cron.html +486 -0
  177. inpanel/public/partials/utils/firewall.html +266 -0
  178. inpanel/public/partials/utils/index.html +193 -0
  179. inpanel/public/partials/utils/network.html +118 -0
  180. inpanel/public/partials/utils/process.html +239 -0
  181. inpanel/public/partials/utils/repository.html +373 -0
  182. inpanel/public/partials/utils/shell.html +28 -0
  183. inpanel/public/partials/utils/ssl.html +319 -0
  184. inpanel/public/partials/utils/time.html +109 -0
  185. inpanel/public/partials/utils/user.html +359 -0
  186. inpanel/public/robots.txt +2 -0
  187. inpanel/remote.py +109 -0
  188. inpanel/templates/file/preview.html +34 -0
  189. inpanel/templates/index.html +93 -0
  190. inpanel/utils.py +282 -0
  191. inpanel/web.py +1811 -0
  192. inpanel/yum.py +756 -0
  193. inpanel-1.2.1.dist-info/METADATA +399 -0
  194. inpanel-1.2.1.dist-info/RECORD +198 -0
  195. inpanel-1.2.1.dist-info/WHEEL +5 -0
  196. inpanel-1.2.1.dist-info/entry_points.txt +2 -0
  197. inpanel-1.2.1.dist-info/licenses/LICENSE +30 -0
  198. inpanel-1.2.1.dist-info/top_level.txt +1 -0
inpanel/__init__.py ADDED
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (c) 2017-2026 Jackson Dou
4
+ # All rights reserved.
5
+ #
6
+ # InPanel is distributed under the terms of the (new) BSD License.
7
+ # The full license can be found in 'LICENSE'.
8
+
9
+ from .base import (
10
+ __version__,
11
+ __author__,
12
+ __license__,
13
+ app_name,
14
+ version_info,
15
+ server_info,
16
+ DEBUG,
17
+ run_type,
18
+ )
19
+
20
+ __all__ = [
21
+ '__version__',
22
+ '__author__',
23
+ '__license__',
24
+ 'app_name',
25
+ 'version_info',
26
+ 'server_info',
27
+ 'DEBUG',
28
+ 'run_type',
29
+ ]
inpanel/acme.py ADDED
@@ -0,0 +1,289 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (c) 2017-2026 Jackson Dou
4
+ # All rights reserved.
5
+ #
6
+ # InPanel is distributed under the terms of the New BSD License.
7
+ # The full license can be found in 'LICENSE'.
8
+
9
+ '''Module for getting a signed TLS certificate by ACME protocol from Let's Encrypt.'''
10
+
11
+ import re
12
+ from base64 import urlsafe_b64encode
13
+ from binascii import unhexlify
14
+ from hashlib import sha256
15
+ from json import dumps, loads
16
+ from pathlib import Path
17
+ import os
18
+ from subprocess import PIPE, STDOUT, Popen
19
+ from time import sleep
20
+
21
+ try:
22
+ from urllib.request import urlopen, Request # Python 3
23
+ except ImportError:
24
+ from urllib2 import urlopen, Request # Python 2
25
+
26
+
27
+ class ACME():
28
+
29
+ # REF: https://github.com/diafygi/acme-tiny, under MIT license, author: Daniel Roesler
30
+ def __init__(self, account_key, csr, acme_check_dir, contact=None):
31
+ self.account_key = account_key
32
+ self.csr = csr
33
+ self.acme_check_dir = acme_check_dir
34
+ self.directory = None
35
+ self.acct_headers = None
36
+ self.alg = 'RS256'
37
+ self.jwk = None
38
+ self.thumbprint = None
39
+ self.certificate = None
40
+
41
+ # Contact details (e.g. mailto:aaa@bbb.com) for your account-key
42
+ self.contact = contact # 'a client of the InPanel'
43
+ # self.ca = "https://acme-v02.api.letsencrypt.org"
44
+ # self.ca_directory = = "https://acme-v02.api.letsencrypt.org/directory"
45
+ # dev
46
+ self.ca = "https://acme-staging-v02.api.letsencrypt.org"
47
+ # certificate authority directory url, default is Let's Encrypt
48
+ self.ca_directory = "https://acme-staging-v02.api.letsencrypt.org/directory"
49
+
50
+ self.init_api_url()
51
+ self.init_account()
52
+ self.registe_account()
53
+ self.parse_csr(order=True)
54
+ # self.create_new_order()
55
+
56
+ def _cmd(self, cmd_list, stdin=None, cmd_input=None, err_msg="Command Line Error"):
57
+ '''run external commands'''
58
+ proc = Popen(cmd_list, stdin=stdin, stdout=PIPE, stderr=PIPE)
59
+ out, err = proc.communicate(cmd_input)
60
+ if proc.returncode != 0:
61
+ raise IOError("{0}\n{1}".format(err_msg, err))
62
+ return out
63
+
64
+ def _b64(self, b):
65
+ '''base64 encode for jose spec'''
66
+ return urlsafe_b64encode(b).decode('utf8').replace('=', '')
67
+
68
+ def _request(self, url, data=None, err_msg='Error', depth=0):
69
+ '''make request and automatically parse json response'''
70
+ try:
71
+ hd = {
72
+ "Content-Type": "application/jose+json",
73
+ "User-Agent": "inpanel"
74
+ }
75
+ res = urlopen(Request(url, data=data, headers=hd))
76
+ res_data = res.read().decode('utf8')
77
+ code = res.getcode()
78
+ headers = res.headers
79
+ except IOError as e:
80
+ res_data = e.read().decode('utf8') if hasattr(e, 'read') else str(e)
81
+ code, headers = getattr(e, 'code', None), {}
82
+ try:
83
+ res_data = loads(res_data) # try to parse json results
84
+ except ValueError:
85
+ pass # ignore json parsing errors
86
+ if depth < 100 and code == 400 and res_data['type'] == 'urn:ietf:params:acme:error:badNonce':
87
+ raise IndexError(res_data) # allow 100 retrys for bad nonces
88
+ if code not in [200, 201, 204]:
89
+ raise ValueError("{0}:\nUrl: {1}\nData: {2}\nResponse Code: {3}\nResponse: {4}".format(
90
+ err_msg, url, data, code, res_data))
91
+ return res_data, code, headers
92
+
93
+ def _s_request(self, url, payload, err_msg, depth=0):
94
+ '''make signed requests'''
95
+ payload64 = self._b64(dumps(payload).encode('utf8'))
96
+ new_nonce = self._request(self.ca_new_nonce)[2]['Replay-Nonce']
97
+ protected = {'url': url, 'alg': self.alg, "nonce": new_nonce}
98
+ protected.update({"jwk": self.jwk} if self.acct_headers is None else {"kid": self.acct_headers['Location']})
99
+ protected64 = self._b64(dumps(protected).encode('utf8'))
100
+ protected_input = "{0}.{1}".format(protected64, payload64).encode('utf8')
101
+ cmd = ['openssl', 'dgst', '-sha256', '-sign', self.account_key]
102
+ out = self._cmd(cmd, stdin=PIPE, cmd_input=protected_input, err_msg='OpenSSL Error')
103
+ data = dumps({
104
+ 'protected': protected64,
105
+ 'payload': payload64,
106
+ 'signature': self._b64(out)
107
+ })
108
+ try:
109
+ return self._request(url, data=data.encode('utf8'), err_msg=err_msg, depth=depth)
110
+ except IndexError: # retry bad nonces (they raise IndexError)
111
+ return self._s_request(url, payload, err_msg, depth=(depth + 1))
112
+
113
+ # helper function - poll until complete
114
+ def _poll_until_not(self, url, pending_statuses, err_msg):
115
+ while True:
116
+ result, _, _ = self._request(url, err_msg=err_msg)
117
+ if result['status'] in pending_statuses:
118
+ sleep(2)
119
+ continue
120
+ return result
121
+
122
+ def init_api_url(self, ca_directory=None):
123
+ # get the ACME directory of urls
124
+ print('API directory getting...')
125
+ ca = ca_directory
126
+ if ca is None:
127
+ ca = self.ca_directory
128
+ ca_dir, _, _ = self._request(ca, err_msg='get directory error')
129
+ self.ca_new_account = ca_dir['newAccount']
130
+ self.ca_new_nonce = ca_dir['newNonce']
131
+ self.ca_new_order = ca_dir['newOrder']
132
+ self.ca_revoke_cert = ca_dir['revokeCert']
133
+ self.ca_key_change = ca_dir['keyChange']
134
+ self.directory = ca_dir
135
+ print('API directory ready!')
136
+
137
+ def init_account(self, account_key=None):
138
+ # parse account key to get public key
139
+ print('Account key parsing...')
140
+ acc_key = account_key
141
+ if acc_key is None:
142
+ acc_key = self.account_key
143
+ acc_key_path = Path(acc_key)
144
+ if not acc_key_path.exists() or not acc_key_path.is_file():
145
+ return None
146
+ cmd = ['openssl', 'rsa', '-in', acc_key, '-noout', '-text']
147
+ out = self._cmd(cmd, err_msg='openssl error')
148
+ pub_pattern = r"modulus:\n\s+00:([a-f0-9\:\s]+?)\npublicExponent: ([0-9]+)"
149
+ pub_hex, pub_exp = re.search(pub_pattern, out.decode('utf8'), re.MULTILINE | re.DOTALL).groups()
150
+ pub_exp = "{0:x}".format(int(pub_exp))
151
+ pub_exp = "0{0}".format(pub_exp) if len(pub_exp) % 2 else pub_exp
152
+ self.jwk = {
153
+ 'e': self._b64(unhexlify(pub_exp.encode('utf-8'))),
154
+ 'kty': 'RSA',
155
+ 'n': self._b64(unhexlify(re.sub(r"(\s|:)", '', pub_hex).encode('utf-8'))),
156
+ }
157
+ acc_key_json = dumps(self.jwk, sort_keys=True, separators=(',', ':'))
158
+ self.thumbprint = self._b64(sha256(acc_key_json.encode('utf8')).digest())
159
+ # print('thumbprint', self.thumbprint)
160
+ print('Account key ready...')
161
+
162
+ def registe_account(self, contact=None):
163
+ # create account, update contact details (if any), and set the global key identifier
164
+ print('Account registration...')
165
+ reg_payload = {'termsOfServiceAgreed': True}
166
+ account, code, self.acct_headers = self._s_request(
167
+ self.ca_new_account, reg_payload, 'Error registering')
168
+ if code == 201:
169
+ print('Account registration is successful !')
170
+ else:
171
+ print('Account is already registered!')
172
+ # print(self.acct_headers)
173
+ if contact is None:
174
+ contact = self.contact
175
+ if contact is not None:
176
+ url = self.acct_headers['Location']
177
+ payload = {'contact': contact}
178
+ account, _, _ = self._s_request(url, payload, 'Error updating contact details')
179
+ print(account)
180
+ print("Updated contact details:\n{0}".format("\n".join(account['contact'])))
181
+
182
+ def parse_csr(self, order=False):
183
+ # find domains
184
+ print('Domains CSR parsing...')
185
+ cmd = ['openssl', 'req', '-in', self.csr, '-noout', '-text']
186
+ out = self._cmd(cmd, err_msg="Error loading {0}".format(self.csr))
187
+ domains = set([])
188
+ common_name = re.search(r"Subject:.*? CN\s?=\s?([^\s,;/]+)", out.decode('utf8'))
189
+ if common_name is not None:
190
+ domains.add(common_name.group(1))
191
+ subject_alt_names = re.search(
192
+ r"X509v3 Subject Alternative Name: \n +([^\n]+)\n", out.decode('utf8'), re.MULTILINE | re.DOTALL)
193
+ if subject_alt_names is not None:
194
+ for san in subject_alt_names.group(1).split(", "):
195
+ if san.startswith("DNS:"):
196
+ domains.add(san[4:])
197
+ print("Found domains: {0}".format(", ".join(domains)))
198
+ # print('domains', domains)
199
+ if order == True:
200
+ self.create_new_order(domains)
201
+
202
+ def create_new_order(self, domains, disable_check=False):
203
+ '''create a new order
204
+ disable_check: disable checking if the challenge file is hosted correctly before telling the CA
205
+ '''
206
+ print("Creating new order...")
207
+ order_payload = {"identifiers": [
208
+ {"type": "dns", "value": d} for d in domains]}
209
+ order, _, order_headers = self._s_request(
210
+ self.ca_new_order, order_payload, "Error creating new order")
211
+ print("Order created!")
212
+
213
+ # get the authorizations that need to be completed
214
+ for auth_url in order['authorizations']:
215
+ authorization, _, _ = self._request(auth_url, err_msg='Error getting challenges')
216
+ domain = authorization['identifier']['value']
217
+ print("Domain {0} Verifying...".format(domain))
218
+
219
+ # find the http-01 challenge and write the challenge file
220
+ challenge = [c for c in authorization['challenges'] if c['type'] == "http-01"][0]
221
+ token = re.sub(r"[^A-Za-z0-9_\-]", "_", challenge['token'])
222
+ key_auth = "{0}.{1}".format(token, self.thumbprint)
223
+ wellknown_path = str(Path(self.acme_check_dir) / token)
224
+ with open(wellknown_path, 'w', encoding='utf-8') as f:
225
+ f.write(key_auth)
226
+
227
+ # check that the wellknown_file is in specified place
228
+ try:
229
+ wellknown_url = "http://{0}/.well-known/acme-challenge/{1}".format(domain, token)
230
+ assert(disable_check or self._request(wellknown_url)[0] == key_auth)
231
+ except (AssertionError, ValueError) as e:
232
+ os.remove(wellknown_path)
233
+ raise ValueError("Wrote file to {0}, but couldn't download {1}: {2}".format(
234
+ wellknown_path, wellknown_url, e))
235
+
236
+ # say the challenge is done
237
+ self._s_request(
238
+ challenge['url'], {}, "Error submitting challenges: {0}".format(domain))
239
+ authorization = self._poll_until_not(auth_url, ["pending"], "Error checking challenge status for {0}".format(domain))
240
+ if authorization['status'] != "valid":
241
+ raise ValueError("Challenge did not pass for {0}: {1}".format(domain, authorization))
242
+ print("Domain {0} verified!".format(domain))
243
+
244
+ # finalize the order with the csr
245
+ print('Certificate signing...')
246
+ csr_der = self._cmd(['openssl', 'req', '-in', self.csr, '-outform', 'DER'], err_msg='DER Export Error')
247
+ self._s_request(order['finalize'], {'csr': self._b64(csr_der)}, 'Error finalizing order')
248
+ # poll the order to monitor when it's done
249
+ order = self._poll_until_not(order_headers['Location'], ['pending', 'processing'], 'Error checking order status')
250
+ if order['status'] != 'valid':
251
+ raise ValueError("Order failed: {0}".format(order))
252
+ self.certificate = order['certificate']
253
+
254
+ def get_certificate(self, certificate=None):
255
+ # download the certificate
256
+ crt_url = self.certificate if certificate is None else certificate
257
+ if crt_url is None:
258
+ return None
259
+ certificate_pem, _, _ = self._request(crt_url, err_msg='Certificate download failed')
260
+ print('Certificate signed!')
261
+ return certificate_pem
262
+
263
+ def ertificate_revoke(self, crt):
264
+ '''revoke certificate'''
265
+ print(crt)
266
+ print('Certificate revoked!')
267
+
268
+ def certificate_renew(self, crt):
269
+ '''renew certificate'''
270
+ print(crt)
271
+ print('Certificate updated!')
272
+
273
+ # if __name__ == "__main__":
274
+ # # import certificate
275
+ # # cert = certificate.Certificate()
276
+ # # # # cert.create_domain_key('test.com')
277
+ # # cert.generate_domain_csr(['test.com', 'aaa.com'], forced=True)
278
+ # account_key = '/Users/douzhenjiang/Projects/inpanel/data/certificate/client.key'
279
+ # csr = '/Users/douzhenjiang/Projects/inpanel/data/certificate/csr/test.com.csr'
280
+ # acme_check_dir = '/Users/douzhenjiang/Projects/inpanel/data'
281
+ # # aaa = ACME(account_key, csr, acme_check_dir)
282
+
283
+ # key = '/Users/douzhenjiang/Projects/inpanel/test/example_com.key'
284
+ # csr = '/Users/douzhenjiang/Projects/inpanel/test/example_com.csr'
285
+ # aaa = ACME(key, csr, acme_check_dir)
286
+
287
+ # # C=CN, ST=Beijing, L=Beijing, O=Example Inc, OU=Network Dept,
288
+ # # CN=example.com/subjectAltName=DNS.1=sub1.example.com,DNS.2=sub2.example.com,DNS.3=sub.another-example.com
289
+ # # CN=test.com/subjectAltName=DNS:test.com,DNS:aaa.com
inpanel/aliyuncs.py ADDED
@@ -0,0 +1,269 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (c) 2017-2026 Jackson Dou
4
+ # All rights reserved.
5
+ #
6
+ # ECSMate is distributed under the terms of the (new) BSD License.
7
+ # The full license can be found in 'LICENSE'.
8
+
9
+ '''ECS SDK'''
10
+
11
+ import time
12
+ import hmac
13
+ import base64
14
+ import hashlib
15
+ import urllib
16
+ import json
17
+ import inspect
18
+ from random import random
19
+
20
+
21
+ class ECS(object):
22
+
23
+ def __init__(self, AccessKeyID, AccessKeySecret, gateway='https://ecs.aliyuncs.com'):
24
+ self.AccessKeyID = AccessKeyID
25
+ self.AccessKeySecret = AccessKeySecret
26
+ self.gateway = gateway
27
+
28
+ @classmethod
29
+ def _urlencode(self, string):
30
+ return urllib.quote(string, '~')
31
+
32
+ def _sign(self, params):
33
+ paramstrings = []
34
+ for k, v in sorted(params.items()):
35
+ paramstrings.append('%s=%s' %
36
+ (ECS._urlencode(k), ECS._urlencode(v)))
37
+ datastrings = [
38
+ ECS._urlencode('GET'),
39
+ ECS._urlencode('/'),
40
+ ECS._urlencode('&'.join(paramstrings)),
41
+ ]
42
+ datastring = '&'.join(datastrings)
43
+ signature = hmac.new(self.AccessKeySecret+'&',
44
+ datastring, hashlib.sha1).digest()
45
+ return base64.b64encode(signature)
46
+
47
+ def _http_get(self, params):
48
+ url = self.gateway + '/?'
49
+
50
+ sysparams = {
51
+ 'Format': 'JSON',
52
+ 'Version': '2012-09-13',
53
+ 'AccessKeyID': self.AccessKeyID,
54
+ 'SignatureMethod': 'HMAC-SHA1',
55
+ 'Timestamp': time.strftime('%Y-%m-%dT%XZ'),
56
+ 'SignatureVersion': '1.0',
57
+ 'SignatureNonce': str(random()).replace('0.', ''),
58
+ }
59
+ params.update(sysparams)
60
+ params['Signature'] = self._sign(params)
61
+ params = urllib.urlencode(params)
62
+
63
+ url += params
64
+ f = urllib.urlopen(url)
65
+ data = f.read()
66
+ f.close()
67
+
68
+ return json.loads(data)
69
+
70
+ def _parse_response(self, apiname, response):
71
+ if 'Error' in response:
72
+ respdata = response['Error']
73
+ reqid = respdata['RequestID']
74
+ del respdata['RequestID']
75
+ return [False, respdata, reqid]
76
+ else:
77
+ respdata = response[apiname+'Response']
78
+ return [True, respdata[apiname+'Result'], respdata['ResponseMetadata']['RequestID']]
79
+
80
+ def _make_params(self, params):
81
+ params = dict((k, str(v))
82
+ for k, v in params.items() if k != 'self' and v != None)
83
+ params['Action'] = inspect.stack()[1][3]
84
+ return params
85
+
86
+ def _execute(self, params):
87
+ response = self._http_get(params)
88
+ return self._parse_response(params['Action'], response)
89
+
90
+ def CreateInstance(self, RegionCode, DiskSize, InstanceType, GroupCode, ImageCode,
91
+ MaxBandwidthIn=None, MaxBandwidthOut=None, InstanceName=None, HostName=None,
92
+ Password=None, ZoneCode=None):
93
+ params = self._make_params(locals())
94
+ return self._execute(params)
95
+
96
+ def StartInstance(self, InstanceName):
97
+ params = self._make_params(locals())
98
+ return self._execute(params)
99
+
100
+ def StopInstance(self, InstanceName, ForceStop=None):
101
+ params = self._make_params(locals())
102
+ return self._execute(params)
103
+
104
+ def RebootInstance(self, InstanceName, ForceStop=None):
105
+ params = self._make_params(locals())
106
+ return self._execute(params)
107
+
108
+ def ResetInstance(self, InstanceName, ImageCode=None, DiskType=None):
109
+ params = self._make_params(locals())
110
+ return self._execute(params)
111
+
112
+ def ResetPassword(self, InstanceName, NewPassword=None):
113
+ params = self._make_params(locals())
114
+ return self._execute(params)
115
+
116
+ def DeleteInstance(self, InstanceName):
117
+ params = self._make_params(locals())
118
+ return self._execute(params)
119
+
120
+ def DescribeInstanceStatus(self, RegionCode=None, ZoneCode=None, PageNumber=None, PageSize=None):
121
+ params = self._make_params(locals())
122
+ return self._execute(params)
123
+
124
+ def DescribeInstanceAttribute(self, InstanceName):
125
+ params = self._make_params(locals())
126
+ return self._execute(params)
127
+
128
+ def ModifyInstanceAttribute(self, InstanceName, InstanceType):
129
+ params = self._make_params(locals())
130
+ return self._execute(params)
131
+
132
+ def ModifyBandwidth(self, InstanceName, MaxBandwidthOut, MaxBandwidthIn):
133
+ params = self._make_params(locals())
134
+ return self._execute(params)
135
+
136
+ def ModifyHostName(self, InstanceName, HostName):
137
+ params = self._make_params(locals())
138
+ return self._execute(params)
139
+
140
+ def CreateDisk(self, InstanceName, Size, SnapshotCode=None):
141
+ params = self._make_params(locals())
142
+ return self._execute(params)
143
+
144
+ def DeleteDisk(self, InstanceName, DiskCode):
145
+ params = self._make_params(locals())
146
+ return self._execute(params)
147
+
148
+ def DescribeDisks(self, InstanceName):
149
+ params = self._make_params(locals())
150
+ return self._execute(params)
151
+
152
+ def DescribeImages(self, RegionCode=None, PageNumber=None, PageSize=None):
153
+ params = self._make_params(locals())
154
+ return self._execute(params)
155
+
156
+ def AllocateAddress(self, InstanceName):
157
+ params = self._make_params(locals())
158
+ return self._execute(params)
159
+
160
+ def ReleaseAddress(self, PublicIpAddress):
161
+ params = self._make_params(locals())
162
+ return self._execute(params)
163
+
164
+ def CreateSecurityGroup(self, GroupCode, RegionCode, Description):
165
+ params = self._make_params(locals())
166
+ return self._execute(params)
167
+
168
+ def AuthorizeSecurityGroup(self, GroupCode, RegionCode, IpProtocol, PortRange,
169
+ SourceGroupCode=None, SourceCidrIp=None, Policy=None, NicType=None, Priority=None):
170
+ params = self._make_params(locals())
171
+ return self._execute(params)
172
+
173
+ def DescribeSecurityGroupAttribute(self, GroupCode, RegionCode, NicType=None):
174
+ params = self._make_params(locals())
175
+ return self._execute(params)
176
+
177
+ def DescribeSecurityGroups(self, RegionCode, PageNumber=None, PageSize=None):
178
+ params = self._make_params(locals())
179
+ return self._execute(params)
180
+
181
+ def ModifySecurityGroupAttribute(self, RegionCode, GroupCode, Adjust):
182
+ params = self._make_params(locals())
183
+ return self._execute(params)
184
+
185
+ def RevokeSecurityGroup(self, GroupCode, RegionCode, IpProtocol, PortRange,
186
+ SourceGroupCode=None, SourceCidrIp=None, Policy=None, NicType=None):
187
+ params = self._make_params(locals())
188
+ return self._execute(params)
189
+
190
+ def DeleteSecurityGroup(self, GroupCode, RegionCode):
191
+ params = self._make_params(locals())
192
+ return self._execute(params)
193
+
194
+ def CreateSnapshot(self, InstanceName, DiskCode):
195
+ params = self._make_params(locals())
196
+ return self._execute(params)
197
+
198
+ def DeleteSnapshot(self, DiskCode, InstanceName, SnapshotCode):
199
+ params = self._make_params(locals())
200
+ return self._execute(params)
201
+
202
+ def CancelSnapshotRequest(self, InstanceName, SnapshotCode):
203
+ params = self._make_params(locals())
204
+ return self._execute(params)
205
+
206
+ def DescribeSnapshots(self, InstanceName, DiskCode):
207
+ params = self._make_params(locals())
208
+ return self._execute(params)
209
+
210
+ def DescribeSnapshotAttribute(self, RegionCode, SnapshotCode):
211
+ params = self._make_params(locals())
212
+ return self._execute(params)
213
+
214
+ def RollbackSnapshot(self, InstanceName, DiskCode, SnapshotCode):
215
+ params = self._make_params(locals())
216
+ return self._execute(params)
217
+
218
+ def DescribeRegions(self):
219
+ params = self._make_params(locals())
220
+ return self._execute(params)
221
+
222
+ def DescribeZones(self, RegionCode):
223
+ params = self._make_params(locals())
224
+ return self._execute(params)
225
+
226
+
227
+ if __name__ == '__main__':
228
+ import pprint
229
+ pp = pprint.PrettyPrinter(indent=4)
230
+
231
+ AccessKeyID = ''
232
+ AccessKeySecret = ''
233
+
234
+ ecs = ECS(AccessKeyID, AccessKeySecret)
235
+
236
+ if 0:
237
+ print('## Regions\n')
238
+ regions = ecs.DescribeRegions()[1]
239
+ pp.pprint(regions)
240
+ print()
241
+
242
+ for region in regions['Regions']:
243
+ print('## Zones in %s\n' % region['RegionCode'])
244
+ zones = ecs.DescribeZones(region['RegionCode'])
245
+ if not zones[0]:
246
+ pp.pprint(zones)
247
+ continue
248
+ zones = zones[1]
249
+ pp.pprint(zones)
250
+ print()
251
+
252
+ for zone in zones['Zones']:
253
+ print('## Instances in %s\n' % zone['ZoneCode'])
254
+ instances = ecs.DescribeInstanceStatus(
255
+ region['RegionCode'], zone['ZoneCode'])[1]
256
+ pp.pprint(instances)
257
+ print()
258
+
259
+ print()
260
+
261
+ #pp.pprint(ecs.DescribeInstanceStatus(PageSize=10, PageNumber=1))
262
+ #pp.pprint(ecs.DescribeInstanceStatus('cn-hangzhou-dg-a01', 'cn-hangzhou-dg101-a'))
263
+ # pp.pprint(ecs.StartInstance('AY1209220917063704221'))
264
+ # pp.pprint(ecs.StopInstance('AY1209220917063704221'))
265
+ # pp.pprint(ecs.RebootInstance('AY1209220917063704221'))
266
+ # pp.pprint(ecs.DescribeInstanceAttribute('AY1209220917063704221'))
267
+ #pp.pprint(ecs.DescribeImages(PageSize=10, PageNumber=9))
268
+ # pp.pprint(ecs.DescribeDisks('AY1209220917063704221'))
269
+ #pp.pprint(ecs.DescribeSnapshots('AY1209220917063704221', '1006-60002839'))