mirror of
https://github.com/adulau/crl-monitor.git
synced 2024-11-22 01:57:05 +00:00
Add API v2.0
This commit is contained in:
parent
e4344dcfae
commit
5082038a95
3 changed files with 68 additions and 11 deletions
30
client/bin/pypssl
Executable file
30
client/bin/pypssl
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import pypssl
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description='Query a Passive SSL instance.')
|
||||||
|
parser.add_argument("--url", default='https://www.circl.lu/', help='URL where the passive SSL is running (no path).')
|
||||||
|
parser.add_argument("-v", "--version", type=int, default=2, help='URL where the passive SSL is running (no path).')
|
||||||
|
parser.add_argument("-u", "--username", help='Username to login on the platform.')
|
||||||
|
parser.add_argument("-p", "--password", help='Password to login on the platform.')
|
||||||
|
parser.add_argument("-t", "--token", help='Token to login on the platform.')
|
||||||
|
parser.add_argument("-i", "--ip", help='IP to query (can be a block, max /23).')
|
||||||
|
parser.add_argument("-c", "--cert", help='SHA1 of the certificate to search.')
|
||||||
|
parser.add_argument("-f", "--fetch", help='SHA1 of the certificate to fetch.')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
p = pypssl.PyPSSL(args.url, args.version, (args.username, args.password), args.token)
|
||||||
|
|
||||||
|
if args.ip is not None:
|
||||||
|
print(json.dumps(p.query(args.ip)))
|
||||||
|
elif args.cert is not None:
|
||||||
|
print(json.dumps(p.query_cert(args.cert)))
|
||||||
|
elif args.fetch is not None:
|
||||||
|
print(json.dumps(p.fetch_cert(args.fetch, make_datetime=False)))
|
||||||
|
else:
|
||||||
|
print('You didn\'t query anything...')
|
|
@ -3,13 +3,15 @@
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import socket
|
import socket
|
||||||
|
from urlparse import urljoin
|
||||||
|
import dateutil.parser
|
||||||
|
|
||||||
|
|
||||||
class PyPSSL(object):
|
class PyPSSL(object):
|
||||||
|
|
||||||
def __init__(self, url='https://www.circl.lu/pssl/query', basic_auth=None,
|
def __init__(self, base_url='https://www.circl.lu/', api_version=2, basic_auth=None, auth_token=None):
|
||||||
auth_token=None):
|
self.base_url = base_url
|
||||||
self.url = url
|
self.api_version = api_version
|
||||||
|
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
if basic_auth is not None:
|
if basic_auth is not None:
|
||||||
|
@ -21,6 +23,13 @@ class PyPSSL(object):
|
||||||
# No authentication defined.
|
# No authentication defined.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _query(self, url):
|
||||||
|
response = self.session.get(url)
|
||||||
|
try:
|
||||||
|
return response.json()
|
||||||
|
except:
|
||||||
|
raise Exception('Unable to decode JSON object: ' + response.text)
|
||||||
|
|
||||||
def _check_IP(self, ip):
|
def _check_IP(self, ip):
|
||||||
if ':' in ip:
|
if ':' in ip:
|
||||||
return {'error': 'IPv6 is not (yet) supported'}
|
return {'error': 'IPv6 is not (yet) supported'}
|
||||||
|
@ -39,9 +48,26 @@ class PyPSSL(object):
|
||||||
check = self._check_IP(q)
|
check = self._check_IP(q)
|
||||||
if check is not None:
|
if check is not None:
|
||||||
return check
|
return check
|
||||||
response = self.session.get('{}/{}' .format(self.url, q))
|
if self.api_version == 1:
|
||||||
try:
|
path = 'pssl/query/{}'.format(q)
|
||||||
return response.json()
|
else:
|
||||||
except:
|
path = 'v2pssl/query/{}'.format(q)
|
||||||
raise Exception('Unable to decode JSON object: ' + response.text)
|
return self._query(urljoin(self.base_url, path))
|
||||||
return {}
|
|
||||||
|
def query_cert(self, q):
|
||||||
|
if self.api_version != 2:
|
||||||
|
return {'error': 'Only available in API v2'}
|
||||||
|
path = 'v2pssl/cquery/{}'.format(q)
|
||||||
|
return self._query(urljoin(self.base_url, path))
|
||||||
|
|
||||||
|
def fetch_cert(self, q, make_datetime=True):
|
||||||
|
if self.api_version != 2:
|
||||||
|
return {'error': 'Only available in API v2'}
|
||||||
|
path = 'v2pssl/cfetch/{}'.format(q)
|
||||||
|
response = self._query(urljoin(self.base_url, path))
|
||||||
|
if response.get('error') or not make_datetime:
|
||||||
|
return response
|
||||||
|
# create python datetime, doesn't return a json object
|
||||||
|
response['info']['not_before'] = dateutil.parser.parse(response['info']['not_before'])
|
||||||
|
response['info']['not_after'] = dateutil.parser.parse(response['info']['not_after'])
|
||||||
|
return response
|
||||||
|
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='pypssl',
|
name='pypssl',
|
||||||
version='1.1',
|
version='2.0',
|
||||||
author='Raphaël Vinot',
|
author='Raphaël Vinot',
|
||||||
author_email='raphael.vinot@circl.lu',
|
author_email='raphael.vinot@circl.lu',
|
||||||
maintainer='Raphaël Vinot',
|
maintainer='Raphaël Vinot',
|
||||||
|
@ -12,6 +12,7 @@ setup(
|
||||||
description='Python API for PSSL.',
|
description='Python API for PSSL.',
|
||||||
long_description=open('README.md').read(),
|
long_description=open('README.md').read(),
|
||||||
packages=['pypssl'],
|
packages=['pypssl'],
|
||||||
|
scripts=['bin/pypssl'],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
|
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
@ -23,6 +24,6 @@ setup(
|
||||||
'Topic :: Security',
|
'Topic :: Security',
|
||||||
'Topic :: Internet',
|
'Topic :: Internet',
|
||||||
],
|
],
|
||||||
install_requires=['requests'],
|
install_requires=['requests', 'python-dateutil'],
|
||||||
package_data={'': ['*.md', '*.rst', 'LICENSE']},
|
package_data={'': ['*.md', '*.rst', 'LICENSE']},
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue