sshwot/src/main-filter.py

130 lines
3.6 KiB
Python

import argparse
import sys
import entry
import hashing
import open_default_files
import read_file
import write_file
def main():
parser = argparse.ArgumentParser(
description = """Search sshwot file(s) for given host and/or
fingerprint.""",
# We want to provide help on --help, but the default thing
# also adds -h, which we don't want
add_help = False
)
# --help to get help
parser.add_argument('--help',
action = 'help',
help = 'show this help message and exit'
)
# -o can be used to write the results to a file instead of stdout
parser.add_argument('-o',
# Given one argument, we open a file of that name and store it
# to outfile, which will be sys.stdout.buffer otherwise.
# We use .buffer since we're going to write binary data
action = 'store',
dest = 'outfile',
type = argparse.FileType('wb'),
default = sys.stdout.buffer,
# This is what will be displayed in the help after -o
metavar = 'outfile',
help = 'write the sshwot file to a given file instead of the stdout'
)
# -h/--host for domain, -p/--port for port (default port is 22)
parser.add_argument('-h', '--host',
action = 'store',
dest = 'host',
help = 'the domain to filter for'
)
parser.add_argument('-p', '--port',
action = 'store',
dest = 'port',
# Automatically convert to integer
type = int,
help = 'the port associated with the given host'
)
# -f/--fingerprint for fingerprint
parser.add_argument('-f', '--fingerprint',
action = 'store',
dest = 'fingerprint',
help = 'the fingerprint to filter for'
)
# Input file(s)
parser.add_argument('infiles',
nargs = '*',
type = argparse.FileType('rb'),
# The text shown for these in the usage
metavar = 'sshwot-file',
help = 'a sshwot file to search'
)
# This automatically parses the command line args for us. If it
# returns, we have correct arguments
args = parser.parse_args()
# Ensure we have a host if port was specified
if args.port is not None and args.host is None:
print('If you specify a port you need to specify a domain too', file=sys.stderr)
sys.exit(1)
# Ensure we're filtering for something
if args.host is None and args.fingerprint is None:
print('Specify a host and/or a fingerprint to filter for', file=sys.stderr)
sys.exit(1)
# Default to port 22
port = 22 if args.port is None else args.port
# Check the validity of the fingerprint and de-base64 it, if we have it
if args.fingerprint is not None:
if args.fingerprint[0:7].upper() != 'SHA256:':
print('We can only handle sha256 fingerprints (starts with SHA256:)')
sys.exit(1)
# We encode this, because hashing.base64dec expects bytes
fingerprint = hashing.base64dec(args.fingerprint[7:].encode())
# A valid sha256 fingerprint is 32 bytes
if len(fingerprint) < 32:
raise Exception('Fingerprint too short')
elif len(fingerprint) > 32:
raise Exception('Fingerprint too long')
else:
fingerprint = None
# Use the default files if no input files were specified
if len(args.infiles) == 0:
infiles = open_default_files.open_all()
else:
infiles = args.infiles
matches = []
for infile in infiles:
entries, file_comment = read_file.read(infile)
# Filter by host if it's present
if args.host is not None:
entries = entry.filter_by_host(entries, args.host, port)
# Filter by fingerprint if it's present
if fingerprint is not None:
entries = entry.filter_by_fingerprint(entries, fingerprint)
matches.extend(entries)
# Print the matches in sshwot format
write_file.write(args.outfile, matches)
if __name__ == '__main__':
try:
main()
except Exception as err:
print('Error: %s' % err, file=sys.stderr)
sys.exit(1)