Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 221 lines (187 sloc) 6.54 KB
#!/usr/bin/env python
# encoding: utf-8
# @author Robin Schneider <ypid23@aol.de>
# @licence GPLv3 <http://www.gnu.org/licenses/gpl.html>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Check the GPG fingerprints on my homepage if they are the correct ones.
"""
__version__ = '0.9'
# modules {{{
import subprocess
import logging
import urllib2
from HTMLParser import HTMLParser
# }}}
logging.basicConfig(
format='%(levelname)s: %(message)s',
# level=logging.DEBUG,
level=logging.INFO,
)
PAGES_WITH_GPG_KEYS = {
'blog': 'ypid.wordpress.com/uber-mich',
'osm-wiki': 'wiki.openstreetmap.org/wiki/User:Ypid'
}
PROTOCOLS = ['http', 'https']
GPG_LIST_KEYS_COMMAND = [
'gpg', '--no-options', '--list-public-keys', '--fingerprint',
'Robin Schneider (Automatic Signing Key) <ypid23@aol.de>',
'Robin Schneider (Release Signing Key) <ypid23@aol.de>',
'Robin Schneider <ypid23@aol.de>'
]
# helper functions {{{
def make_clean(string, is_html):
"""Workaround for HTMLParser.
Not sure why but if an HTML entity is contained in the parsed HTML the
HTMLParser does not work probably.
"""
if is_html:
return string.replace('&lt;', '**EmailStart**').replace('&gt;', '**EmailEnd**')
else:
return string.replace('<', '**EmailStart**').replace('>', '**EmailEnd**')
def reverse_clean(string):
"""Workaround for HTMLParser."""
return string.replace('**EmailStart**', '<').replace('**EmailEnd**', '>')
def sort_string_lines(string):
"""Split string by newline, strip whitespace and return the sorted array."""
array_of_lines = []
for line in string.split('\n'):
line = line.strip()
if line != '':
array_of_lines.append(line.strip())
return sorted(array_of_lines)
# }}}
# get trusted fingerprints from my machine {{{
def get_public_keys_from_machine():
"""Get the local list of public GPG keys to compare with the remote ones."""
gpg_public_keys_from_my_machine = u''
process = subprocess.Popen(
GPG_LIST_KEYS_COMMAND,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
while True:
out = process.stdout.read(1)
if out == '' and process.poll() is not None:
break
if out != '':
gpg_public_keys_from_my_machine += out.encode('utf-8')
return [make_clean(line, False) for line in sort_string_lines(gpg_public_keys_from_my_machine)]
# }}}
class MyHTMLParser(HTMLParser):
_in_pre = False
pre_data = ''
def handle_starttag(self, tag, attrs):
if tag == 'pre':
self._in_pre = True
def handle_endtag(self, tag):
if tag == 'pre':
self._in_pre = False
def handle_data(self, data):
if self._in_pre:
self.pre_data = data
# }}}
def compate_with_html_page(html): # {{{
number_ok = 0
parser = MyHTMLParser()
parser.feed(make_clean(html, True))
gpg_public_keys_from_web_pages_array = sort_string_lines(parser.pre_data)
max_len = max(
len(gpg_public_keys_from_web_pages_array),
len(gpg_public_keys_from_my_machine_array)
)
len_equal = len(
gpg_public_keys_from_web_pages_array) == len(
gpg_public_keys_from_my_machine_array)
if not len_equal:
logging.warning(
"Lengths for the trusted lines and the lines form the web differ (max %d).",
max_len)
for idx in range(max_len):
trusted_line = gpg_public_keys_from_my_machine_array[idx]
if trusted_line is None:
if trusted_line is not None:
logging.warning(
"Line available locally but not upstream: %s",
trusted_line)
elif trusted_line not in gpg_public_keys_from_web_pages_array:
logging.error(
'%s\n%s%s',
"String at line %d was not found remotely:" % idx,
'\tExpected: "%s"' % reverse_clean(trusted_line),
'\n\tGot: "%s"' % reverse_clean(
gpg_public_keys_from_web_pages_array[
idx]) if len_equal else ''
)
else:
logging.debug("Testing line: %s", trusted_line)
number_ok += 1
logging.info("%d lines are equal out of %d", number_ok, max_len)
return max_len - number_ok
# }}}
# main {{{
if __name__ == '__main__':
"""Execute module in command line mode."""
from argparse import ArgumentParser
args = ArgumentParser(
description=__doc__
)
args.add_argument(
'-V',
'--version',
action='version',
version='%(prog)s {version}'.format(version=__version__)
)
args.add_argument(
'-s',
'--show',
action='store_true',
default=False,
help=u"Print the expected lines and exit."
)
args.add_argument(
'-c',
'--command',
action='store_true',
default=False,
help=u"Print the gpg command used and exit."
)
args.add_argument(
'-e',
'--html-escape',
action='store_true',
default=False,
help=u"Use HTML entities for all special characters"
)
user_parms = args.parse_args()
gpg_public_keys_from_my_machine_array = get_public_keys_from_machine()
if user_parms.command:
print(' '.join(GPG_LIST_KEYS_COMMAND))
raise SystemExit()
if user_parms.show:
# for line in gpg_public_keys_from_my_machine_array:
# print(line)
subprocess.call(GPG_LIST_KEYS_COMMAND)
raise SystemExit()
lines_not_matching = 0
for proto in PROTOCOLS:
for page_name in PAGES_WITH_GPG_KEYS:
url = '%s://%s' % (proto, PAGES_WITH_GPG_KEYS[page_name])
logging.info("Checking page: %s", url)
content = urllib2.urlopen(url).read().decode('utf-8')
lines_not_matching += compate_with_html_page(content)
if lines_not_matching == 0:
logging.info("Everything seems to be ok.")
else:
logging.warning("%d lines did not match …", lines_not_matching)
# }}}