Guest User

ssl tool

a guest
Apr 12th, 2017
640
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.90 KB | None | 0 0
  1. #!/usr/bin/python2.7
  2. """
  3. ' Name: ssl_tool
  4. ' Version: 0.9
  5. ' Description: SSL order, installation, and checking tool using Comodo's API
  6. ' Riley L. for contributions,suggestions,or found bugs email rileymace57@gmail.com
  7. ' Contributions by: Jadon N., Nick D., and Kevin A.
  8. """
  9. import argparse
  10. import getpass
  11. import sys
  12. import os
  13. import re
  14. import urllib
  15. import time
  16. import base64
  17. import hashlib
  18. import requests
  19. import tldextract
  20. from rads.cpanel_api import whm_api
  21. from rads.cpanel_api import cpanel_api
  22. from rads.common import strcolor
  23. from platform import node as hostname
  24. from glob import glob
  25.  
  26. """
  27. ' Ideas:
  28. ' -wildcard status searches based on domain
  29. ' -allow output of statuses for multiple orders by date, domains, order
  30. numbers, etc.
  31. ' -provide options for sumarized status messages, or detailed
  32. ' -provide options for pulling status, and SSL cert data on more than
  33. just order number
  34. ' -allow for multiple order numbers, domains, etc.
  35. ' -check local server as well to see if the SSL is installed properly(
  36. in case a cx wants to pre-install an SSL before pointing their DNS )
  37. ' -add country searching, and auto-change for full CC names via
  38. https://pypi.python.org/pypi/pycountry
  39. ' -make help output more pretty.
  40. Example: http://stackoverflow.com/q/20094215/49853
  41. """
  42.  
  43.  
  44. def parse_arguments():
  45. """
  46. ' Parse the command line arguments, and compare to available options
  47. ' @param none
  48. ' @return void
  49. """
  50.  
  51. main_parser = argparse.ArgumentParser(
  52. prog="\n\nssl_tool",
  53. description="Perform common SSL tasks.",
  54. epilog="Feel free to send ideas to CaseyB@InMotionHosting.com")
  55. subparsers = main_parser.add_subparsers(dest='cmd')
  56.  
  57. csr_help_command = strcolor("yellow", "ssl_tool gen-csr -h")
  58. csr_help = "Generate CSR -- use '" + csr_help_command + "' for more info"
  59. csr_epilog = strcolor(
  60. "yellow",
  61. "Please keep in mind that every option except for the " +
  62. "ones for 'company', and 'division' in gen-csr are required. If " +
  63. "'company' or 'division' are omitted ssl_tool will automagically " +
  64. "use the value from 'domain'.")
  65. csr_subparser = subparsers.add_parser(
  66. "gen-csr",
  67. help=csr_help,
  68. epilog=csr_epilog)
  69. csr_subparser.add_argument(
  70. "-d",
  71. "--domain",
  72. metavar="DOMAIN",
  73. type=str.lower,
  74. required=True,
  75. nargs=1)
  76. csr_subparser.add_argument(
  77. "-e",
  78. "--email",
  79. metavar="EMAIL",
  80. required=True,
  81. nargs=1)
  82. csr_subparser.add_argument(
  83. "-c",
  84. "--city",
  85. metavar="CITY",
  86. required=True,
  87. nargs="+")
  88. csr_subparser.add_argument(
  89. "-s",
  90. "--state",
  91. metavar="STATE",
  92. required=True,
  93. nargs="+")
  94. csr_subparser.add_argument(
  95. "-p",
  96. "--country",
  97. metavar="COUNTRY",
  98. required=True,
  99. nargs="+")
  100. csr_subparser.add_argument(
  101. "-co",
  102. "--company",
  103. metavar="COMPANY",
  104. nargs="*")
  105. csr_subparser.add_argument(
  106. "-div",
  107. "--division",
  108. metavar="DIVISION",
  109. nargs="*")
  110.  
  111. # Python 2.7 won't allow me to make a sub-parser optional and the following
  112. # is the best compromise I could come up with.
  113. main_subparser_epilog = strcolor(
  114. "yellow",
  115. "Note that only one option from 'main' is used at a time.")
  116. main_help_command = strcolor(
  117. "yellow",
  118. "ssl_tool main -h")
  119. main_subparser_help = (
  120. "Everything else -- use '" +
  121. main_help_command +
  122. "' for more info")
  123. main_subparser = subparsers.add_parser(
  124. "main",
  125. help=main_subparser_help,
  126. epilog=main_subparser_epilog)
  127. default_group = main_subparser.add_mutually_exclusive_group()
  128. order_ssl_help = "Order an SSL for a given domain name using the " + \
  129. "most recent CSR from this server, and setup DCV"
  130. default_group.add_argument(
  131. "-o",
  132. "--order-ssl",
  133. metavar="DOMAIN",
  134. type=str.lower,
  135. help=order_ssl_help,
  136. nargs=1)
  137.  
  138. setup_dcv_help = "Setup DCV file for a domain " + \
  139. "based on it's most recent CSR in "
  140.  
  141. setup_dcv_help += "/var/cpanel/ssl/system/csrs" + \
  142. "[ automatically called by -o ]"
  143.  
  144. default_group.add_argument(
  145. "--setup-dcv",
  146. metavar="DOMAIN",
  147. type=str.lower,
  148. help=setup_dcv_help,
  149. nargs=1)
  150.  
  151. order_status_help = "Check the status of an SSL order by the order number"
  152. default_group.add_argument(
  153. "-s",
  154. "--order-status",
  155. metavar="ORDER_NUMBER",
  156. help=order_status_help,
  157. nargs=1)
  158.  
  159. install_ssl_help = "Install an SSL that has been confirmed ready " + \
  160. "by Comodo by the Comodo order number"
  161. default_group.add_argument(
  162. "-i",
  163. "--install-ssl",
  164. metavar="ORDER_NUMBER",
  165. help=install_ssl_help,
  166. nargs=1)
  167.  
  168. check_install_help = "Check externally that an SSL is installed " + \
  169. "properly by given domain name"
  170. default_group.add_argument(
  171. "-c",
  172. "--check-install",
  173. metavar="DOMAIN",
  174. type=str.lower,
  175. help=check_install_help,
  176. nargs=1)
  177.  
  178. default_group.add_argument(
  179. "-v",
  180. "--version",
  181. action='version',
  182. version='%(prog)s 1.0')
  183.  
  184. if len(sys.argv) > 1:
  185. args = vars(main_parser.parse_args())
  186. for k_arg, v_arg in args.iteritems():
  187. if type(args[k_arg]) is list:
  188. args[k_arg] = ' '.join(v_arg)
  189.  
  190. else:
  191. monolithic_help = ""
  192. # retrieve subparsers from parser
  193. subparsers_actions = [
  194. action for action in main_parser._actions
  195. if isinstance(action, argparse._SubParsersAction)]
  196. # print sub-help for each parser
  197. for subparsers_action in subparsers_actions:
  198. # get all subparsers and print help
  199. for choice, subparser in subparsers_action.choices.items():
  200. monolithic_help += "\n\n"
  201. monolithic_help += strcolor(
  202. "red",
  203. "Subparser '{}'".format(choice))
  204. monolithic_help += "\n"
  205. monolithic_help += subparser.format_help()
  206. print monolithic_help
  207. quit()
  208.  
  209. return args
  210.  
  211.  
  212. def check_input(inputs, input_type='domain'):
  213. """
  214. Do a basic sanity check on input args
  215. @params inputString as 'arguments'
  216. @params optional input_type to check
  217. @return
  218. """
  219.  
  220. domain_regex = re.compile(
  221. r"^(([a-zA-Z]{1})|" +
  222. r"([a-zA-Z0-9][a-zA-Z0-9-_]{0,61}[a-zA-Z0-9]))(\.(([a-zA-Z]{1})|" +
  223. r"([a-zA-Z0-9][a-zA-Z0-9-_]{0,61}[a-zA-Z0-9]))){0,6}$")
  224. if input_type is 'domain':
  225. if not domain_regex.match(inputs):
  226. print strcolor(
  227. "red",
  228. "Domain does not seem to be in a valid format.")
  229. sys.exit()
  230. if not is_valid_tld(inputs):
  231. print strcolor("red", "Invalid TLD used in domain name.")
  232. sys.exit()
  233. if len(inputs) > 253:
  234. print strcolor("red", "Domain entered is too long.")
  235. sys.exit()
  236. if 'inmotionhosting.com' in inputs or 'webhostinghub.com' in inputs:
  237. print strcolor("red", "Domain provided contains brand.")
  238. sys.exit()
  239.  
  240. email_regex = re.compile(
  241. r"[^@]+@[^@]+\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$")
  242. if input_type is 'email':
  243. if not is_valid_tld(inputs):
  244. print strcolor("red", "Invalid TLD in email address.")
  245. sys.exit()
  246. if not email_regex.match(inputs):
  247. print strcolor(
  248. "red",
  249. "Email does not seem to be in a valid format.")
  250. sys.exit()
  251.  
  252. if input_type is 'order_number' and not inputs.isdigit():
  253. print strcolor("red", "Order number must be only numerals.")
  254. sys.exit()
  255.  
  256.  
  257. def is_valid_tld(string):
  258. """
  259. Check string for valid TLD
  260. @params String to check as 'string'
  261. @return Bool of status
  262. """
  263.  
  264. if len(tldextract.extract(string)[2]) != 0:
  265. return True
  266. return False
  267.  
  268.  
  269. def generate_csr(csr_data):
  270. """
  271. Generate and pring a CSR, and self-signed SSL based on a given string
  272. @params cPanel required CSR parameters as raw_csr_data
  273. @return Bool for success or failure
  274. """
  275.  
  276. if check_input(csr_data['domain']):
  277. return False
  278. if len(csr_data['state']) == 2:
  279. print strcolor("red", "State must not be abbreviated.")
  280. return False
  281. if len(csr_data['country']) != 2 or not csr_data['country'].isalpha():
  282. print strcolor("red", "Country must be 2 letter ISO code.")
  283. return False
  284. if not csr_data['company']:
  285. csr_data['company'] = csr_data['domain']
  286. if not csr_data['division']:
  287. csr_data['division'] = csr_data['domain']
  288. if check_input(csr_data['email'], 'email'):
  289. return False
  290.  
  291. userdata_request = {
  292. "function": "domainuserdata",
  293. "version": "1",
  294. "domain": csr_data['domain']
  295. }
  296. userdata_response = whm_api(**userdata_request)
  297. try:
  298. userdata_response['data']
  299. except (KeyError, TypeError):
  300. print strcolor("red", userdata_response['metadata']['reason'])
  301. return False
  302.  
  303. csr_request = {
  304. "function": "generatessl",
  305. "version": "1",
  306. "domains": csr_data['domain'],
  307. "localityName": csr_data['city'],
  308. "stateOrProvinceName": csr_data['state'],
  309. "countryName": csr_data['country'],
  310. "organizationName": csr_data['company'],
  311. "organizationalUnitName": csr_data['division'],
  312. "emailAddress": csr_data['email'],
  313. "keysize": '2048',
  314. "signatureHash": "PREFER_SHA2"
  315. }
  316. csr_response = whm_api(**csr_request)
  317. try:
  318. print csr_response['data']['csr']
  319. except (KeyError, TypeError):
  320. print strcolor("red", csr_response['metadata']['reason'])
  321. return False
  322. print strcolor(
  323. "yellow",
  324. "Please note that if you are proceeding to install that " +
  325. "you do not need to copy the CSR data, as ssl_tool will " +
  326. "pull the CSR from the server for you during the install step.")
  327.  
  328. return True
  329.  
  330.  
  331. def call_comodo(
  332. request_type,
  333. request_parameters,
  334. split_char='\n',
  335. password=''):
  336. """
  337. Call Comodo's API for given parameters
  338. @params type of request as a string, and request parameters as dict
  339. @return URL encoded raw results of API call
  340. """
  341.  
  342. brand_domain = "inmotionhosting.com"
  343. server_hostname = hostname()
  344. if "webhostinghub.com" in server_hostname:
  345. brand_domain = "webhostinghub.com"
  346. base_request_url = "https://secure.comodo.net/products/"
  347. comodo_login_name = 'certs@' + brand_domain
  348. print
  349.  
  350. if password is '':
  351. comodo_pass = getpass.getpass(
  352. "Current " +
  353. comodo_login_name +
  354. " password, please: ")
  355. else:
  356. comodo_pass = password
  357. comodo_request = {
  358. "loginName": comodo_login_name,
  359. "loginPassword": comodo_pass
  360. }
  361. comodo_request.update(request_parameters)
  362.  
  363. print "Calling Comodo..."
  364. try:
  365. comodo_response = requests.post(
  366. base_request_url +
  367. request_type,
  368. data=comodo_request)
  369. except requests.exceptions.ConnectionError:
  370. print "Unable to reach Comodo at " + base_request_url + request_type \
  371. + " using " + comodo_login_name
  372. return False
  373.  
  374. comodo_response = comodo_response.text.split(split_char)
  375. if split_char == '&':
  376. comodo_response = [pair.split('=') for pair in comodo_response]
  377.  
  378. return {
  379. "comodo_response": comodo_response,
  380. "comodo_pass": comodo_pass
  381. }
  382.  
  383.  
  384. def get_csr(domain):
  385. """
  386. Get most recent CSR for given domain
  387. @params domain name as string to search for
  388. @return most recent CSR as string
  389. """
  390.  
  391. check_input(domain)
  392. search_term = re.sub(r'[\.-]+', '_', domain)
  393. system_csr_path = "/var/cpanel/ssl/system/csrs/"
  394. max_mtime = 0
  395. most_recent_file_path = ""
  396.  
  397. if not glob('{}*'.format(system_csr_path)):
  398. print strcolor("red", "No CSRs found!")
  399. print strcolor(
  400. "red",
  401. "Have you already generated the CSRs on this server?")
  402. return False
  403. for file_found in glob('{}{}*'.format(system_csr_path, search_term)):
  404. if os.path.getmtime(file_found) > max_mtime:
  405. max_mtime = os.path.getmtime(file_found)
  406. most_recent_file_path = file_found
  407.  
  408. try:
  409. with open(most_recent_file_path, 'r') as csr_file:
  410. csr = csr_file.read()
  411. return csr
  412. except IOError:
  413. print strcolor("red", "CSR for given domain not found!")
  414. return False
  415.  
  416.  
  417. def setup_dcv(domain):
  418. """
  419. Setup DCV for the SSL order process
  420. @params domain name as string that the DCV needs to be setup for
  421. @return bool based on success / fail
  422. """
  423.  
  424. if check_input(domain):
  425. return False
  426. csr = str(get_csr(domain))
  427. if csr == 'False':
  428. return False
  429. dcv_data = {'MD5': '', 'SHA1': ''}
  430. first_line = csr.find('\n')
  431. last_line = csr.rfind('\n')
  432. decoded_csr = base64.b64decode(csr[first_line+1:last_line])
  433. dcv_data['MD5'] = hashlib.md5(decoded_csr).hexdigest().upper()
  434. dcv_data['SHA1'] = hashlib.sha1(decoded_csr).hexdigest().upper()
  435.  
  436. extracted_domain = tldextract.extract(domain)
  437. username_request = {
  438. 'function': 'domainuserdata',
  439. 'version': '1',
  440. 'domain': extracted_domain.domain + "." + extracted_domain.suffix
  441. }
  442. username_response = whm_api(**username_request)
  443. try:
  444. domain_owner = username_response['data']['userdata']['user']
  445. except (KeyError, TypeError):
  446. print strcolor("red", username_response['metadata']['reason'])
  447. print strcolor("yellow", "DCV MD5 is: " + dcv_data['MD5'])
  448. print strcolor("yellow", "DCV SHA1 is: " + dcv_data['SHA1'])
  449. print strcolor("red", "DCV not placed.")
  450. quit()
  451.  
  452. # cpapi2
  453. # --user=fromcr6 DomainLookup getdocroot domain=www.fromcrimsontowool.com
  454. docroot_request = {
  455. 'module': 'DomainLookup',
  456. 'version': 2,
  457. 'function': 'getdocroot',
  458. 'user': domain_owner,
  459. 'domain': domain
  460. }
  461. docroot_response = cpanel_api(**docroot_request)
  462. try:
  463. domain_docroot = docroot_response['cpanelresult']['data'][0]['docroot']
  464. except (KeyError, TypeError):
  465. print strcolor("yellow", "DCV MD5 is: " + dcv_data['MD5'])
  466. print strcolor("yellow", "DCV SHA1 is: " + dcv_data['SHA1'])
  467. print strcolor("red", "DCV not placed.")
  468. quit()
  469.  
  470. htaccess_rule = '<IfModule mod_rewrite.c>\nRewriteRule ' + \
  471. dcv_data['MD5'] + '.txt - [L]\n</IfModule>\n\n'
  472. target_htaccess_file = "/home/" + domain_owner + "/.htaccess"
  473. with open(target_htaccess_file, 'a+') as htaccess_file:
  474. original_contents = htaccess_file.read()
  475. if dcv_data['MD5'] in original_contents:
  476. print strcolor(
  477. "yellow",
  478. target_htaccess_file +
  479. " file already has MD5 hash inside.")
  480. return
  481. htaccess_file.seek(0, 0)
  482. htaccess_file.write(htaccess_rule + original_contents)
  483. print strcolor(
  484. "green",
  485. target_htaccess_file +
  486. " file updated with DCV hash.")
  487.  
  488. if os.path.isdir(domain_docroot):
  489. with open(domain_docroot+'/'+dcv_data['MD5']+".txt", 'w+') as dcv_file:
  490. dcv_file.write(dcv_data['SHA1'] + "\n" + "comodoca.com")
  491. print strcolor(
  492. "green",
  493. "DCV file placed at: " +
  494. domain_docroot +
  495. "/" +
  496. dcv_data['MD5'] +
  497. ".txt")
  498. check_dcv(domain + "/" + dcv_data['MD5'] + ".txt")
  499.  
  500. print strcolor("yellow", "DCV setup complete.")
  501. return
  502.  
  503.  
  504. def check_dcv(dcv_url):
  505. """
  506. Check the Domain Control Validation (DCV)
  507. @param URL to check the DCV
  508. @return bool
  509. """
  510. # Check for https and do proper DCV check
  511. site = requests.get(dcv_url)
  512. if site.url[:8] == r'https://':
  513. # Check HTTPS DCV
  514. print 'checking HTTPS URL'
  515. elif site.url[:7] == r'http://':
  516. # Check HTTP DCV
  517. print 'checking HTTP URL'
  518. return
  519.  
  520.  
  521. def order_ssl(domain):
  522. """
  523. Order an SSL using most recent CSR on the local server for a domain
  524. @param domain to generate for the SSL
  525. @return void
  526. """
  527.  
  528. check_input(domain)
  529. csr = get_csr(domain)
  530. if not csr:
  531. return False
  532.  
  533. setup_dcv(domain)
  534.  
  535. # The 'test' option this will need to be removed,
  536. # or at least changed before release
  537. order_request = {
  538. "product": '488',
  539. "years": '1',
  540. "serverSoftware": '31',
  541. "csr": csr,
  542. "dcvMethod": 'HTTP_CSR_HASH',
  543. "isCustomerValidated": 'n',
  544. "test": 'Y'
  545. }
  546.  
  547. order_response = call_comodo('!AutoApplySSL', order_request)[0]
  548. order_return_code = order_response[0]
  549. if order_return_code != '0' and order_return_code != '1':
  550. print strcolor("red", order_response[1])
  551. return False
  552. elif order_return_code == '1':
  553. print strcolor(
  554. "yellow",
  555. "Order was successful, but payment is still required.")
  556. elif int(order_return_code) >= 0:
  557. # The folowing text is courtesy of
  558. # https://secure.comodo.net/api/pdf/webhostreseller/sslcertificates/AutoApplySSL%20v1.44.pdf
  559. expected_return_texts = {
  560. 1: "This order has been automatically validated and the " +
  561. "certificate will be issued as soon as possible (i.e. " +
  562. "almost definitely within the next hour).",
  563. 24: "This order, although marked as validated by the " +
  564. "Web Host, is awaiting final approval by a Comodo " +
  565. "account manager.",
  566. 48: "This order was not marked as validated by the Web Host, " +
  567. "and could not be automatically validated by Comodo: " +
  568. "the 48 hours starts when " +
  569. "Comodo has received various documents from the end-user."
  570. }
  571.  
  572. try:
  573. expected_delivery = int(order_response[3])
  574. except ValueError:
  575. print strcolor(
  576. "red",
  577. "Expected delivery time parameter is not a number!")
  578. return False
  579. if expected_delivery == 1:
  580. print strcolor(
  581. "green",
  582. expected_return_texts.get(expected_delivery))
  583. else:
  584. print strcolor(
  585. "yellow",
  586. expected_return_texts.get(expected_delivery))
  587.  
  588. print strcolor("green", "Order Successful!")
  589. print "Order Number is " + strcolor("yellow", order_response[1])
  590. return
  591.  
  592.  
  593. def convert(name):
  594. """
  595. Convert a given string to replace _ with spaces, and apply title()
  596. @params string to convert
  597. @return converted string
  598. """
  599.  
  600. string_1 = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', name)
  601. return re.sub('([a-z0-9])([A-Z])', r'\1 \2', string_1).title()
  602.  
  603.  
  604. def order_status(order_number):
  605. """
  606. ' Check the order status of an already purchased SSL by order number
  607. ' @param Comodo order number
  608. ' @return void
  609. """
  610.  
  611. check_input(order_number, 'order_number')
  612.  
  613. comodo_parameters = {'orderNumber': order_number}
  614. status_result = call_comodo('!WebHostReport', comodo_parameters, '&')
  615. print_keys = [
  616. "orderNumber",
  617. "domain",
  618. "_status",
  619. "_dateTime",
  620. "_lastStatusChange",
  621. "_dcvStatus"
  622. ]
  623.  
  624. print "\n"
  625. for key, value in status_result['comodo_response']:
  626. if not (any(name in key for name in print_keys) or
  627. key == 'errorMessage' and value != '0' or
  628. key == 'noOfResults' and value != '1'):
  629. continue
  630. if "status" in key:
  631. value = urllib.unquote(value).decode("utf8").replace("+", " ")
  632. if "lastStatusChange" in key or "dateTime" in key:
  633. if "dateTime" in key:
  634. key = "dateOrderSubmitted"
  635. date_time_str = "%d%^b%y %H%M %Z"
  636. value = time.strftime(date_time_str, time.localtime(int(value)))
  637. key_name = key.split('_')[-1]
  638. print convert(key_name) + ': ' + value
  639. print "\n"
  640.  
  641. call_comodo(
  642. '!WebHostReport',
  643. comodo_parameters,
  644. '&',
  645. status_result['comodo_pass'])
  646. return
  647.  
  648.  
  649. def install_ssl(order_number):
  650. """
  651. Install an SSL after pulling it from Comodo
  652. @params Comodo order number as a string
  653. @return void
  654. """
  655.  
  656. check_input(order_number, 'order_number')
  657.  
  658. comodo_parameters = {
  659. 'orderNumber': order_number,
  660. 'queryType': '1',
  661. 'showFQDN': 'Y'
  662. }
  663. collect_ssl_response = call_comodo(
  664. 'download/CollectSSL',
  665. comodo_parameters)
  666. collect_ssl_response_code = collect_ssl_response[0]
  667. if collect_ssl_response_code != '2':
  668. print strcolor("red", collect_ssl_response[1])
  669. return False
  670. domain = collect_ssl_response[1].lower()
  671.  
  672. begin_domain_ssl = collect_ssl_response.index(
  673. "-----BEGIN CERTIFICATE-----")
  674. end_domain_ssl = collect_ssl_response.index(
  675. "-----END CERTIFICATE-----")
  676. domain_ssl = collect_ssl_response[begin_domain_ssl:end_domain_ssl+1]
  677. domain_ssl = "\n".join(domain_ssl)
  678.  
  679. ca_ssls = collect_ssl_response[end_domain_ssl+1:]
  680. ca_ssls = "\n".join(ca_ssls)
  681. print "Domain from given order number is: " + strcolor("green", domain)
  682.  
  683. extracted_domain = tldextract.extract(domain)
  684. user_name_parameters = {
  685. 'function': 'domainuserdata',
  686. 'version': '1',
  687. 'domain': extracted_domain.domain + "." + extracted_domain.suffix
  688. }
  689. user_name_response = whm_api(**user_name_parameters)
  690. try:
  691. domain_ip = user_name_response['data']['userdata']['ip']
  692. except (KeyError, TypeError):
  693. print strcolor("red", user_name_response['metadata']['reason'])
  694. return False
  695.  
  696. crt_key_parameters = {
  697. 'function': 'fetchsslinfo',
  698. 'version': '1',
  699. 'domain': domain
  700. }
  701. crt_response = whm_api(**crt_key_parameters)
  702. try:
  703. crt_key = crt_response['data']['key']
  704. except (KeyError, TypeError):
  705. print strcolor("red", crt_response['metadata']['reason'])
  706. return False
  707.  
  708. install_ssl_request = {
  709. 'function': 'installssl',
  710. 'version': '1',
  711. 'domain': domain,
  712. 'crt': domain_ssl,
  713. 'key': crt_key,
  714. 'cab': ca_ssls,
  715. 'ip': domain_ip
  716. }
  717.  
  718. install_response = whm_api(**install_ssl_request)
  719. try:
  720. install_response['data']['statusmsg']
  721. except (KeyError, TypeError):
  722. print strcolor(
  723. "red",
  724. "cPanel was unable to install the SSL from Comodo.")
  725. print strcolor("red", install_response['metadata']['reason'])
  726. return False
  727.  
  728. check_install(domain)
  729.  
  730. return
  731.  
  732.  
  733. def check_install(domain):
  734. """
  735. Check the installation of an SSL for a domain, and print the status
  736. @params domain to check as a string
  737. @return void
  738. """
  739.  
  740. check_input(domain)
  741. one_month = 2592000
  742. one_year = 28930000
  743. time_now = int(time.time())
  744. ssl_age = 'fair'
  745. check_install_url = 'https://secure.comodo.com/sslchecker'
  746. check_install_request = {
  747. 'url': domain
  748. }
  749. fields_to_print = [
  750. 'server_ip',
  751. 'cert_notAfter',
  752. 'cert_issuer_DN',
  753. 'cert_subject_CN'
  754. ]
  755. field_labels = {
  756. 'server_ip': 'Server/Domain IP',
  757. 'cert_notAfter': 'Cert. not valid after',
  758. 'cert_issuer_DN': 'Cert. issuer',
  759. 'cert_subject_CN': 'SSL \'Common Name\''
  760. }
  761.  
  762. check_install_results = requests.post(
  763. check_install_url, data=check_install_request).text.split('&')
  764. check_install_results = [check_install_result.split('=') for
  765. check_install_result in check_install_results]
  766.  
  767. error_message = check_install_results[-2][1].replace("+", " ")
  768. if error_message != "OK":
  769. print strcolor("red", "Comodo returned: " + error_message)
  770. return False
  771.  
  772. for key, value in check_install_results:
  773. if key == "server_domain" and value != domain:
  774. print strcolor(
  775. "yellow",
  776. "SSL domain does not match given domain: " + value)
  777. if key in fields_to_print:
  778. if domain not in value and key == 'cert_subject_CN':
  779. print strcolor(
  780. "red",
  781. "Domain given does not match certificate")
  782. value = strcolor("red", value)
  783. if "DN" in key:
  784. value = urllib.unquote(value.replace("%0D%0A", "="))
  785. value = value.decode("utf8")
  786. value = ', '.join(value.split('=')[1::2])
  787. value = value.replace("+", " ")
  788. if "notAfter" in key:
  789. if value > time_now + one_month:
  790. ssl_age = 'bad'
  791. if value > time_now + one_year - one_month:
  792. ssl_age = 'good'
  793. date_time = "%d%^b%y %H%M %Z"
  794. value = time.strftime(date_time, time.localtime(int(value)))
  795. if ssl_age == 'bad':
  796. value = strcolor("red", value)
  797. elif ssl_age == 'good':
  798. value = strcolor("green", value)
  799. else:
  800. value = strcolor("yellow", value)
  801. print field_labels[key] + ": " + value
  802. return
  803.  
  804.  
  805. def main():
  806. """
  807. Main function for getting things started
  808. @params none
  809. @return void
  810. """
  811.  
  812. args = parse_arguments()
  813.  
  814. if args['cmd'] == "gen-csr":
  815. generate_csr(args)
  816. elif args['order_ssl']:
  817. order_ssl(args['order_ssl'])
  818. elif args['setup_dcv']:
  819. setup_dcv(args['setup_dcv'])
  820. elif args['order_status']:
  821. order_status(args['order_status'])
  822. elif args['install_ssl']:
  823. install_ssl(args['install_ssl'])
  824. elif args['check_install']:
  825. check_install(args['check_install'])
  826.  
  827. if __name__ == "__main__":
  828. try:
  829. main()
  830. except KeyboardInterrupt:
  831. print "\nCtrl + C received..."
  832. sys.exit("\nQuitting.")
Add Comment
Please, Sign In to add comment