#!/usr/bin/env python
# tls-scan - lib: REST API
# https://github.com/ArtiomL/tls-scan
# Artiom Lichtenstein
# v0.0.2, 08/11/2016

import json
import log
import requests

__author__ = 'Artiom Lichtenstein'
__license__ = 'MIT'
__version__ = '0.0.2'

# SSL Labs REST API
class clsSAPI(object):
	def __init__(self):
		# API entry point
		self.strAPIE = 'https://api.ssllabs.com/api/v2/'
		# API call: analyze
		self.strAnalyze = 'analyze?publish=off&all=done&host='
		# Parameter to initiate a new assessment
		self.strAnStNew = '&startNew=on'
		# API HTTPS session
		self.objHS = requests.session()
		# Add Content-Type to HTTP headers and modify User-Agent
		self.objHS.headers.update({ 'Content-Type': 'application/json', 'User-Agent': 'tls-scan v%s' % __version__ })

	def funAnalyze(self, strHost):
		# Initiate a new assessment for a host
		try:
			objHResp = self.objHS.get(self.strAPIE + self.strAnalyze + strHost + self.strAnStNew)
			if objHResp.status_code == 200:
				return json.loads(objHResp.content)['statusMessage']

		except Exception as e:
			log.funLog(2, repr(e), 'err')

	def funOpStatus(self, strHost):
		# Check operation status
		strURL = self.strAPIE + self.strAnalyze + strHost
		strStatus = 'DNS'
		while strStatus == 'DNS':
			try:
				diOper = json.loads(self.objHS.get(strURL).content)
				strStatus = diOper['status']
				if strStatus == 'READY':
					return diOper

				if strStatus == 'ERROR':
					return ['X %s, %s' % (strHost, diOper['statusMessage'])]

				lstMessages = [None] * len(diOper['endpoints'])
				log.funLog(2, 'Total number of endpoints: %s' % len(lstMessages))
			except Exception as e:
				log.funLog(2, repr(e), 'err')
		while strStatus == 'IN_PROGRESS':
			try:
				diOper = json.loads(self.objHS.get(strURL).content)
				strStatus = diOper['status']
				for i, diEP in enumerate(diOper['endpoints']):
					strStaMess = diEP['statusMessage']
					if strStatus == 'READY':
						strGrade = 'X'
						if strStaMess == 'Ready':
							strGrade = diEP['grade']
						lstMessages[i] = '%s %s, %s, %s' % (strGrade, strHost, diEP['ipAddress'], strStaMess)
					else:
						if strStaMess == 'In progress':
							strDetMess = diEP['statusDetailsMessage']
							if strDetMess != lstMessages[i]:
								lstMessages[i] = strDetMess
								log.funLog(3, '%s, IP: %s, %s' % (strHost, diEP['ipAddress'], lstMessages[i]))
			except Exception as e:
				log.funLog(2, repr(e), 'err')
		return lstMessages

@@ -113,13 +113,13 @@
 0.0.
-2, 08
+3, 12
 /11/
@@ -238,17 +238,17 @@
  = '0.0.
-2
+3
 '%0A%0A# SSL
@@ -760,16 +760,45 @@
 ion__ %7D)
+%0A%09%09# %0A%09%09self.boolJSON = False
 %0A%0A%09def f
@@ -1112,16 +1112,329 @@
 'err')%0A%0A
+%09def funGrades(self, diOper):%0A%09%09lstGrades = %5B%5D%0A%09%09for diEP in diOper%5B'endpoints'%5D:%0A%09%09%09strStaMess = diEP%5B'statusMessage'%5D%0A%09%09%09strGrade = 'X'%0A%09%09%09if strStaMess == 'Ready':%0A%09%09%09%09strGrade = diEP%5B'grade'%5D%0A%09%09%09lstGrades.append('%25s %25s, %25s, %25s' %25 (strGrade, diOper%5B'host'%5D, diEP%5B'ipAddress'%5D, strStaMess))%0A%09%09return lstGrades%0A%0A
 %09def fun
@@ -1485,16 +1485,36 @@
  status%0A
+%09%09strStatus = 'DNS'%0A
 %09%09strURL
@@ -1557,36 +1557,16 @@
 strHost%0A
-%09%09strStatus = 'DNS'%0A
 %09%09while 
@@ -1690,57 +1690,205 @@
 %09%09%09%09
-if strStatus == 'READY':%0A%09%09%09%09%09return diOper
+log.funLog(3, 'Transaction status: %25s' %25 strStatus)%0A%09%09%09%09if strStatus == 'READY':%0A%09%09%09%09%09# Cached result (from 'DNS' to 'READY')%0A%09%09%09%09%09return diOper if self.boolJSON else self.funGrades(diOper)
 %0A%0A%09%09%09%09
+el
 if s
@@ -1973,16 +1973,74 @@
 '%5D)%5D%0A%0A%09%09
+%09except Exception as e:%0A%09%09%09%09log.funLog(2, repr(e), 'err')%0A
 %09%09lstMes
@@ -2081,18 +2081,16 @@
 ints'%5D)%0A
-%09%09
 %09%09log.fu
@@ -2153,68 +2153,8 @@
 s))%0A
-%09%09%09except Exception as e:%0A%09%09%09%09log.funLog(2, repr(e), 'err')%0A
 %09%09wh

Update reapi.py