def check_fingerprint_hostname(hostname): """ Helper function to check hostname fingerprint :param hostname: :return: """ known_hosts_path = get_user_known_hosts_path(current_user, flask.current_app.config['USER']) try: found, remote_server_key = check_hostname(hostname, known_hosts_path) except (TimeoutError, socket.timeout) as e: return flask.jsonify({ 'message': 'Failed to obtain SSH response with error: {}. (Is SSH server running at {}:22 ?)'.format(str(e), hostname) }), 400 data = { 'found': found, 'datetime': datetime.datetime.now().isoformat(), 'hostname': hostname, 'md5_fingerprint': format_md5_fingerprint(calculate_fingerprint(remote_server_key, 'md5')), 'sha256_fingerprint': format_sha256_fingerprint(calculate_fingerprint(remote_server_key, 'sha256')) } data_sign = json.dumps(data, sort_keys=True).encode() private_key = import_key(get_user_private_key_path(current_user, flask.current_app.config['USER'])) data['signature'] = base64.b64encode(sign_data(data_sign, private_key)).decode("ascii") return flask.jsonify(data), 200
def get_fingerprint(): known_hosts_path = get_user_known_hosts_path( current_user, flask.current_app.config['USER']) host_keys = paramiko.hostkeys.HostKeys( known_hosts_path if os.path.isfile(known_hosts_path) else None) host_keys_proccessed = [] for host_key in host_keys: keys = [] sha256_fingerprints = [] for type in host_keys[host_key].keys(): remote_server_key = host_keys[host_key][type] sha256_fingerprint = format_sha256_fingerprint( calculate_fingerprint(remote_server_key, 'sha256')) sha256_fingerprints.append(sha256_fingerprint) md5_fingerprint = format_md5_fingerprint( calculate_fingerprint(remote_server_key, 'md5')) keys.append({ 'type': type, 'md5_fingerprint': md5_fingerprint, 'sha256_fingerprint': sha256_fingerprint }) fingerprint_info = Fingerprint.query.filter( Fingerprint.user_id == current_user.id, Fingerprint.hashed_hostname == host_key).first() if not fingerprint_info: fingerprint_info = Fingerprint.query.filter( Fingerprint.user_id == current_user.id, Fingerprint.sha256_fingerprint.in_( sha256_fingerprints)).first() color_class = 'danger' title = '{} - Not in fingerprint database'.format(host_key) if fingerprint_info: if fingerprint_info.hashed_hostname == host_key: color_class = 'success' title = '{} - Matched by hostname hash'.format(host_key) else: color_class = 'warning' title = '{} - Matched by hostname fingerprint'.format(host_key) host_keys_proccessed.append({ 'hostname': fingerprint_info.hostname if fingerprint_info else host_key, 'title': title, 'color_class': color_class, 'hashed_hostname': host_key, 'keys': keys }) return flask.render_template('fingerprint.index.fingerprint.html', host_keys_proccessed=host_keys_proccessed)
def delete_fingerprint(hostname: str): known_hosts_path = get_user_known_hosts_path(current_user, flask.current_app.config['USER']) host_keys = paramiko.hostkeys.HostKeys(known_hosts_path if os.path.isfile(known_hosts_path) else None) # !FIXME i could not find a better way how to do this for entry in host_keys._entries: if hostname in entry.hostnames: host_keys._entries.remove(entry) host_keys.save(known_hosts_path) flask.flash('Fingerprint was deleted successfully.', 'success') return flask.redirect(flask.url_for('fingerprint.index.get_fingerprint'))
def add_hostname_fingerprint(): json_data = flask.request.get_json() if not json_data: return flask.jsonify({ 'message': 'No data' }), 400 hostname = json_data.get('hostname') if not hostname: return flask.jsonify({ 'message': 'Required parameter hostname is missing' }), 400 remote_server_key = get_remote_server_key(hostname) data = { 'found': json_data.get('found'), 'datetime': json_data.get('datetime'), 'hostname': hostname, # Recalculation fingerprint for remote_server_key and not using one in resuest # ensures that fingerprint did not change (signature chech would fail) 'md5_fingerprint': format_md5_fingerprint(calculate_fingerprint(remote_server_key, 'md5')), 'sha256_fingerprint': format_sha256_fingerprint(calculate_fingerprint(remote_server_key, 'sha256')) } data_sign = json.dumps(data, sort_keys=True).encode() # Validate signature public_key = import_key(get_user_public_key_path(current_user, flask.current_app.config['USER'])) signature = base64.b64decode(flask.request.json.get('signature')) if not verify_data(data_sign, signature, public_key): # Déjà vu Neo, It happens when they change something... return flask.jsonify({ 'message': 'Signature is invalid, we will get out of this hotel!' }), 401 # We got here, signature is valid, lets check time # Check date, allow only 2h old signatures from_date = datetime.datetime.today() - datetime.timedelta(hours=2) if dateutil.parser.parse(data['datetime']) < from_date: return flask.jsonify({ 'message': 'Signature is older than 2 hours, please generate a new one' }), 403 # Everything looks "hunky dory" lets continue known_hosts_path = get_user_known_hosts_path(current_user, flask.current_app.config['USER']) found = check_hostname(hostname, known_hosts_path)[0] if found: return flask.jsonify({ 'message': 'Fingerprint is already in known_hosts file' }), 200 hashed_hostname = add_hostname(data['hostname'], remote_server_key, known_hosts_path) found_fingerprint = Fingerprint.query.filter_by(hashed_hostname=hashed_hostname, user_id=current_user.id).first() if not found_fingerprint: found_fingerprint = Fingerprint() found_fingerprint.hostname = data['hostname'] found_fingerprint.user_id = current_user.id found_fingerprint.hashed_hostname = hashed_hostname found_fingerprint.sha256_fingerprint = data['sha256_fingerprint'] db.session.add(found_fingerprint) db.session.commit() return flask.jsonify({ 'message': 'OK', 'hashed_hostname': hashed_hostname }), 200