Пример #1
0
    def event_history(self, columns, *, indent=4, sieve=None, repres=None):
        self._events_to_show = _filter_events(self._all_events, sieve)
        if not self._events_to_show:
            print_info('No USB events found!')
            return

        if not cfg.QUIET and cfg.ISATTY:
            choice, abs_filename = _output_choice('event history',
                                                  'history.json', 'history/')
            if choice == '2':
                try:
                    _dump_events(self._events_to_show, 'event history',
                                 abs_filename, indent)
                except USBRipError as e:
                    print_critical(str(e),
                                   initial_error=e.errors['initial_error'])
                return

        # elif choice == '1' or choice == '':

        if columns:
            table_data = [[COLUMN_NAMES[name] for name in columns]]
        else:
            columns = [key for key in COLUMN_NAMES.keys()]
            table_data = [[val for val in COLUMN_NAMES.values()]]

        _represent_events(self._events_to_show, columns, table_data,
                          'USB-History-Events', repres)
Пример #2
0
def _get_latest_version():
    connected, errcode, e = _check_connection('www.google.com')
    if not connected:
        return (None, -1, -1, errcode, e)

    print_info('Getting latest version and date')

    try:
        html = urlopen('http://www.linux-usb.org/usb.ids', timeout=10).read()
        #from requests import get
        #resp = get('http://www.linux-usb.org/usb.ids', timeout=10)
    except socket.timeout as e:
        #except requests.exceptions.Timeout as e:
        return (None, -1, -1, USBIDs._SERVER_TIMEOUT_ERROR, str(e))

    db = html.decode('cp1252')
    #soup = BeautifulSoup(resp.text, 'html.parser')
    #db = soup.text

    try:
        latest_ver = re.search(r'^# Version:\s*(.*?$)', db,
                               re.MULTILINE).group(1)
        latest_date = re.search(r'^# Date:\s*(.*?$)', db,
                                re.MULTILINE).group(1)
    except AttributeError as e:
        return (None, -1, -1, USBIDs._SERVER_CONTENT_ERROR, str(e))

    return (db, latest_ver, latest_date, 0, '')
Пример #3
0
def get_config_parser():
	config_parser = ConfigParser(allow_no_value=True)
	config_parser.optionxform = str

	os.makedirs(CONFIG_FILE.rsplit('/', 1)[0], exist_ok=True)

	if os.path.isfile(CONFIG_FILE):
		config_parser.read(CONFIG_FILE, encoding='utf-8')
		print_info(f'Configuration loaded: "{CONFIG_FILE}"')

	else:
		print_warning('No configuration file found, creating new one...')

		config_parser.add_section('history')
		config_parser.set('history', 'password', 'r1pp3r')

		config_parser.add_section('violations')
		config_parser.set('violations', 'password', 'r1pp3r')

		print_info(f'New configuration file: "{CONFIG_FILE}"')

		with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
			config_parser.write(f)

	return config_parser
Пример #4
0
def _dump_events(events_to_show, list_name, abs_filename, indent):
	print_info(f'Generating {list_name} list (JSON)')

	out = []
	for event in events_to_show:
		tmp_event_dict = OrderedDict()

		for key in ('conn', 'host', 'vid', 'pid', 'prod', 'manufact', 'serial', 'port', 'disconn'):
			tmp_event_dict[key] = event[key]

		out.append(tmp_event_dict)

	try:
		with open(abs_filename, 'w', encoding='utf-8') as out_json:
			json.dump(out, out_json, indent=indent)

	except PermissionError as e:
		raise USBRipError(
			f'Permission denied: "{abs_filename}". Retry with sudo',
			errors={'initial_error': str(e)}
		)

	os.chmod(abs_filename, stat.S_IRUSR | stat.S_IWUSR)  # 600

	print_info(f'New {list_name} list: "{abs_filename}"')
Пример #5
0
def _get_filtered_history():
    filtered_history = []

    print_info(
        'Searching for log files: C:\\Users\\eyver-dev\\Documents\\python\\usbrip\\test\\syslog* or C:\\Users\\eyver-dev\\Documents\\python\\usbrip\\test\\messages*'
    )

    syslog_files = sorted([
        filename for filename in list_files(
            'C:\\Users\\eyver-dev\\Documents\\python\\usbrip\\test')
        if filename.rsplit('\\', 1)[1].startswith('syslog')
    ])

    if syslog_files:
        for syslog in syslog_files:
            filtered_history.extend(_read_log_file(syslog))
    else:
        messages_files = sorted([
            filename for filename in list_files('/var/log/')
            if filename.rsplit('/', 1)[1].startswith('messages')
        ])

        if messages_files:
            for messages in messages_files:
                filtered_history.extend(_read_log_file(messages))
        else:
            raise USBRipError('None of log file types was found!')

    return filtered_history
Пример #6
0
def _read_log_file(filename):
    filtered = DefaultOrderedDict(default_factory=list)

    if filename.endswith('.gz'):
        print_info(f'Unpacking "{filename}"')

        try:
            log = gzip.open(filename, 'rb')
        except PermissionError as e:
            print_warning(f'Permission denied: "{filename}". Retry with sudo',
                          initial_error=str(e))
            return filtered
        else:
            end_of_file = b''
            filename = filename[:-3]

    else:
        log = codecs.open(filename, 'r', encoding='utf-8', errors='ignore')
        end_of_file = ''

    print_info(f'Reading "{filename}"')
    regex = re.compile(r'usb')
    for line in iter(log.readline, end_of_file):
        if isinstance(line, bytes):
            line = line.decode(encoding='utf-8', errors='ignore')
        if regex.search(line):
            filtered[line[:15]].append(line)  # line[:15] == 'Mon dd hh:mm:ss'

    log.close()
    return filtered
Пример #7
0
def _get_raw_history():
    raw_history = DefaultOrderedDict(default_factory=list)

    print_info(
        'Searching for log files: "/var/log/syslog*" or "/var/log/messages*"')

    syslog_files = sorted([
        filename for filename in list_files('/var/log/')
        if filename.rsplit('/', 1)[1].startswith('syslog')
    ])

    if syslog_files:
        for syslog in syslog_files:
            raw_history.update(_read_log_file(syslog))
    else:
        messages_files = sorted([
            filename for filename in list_files('/var/log/')
            if filename.rsplit('/', 1)[1].startswith('messages')
        ])

        if messages_files:
            for messages in messages_files:
                raw_history.update(_read_log_file(messages))
        else:
            raise USBRipError('None of log file types was found!')

    return raw_history
Пример #8
0
    def open_dump(input_dump, columns, *, sieve=None, repres=None):
        abs_input_dump = os.path.abspath(input_dump)

        print_info(f'Opening USB event dump: "{abs_input_dump}"')

        try:
            with open(abs_input_dump, 'r', encoding='utf-8') as dump:
                events_dumped = json.load(dump)
        except json.decoder.JSONDecodeError as e:
            print_critical('Failed to decode event dump (JSON)',
                           initial_error=str(e))
            return

        if not events_dumped:
            print_critical('This dump is empty!')
            return

        events_to_show = _filter_events(events_dumped, sieve)
        if not events_to_show:
            print_info('No USB events found!')
            return

        if columns:
            table_data = [[COLUMN_NAMES[name] for name in columns]]
        else:
            columns = [key for key in COLUMN_NAMES.keys()]
            table_data = [[val for val in COLUMN_NAMES.values()]]

        _represent_events(events_to_show, columns, table_data,
                          'USB-Event-Dump', repres)
Пример #9
0
def _get_filtered_history():
    filtered_history = []

    print_info(
        'Searching for log files: "/var/log/syslog*" or "/var/log/messages*"')

    syslog_files = sorted([
        filename for filename in list_files('/var/log/')
        if filename.rsplit('/', 1)[1].startswith('syslog')
    ])

    if syslog_files:
        for syslog in syslog_files:
            filtered_history.extend(_read_log_file(syslog))
    else:
        messages_files = sorted([
            filename for filename in list_files('/var/log/')
            if filename.rsplit('/', 1)[1].startswith('messages')
        ])

        if messages_files:
            for messages in messages_files:
                filtered_history.extend(_read_log_file(messages))
        else:
            raise USBRipError('None of log file types was found!')

    return filtered_history
Пример #10
0
def _read_log_file(filename):
    filtered = []

    abs_filename = os.path.abspath(filename)

    if abs_filename.endswith('.gz'):
        print_info(f'Unpacking "{abs_filename}"')

        try:
            log = gzip.open(abs_filename, 'rb')
        except PermissionError as e:
            print_warning(
                f'Permission denied: "{abs_filename}". Retry with sudo',
                initial_error=str(e))
            return filtered
        else:
            end_of_file = b''
            abs_filename = os.path.splitext(abs_filename)

    else:
        log = codecs.open(abs_filename, 'r', encoding='utf-8', errors='ignore')
        end_of_file = ''

    print_info(f'Reading "{abs_filename}"')

    regex = re.compile(r'] usb (.*?): ')
    for line in iter(log.readline, end_of_file):
        if isinstance(line, bytes):
            line = line.decode(encoding='utf-8', errors='ignore')

        if regex.search(line):
            date = line[:32]
            if date.count(':') > 2:
                date = ''.join(
                    line[:32].rsplit(':', 1)
                )  # rreplace(':', 1) to remove the last ':' from "2019-08-09T06:15:49.655261-04:00" timestamp if there is one

            try:
                date = datetime.strptime(
                    date, '%Y-%m-%dT%H:%M:%S.%f%z'
                )  # ex. 2019-08-09T06:15:49.655261-0400
            except ValueError as e:
                raise USBRipError(
                    f'Wrong timestamp format found in "{abs_filename}"',
                    errors={'initial_error': str(e)})
            else:
                date = date.strftime('%Y-%m-%d %H:%M:%S')
                logline = line[32:].strip()
                if any(pat in line
                       for pat in ('New USB device found, ', 'Product: ',
                                   'Manufacturer: ', 'SerialNumber: ')):
                    filtered.append((date, 'c', logline))
                elif 'disconnect' in line:
                    filtered.append((date, 'd', logline))

    log.close()
    return filtered
Пример #11
0
    def change_password(storage_type, *, compression_level='5'):
        storage_full_path = f'{USBStorage._STORAGE_BASE}/{storage_type}.7z'
        if not os.path.isfile(storage_full_path):
            print_critical(f'Storage not found: "{storage_full_path}"')
            return

        old_password = getpass('Old password: '******'New password: '******'Confirm new password: '******'Passwords does not match, try again')
            return

        try:
            out = _7zip_unpack(storage_full_path, old_password)
            if 'Everything is Ok' in out:
                base_filename = re.search(
                    r'([^\n ]*\.json)',
                    _7zip_list(storage_full_path, old_password),
                    re.MULTILINE).group(1)
                json_file = f'{USBStorage._STORAGE_BASE}/{base_filename}'
                os.remove(storage_full_path)

                out = _7zip_pack(storage_full_path, json_file, new_password,
                                 compression_level)

                if 'Everything is Ok' in out:
                    print_info('Password was successfully changed')

                    conf_parser = ConfigParser(allow_no_value=True)
                    conf_parser.optionxform = str
                    conf_parser.read(CONFIG_FILE, encoding='utf-8')
                    conf_parser.set(storage_type, 'password', new_password)
                    with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
                        conf_parser.write(f)

                    print_info('Configuration file updated')

                else:
                    print_critical(
                        'Undefined behaviour while creating storage',
                        initial_error=out)

                os.remove(json_file)

            else:
                print_critical('Undefined behaviour while unpacking storage',
                               initial_error=out)

        except USBRipError as e:
            print_critical(str(e),
                           errcode=e.errors['errcode'],
                           initial_error=e.errors['initial_error'])
            return
Пример #12
0
    def create_storage(storage_type,
                       password,
                       *,
                       input_auth=None,
                       attributes=None,
                       compression_level='5',
                       indent=4,
                       sieve=None):
        if storage_type == 'history':
            events_to_show = _get_history_events(sieve)
        elif storage_type == 'violations':
            try:
                events_to_show = _get_violation_events(sieve, input_auth,
                                                       attributes, indent)
            except USBRipError as e:
                print_critical(str(e), initial_error=e.errors['initial_error'])
                return 1

        if events_to_show is None:
            return 1

        if events_to_show:
            min_date, max_date = _get_dates(events_to_show)
            json_file = f'{USBStorage._STORAGE_BASE}/{min_date}-{max_date}.json'
        else:
            json_file = f'{USBStorage._STORAGE_BASE}/{datetime.now().strftime("%Y%m%dT%H%M%S")}.json'

        try:
            _dump_events(events_to_show, storage_type, json_file, indent)
        except USBRipError as e:
            print_critical(str(e), initial_error=e.errors['initial_error'])
            return 1

        storage_full_path = f'{USBStorage._STORAGE_BASE}/{storage_type}.7z'
        if os.path.exists(storage_full_path):
            os.remove(storage_full_path)

        try:
            out = _7zip_pack(storage_full_path, json_file, password,
                             compression_level)
        except USBRipError as e:
            os.remove(json_file)
            print_critical(str(e),
                           errcode=e.errors['errcode'],
                           initial_error=e.errors['initial_error'])
            return 1

        if 'Everything is Ok' in out:
            print_info(f'New {storage_type} storage: "{storage_full_path}"')
            print_secret('Your password is', secret=password)
            os.remove(json_file)
        else:
            print_critical('Undefined behaviour while creating storage',
                           initial_error=out)
Пример #13
0
def _output_choice(list_name, default_filename, dirname):
    while True:
        print(
            f'[?] How would you like your {list_name} list to be generated?\n')

        print('    1. JSON-file')
        print('    2. Terminal stdout')

        number = input('\n[>] Please enter the number of your choice: ')

        if number == '1':
            while True:
                filename = input(
                    f'[>] Please enter the base name for the output file '
                    f'(default is "{default_filename}"): ')

                if all(c in printable
                       for c in filename) and len(filename) < 256:
                    if not filename:
                        filename = default_filename
                    elif filename[-5:] != '.json':
                        filename = filename + '.json'

                    filename = root_dir_join(dirname + filename)

                    try:
                        dirname = os.path.dirname(filename)
                        os_makedirs(dirname)
                    except USBRipError as e:
                        print_critical(str(e),
                                       initial_error=e.errors['initial_error'])
                        return (None, '')
                    else:
                        print_info(f'Created "{dirname}"')

                    overwrite = True
                    if os.path.isfile(filename):
                        while True:
                            overwrite = input(
                                '[?] File exists. Would you like to overwrite it? [Y/n]: '
                            )
                            if len(overwrite) == 1 and overwrite in 'Yy':
                                overwrite = True
                                break
                            elif len(overwrite) == 1 and overwrite in 'Nn':
                                overwrite = False
                                break

                    if overwrite:
                        return (int(number), filename)

        elif number == '2':
            return (int(number), '')
Пример #14
0
	def __new__(cls, files=None):
		try:
			if files:
				filtered_history = []
				for file in files:
					filtered_history.extend(_read_log_file(file))

			else:
				print_info('Trying to run journalctl...')

				# child_env = os.environ.copy()
				# child_env['LANG'] = 'en_US.utf-8'
				# journalctl_out = check_output(['journalctl'], env=child_env).decode('utf-8')

				try:
					journalctl_out = check_output([
						'journalctl',
						'-o',
						'short-iso-precise'
					]).decode('utf-8')

				except Exception as e:
					print_warning(f'Failed to run journalctl: {str(e)}')
					filtered_history = _get_filtered_history()

				else:
					if '-- Logs begin at' in journalctl_out:
						print_info('Successfully ran journalctl')

						filtered_history = _read_log_file(
							None,
							log=StringIO(journalctl_out),
							total=journalctl_out.count('\n')
						)

					else:
						print_warning(f'An error occurred when running journalctl: {journalctl_out}')
						filtered_history = _get_filtered_history()

		except USBRipError as e:
			print_critical(str(e), initial_error=e.errors['initial_error'])
			return None

		all_events = _parse_history(filtered_history)

		instance = super().__new__(cls)
		instance._all_events = all_events  # self._all_events
		instance._violations = []          # self._violations
		instance._events_to_show = None    # self._events_to_show
		return instance
Пример #15
0
def _7zip_list(archive, password):
    print_info(f'Listing archive: "{archive}"')

    cmd = ['7z', 'l', archive, '-p' + password]

    out, errcode, errmsg, e = _7zip_subprocess_handler(cmd)
    if errcode:
        raise USBRipError(errmsg,
                          errors={
                              'errcode': errcode,
                              'initial_error': e
                          })

    return out
Пример #16
0
	def generate_auth_json(self, output_auth, attributes, *, indent=4, sieve=None):
		self._events_to_show = _filter_events(self._all_events, sieve)
		if not self._events_to_show:
			print_info('No USB devices found!')

		rand_id = f'usbrip-{randint(1000, 9999)}'
		self._events_to_show += [{
			'conn':     rand_id,
			'host':     rand_id,
			'vid':      rand_id,
			'pid':      rand_id,
			'prod':     rand_id,
			'manufact': rand_id,
			'serial':   rand_id,
			'port':     rand_id,
			'disconn':  rand_id
		}]

		abs_output_auth = os.path.abspath(output_auth)

		try:
			dirname = os.path.dirname(abs_output_auth)
			os_makedirs(dirname)
		except USBRipError as e:
			print_critical(str(e), initial_error=e.errors['initial_error'])
			return 1
		else:
			print_info(f'Created directory "{dirname}/"')

		try:
			auth_json = open(abs_output_auth, 'w', encoding='utf-8')
		except PermissionError as e:
			print_critical(f'Permission denied: "{abs_output_auth}". Retry with sudo', initial_error=str(e))
			return 1

		print_info('Generating authorized device list (JSON)')

		if not attributes:
			attributes = ('vid', 'pid', 'prod', 'manufact', 'serial')

		auth = defaultdict(set)
		for event in tqdm(self._events_to_show, ncols=80, unit='dev'):
			for key, val in event.items():
				if key in attributes and val is not None:
					auth[key].add(val)

		auth = {key: list(vals) for key, vals in auth.items()}

		for key in auth.keys():
			auth[key].sort()

		json.dump(auth, auth_json, sort_keys=True, indent=indent)
		auth_json.close()

		os.chmod(abs_output_auth, stat.S_IRUSR | stat.S_IWUSR)  # 600

		print_info(f'New authorized device list: "{abs_output_auth}"')
Пример #17
0
def _7zip_pack(archive, file, password, compression_level):
    print_info(f'Creating storage (7-Zip): "{archive}"')

    cmd = [
        '7z', 'a', archive, file, '-mhe=on', '-p' + password,
        '-mx=' + compression_level
    ]

    out, errcode, errmsg, e = _7zip_subprocess_handler(cmd)
    if errcode:
        raise USBRipError(errmsg,
                          errors={
                              'errcode': errcode,
                              'initial_error': e
                          })

    return out
Пример #18
0
def _7zip_unpack(archive, password):
	print_info(f'Unpacking archive: "{archive}"')

	cmd = [
		'7z',
		'e',
		archive,
		'-p' + password,
		'-o' + USBStorage._STORAGE_BASE,
		'-y'
	]

	out, errcode, errmsg, e = _7zip_subprocess_handler(cmd)
	if errcode:
		raise USBRipError(errmsg, errors={'errcode': errcode, 'initial_error': e})

	return out
Пример #19
0
def _download_database(filename):
    try:
        dirname = os.path.dirname(filename)
        os_makedirs(dirname)
    except USBRipError as e:
        raise USBRipError(str(e),
                          errors={'initial_error': e.errors['initial_error']})
    else:
        print_info(f'Created directory "{dirname}/"')

    try:
        usb_ids = open(filename, 'w+', encoding='utf-8')
    except PermissionError as e:
        raise USBRipError(f'Permission denied: "{filename}"',
                          errors={'initial_error': str(e)})

    db, latest_ver, latest_date, errcode, e = _get_latest_version()

    if errcode:
        usb_ids.close()
        os.remove(filename)

        if errcode == USBIDs._INTERNET_CONNECTION_ERROR:
            errmsg = 'No internet connection'
        elif errcode == USBIDs._SERVER_TIMEOUT_ERROR:
            errmsg = 'Server timeout'
        elif errcode == USBIDs._SERVER_CONTENT_ERROR:
            errmsg = 'Server content error: no version or date found'

        raise USBRipError(errmsg,
                          errors={
                              'errcode': errcode,
                              'initial_error': e
                          })

    usb_ids.write(db)
    usb_ids.seek(0)

    print_info('Database downloaded')

    print(f'Version:  {latest_ver}')
    print(f'Date:     {latest_date}')

    return usb_ids
Пример #20
0
    def change_password(storage_type,
                        old_password,
                        new_password,
                        *,
                        compression_level='5'):
        storage_full_path = '{}/{}.7z'.format(USBStorage._STORAGE_BASE,
                                              storage_type)
        if not os.path.isfile(storage_full_path):
            print_critical(
                'Storage not found: \'{}\''.format(storage_full_path))
            return

        try:
            out = _7zip_unpack(storage_full_path, old_password)
            if 'Everything is Ok' in out:
                os.remove(storage_full_path)

                base_filename = re.search(r'Extracting\s*(.*?$)', out,
                                          re.MULTILINE).group(1)
                json_file = '{}/{}'.format(USBStorage._STORAGE_BASE,
                                           base_filename)

                out = _7zip_pack(storage_full_path, json_file, new_password,
                                 compression_level)
                if 'Everything is Ok' in out:
                    print_info('Password was successfully changed')
                else:
                    print_critical(
                        'Undefined behaviour while creating storage',
                        initial_error=out)

                os.remove(json_file)

            else:
                print_critical('Undefined behaviour while unpacking storage',
                               initial_error=out)

        except USBRipError as e:
            print_critical(str(e),
                           errcode=e.errors['errcode'],
                           initial_error=e.errors['initial_error'])
            return
Пример #21
0
def _dump_events(events_to_show, list_name, filename, indent):
	print_info('Generating {} list (JSON)'.format(list_name))

	out = []
	for event in events_to_show:
		tmp_event_dict = OrderedDict()
		for key in ('conn', 'user', 'vid', 'pid', 'prod', 'manufact', 'serial', 'port', 'disconn'):
			tmp_event_dict[key] = event[key]
		out.append(tmp_event_dict)

	try:
		with open(filename, 'w', encoding='utf-8') as out_json:
			json.dump(out, out_json, indent=indent)
	except PermissionError as e:
		raise USBRipError(
			'Permission denied: \'{}\'. Retry with sudo'.format(filename),
			errors={'initial_error': str(e)}
		)

	print_info('New {} list: \'{}\''.format(list_name, os.path.abspath(filename)))
Пример #22
0
def _filter_events(all_events, sieve):
    if sieve is None:
        sieve = {'external': False, 'number': -1, 'dates': [], 'fields': {}}

    if sieve != {'external': False, 'number': -1, 'dates': [], 'fields': {}}:
        print_info('Filtering events')

    events_to_show = all_events

    if sieve['fields']:
        events_to_show = []
        for key, vals in sieve['fields'].items():
            events_to_show += [
                event for event in all_events for val in vals
                if event[key] == val
            ]

    if sieve['external']:
        events_to_show = [
            event for event in all_events if event['disconn'] is not None
        ]

    if sieve['dates']:
        events_to_show = [
            event for date in sieve['dates'] for event in events_to_show
            if event['conn'][:6] == date
        ]

    if not events_to_show:
        return []

    SIZE = len(events_to_show)
    if sieve['number'] == -1 or sieve['number'] >= SIZE:
        if sieve['number'] > SIZE:
            print_warning(
                f'USB action history has only {SIZE} entries instead of requested {sieve["number"]}, '
                f'displaying all of them...')

        sieve['number'] = SIZE

    return [events_to_show[SIZE - i] for i in range(sieve['number'], 0, -1)]
Пример #23
0
    def search_violations(self,
                          input_auth,
                          attributes,
                          columns,
                          *,
                          indent=4,
                          sieve=None,
                          repres=None):
        print_info(
            f'Opening authorized device list: "{os.path.abspath(input_auth)}"')

        try:
            auth = _process_auth_list(input_auth, indent)
        except json.decoder.JSONDecodeError as e:
            print_critical('Failed to decode authorized device list (JSON)',
                           initial_error=str(e))
            return

        print_info('Searching for violations')

        if not attributes:
            attributes = auth.keys()

        for event in self._all_events:
            try:
                if any(event[key] not in vals and event[key] is not None
                       for key, vals in zip(attributes, auth.values())):
                    self._violations.append(event)
            except KeyError as e:
                print_critical('No such attribute in authorized device list',
                               initial_error=str(e))
                return

        self._events_to_show = _filter_events(self._violations, sieve)
        if not self._events_to_show:
            print_info('No USB violation events found!')
            return

        if not cfg.QUIET and cfg.ISATTY:
            number, filename = _output_choice('violation', 'viol.json',
                                              'violations/')
            if number is None:
                return
            elif number == 1:
                try:
                    _dump_events(self._events_to_show, 'violations', filename,
                                 indent)
                except USBRipError as e:
                    print_critical(str(e),
                                   initial_error=e.errors['initial_error'])
                return

        if columns:
            table_data = [[COLUMN_NAMES[name] for name in columns]]
        else:
            columns = [key for key in COLUMN_NAMES.keys()]
            table_data = [[val for val in COLUMN_NAMES.values()]]

        _represent_events(self._events_to_show, columns, table_data,
                          'USB-Violation-Events', repres)
Пример #24
0
    def generate_auth_json(self,
                           output_auth,
                           attributes,
                           *,
                           indent=4,
                           sieve=None):
        self._events_to_show = _filter_events(self._all_events, sieve)
        if not self._events_to_show:
            print_info('No USB devices found!')
            return 1

        abs_output_auth = os.path.abspath(output_auth)

        try:
            dirname = os.path.dirname(abs_output_auth)
            os_makedirs(dirname)
        except USBRipError as e:
            print_critical(str(e), initial_error=e.errors['initial_error'])
            return 1
        else:
            print_info(f'Created "{dirname}"')

        try:
            auth_json = open(abs_output_auth, 'w', encoding='utf-8')
        except PermissionError as e:
            print_critical(
                f'Permission denied: "{abs_output_auth}". Retry with sudo',
                initial_error=str(e))
            return 1

        print_info('Generating authorized device list (JSON)')

        if not attributes:
            attributes = ('vid', 'pid', 'prod', 'manufact', 'serial')

        auth = defaultdict(list)
        for event in tqdm(self._events_to_show, ncols=80, unit='dev'):
            for key, val in event.items():
                if (key in attributes and val is not None
                        and val not in auth[key]):
                    auth[key].append(val)

        for key in auth.keys():
            auth[key].sort()

        json.dump(auth, auth_json, sort_keys=True, indent=indent)
        auth_json.close()

        print_info(f'New authorized device list: "{abs_output_auth}"')
Пример #25
0
def _update_database(filename):
	try:
		usb_ids = open(filename, 'r+', encoding='utf-8')
	except PermissionError as e:
		raise USBRipError(
			f'Permission denied: "{filename}"',
			errors={'initial_error': str(e)}
		)

	print_info('Getting current database version')
	curr_ver, curr_date = _get_current_version(usb_ids)
	print(f'Version:  {curr_ver}')
	print(f'Date:     {curr_date}')

	print_info('Checking local database for update')
	db, latest_ver, latest_date, errcode, e = _get_latest_version()

	if errcode:
		if errcode == USBIDs._INTERNET_CONNECTION_ERROR:
			print_warning(
				'No internet connection, using current version',
				errcode=errcode
			)

		elif errcode == USBIDs._SERVER_TIMEOUT_ERROR:
			print_warning(
				'Server timeout, using current version',
				errcode=errcode,
				initial_error=e
			)

		elif errcode == USBIDs._SERVER_CONTENT_ERROR:
			print_warning(
				'Server error, using current version',
				errcode=errcode,
				initial_error=e
			)

		return usb_ids

	if curr_ver != latest_ver and curr_date != latest_date:  # if there's newer database version
		print('Updating database... ', end='')

		usb_ids.write(db)
		usb_ids.truncate()
		usb_ids.seek(0)

		print('Done\n')

		print(f'Version:  {latest_ver}')
		print(f'Date:     {latest_date}')

	print_info('Local database is up-to-date')

	return usb_ids
Пример #26
0
def _represent_events(events_to_show, columns, table_data, title, repres):
    print_info('Preparing gathered events')

    if repres is None:
        repres = {'table': False, 'list': False, 'smart': True}

    max_len = {
        'conn':
        19,
        'user':
        max(max(len(event['user']) for event in events_to_show), len('User')),
        'vid':
        4,
        'pid':
        4,
        'prod':
        max(max(len(str(event['prod'])) for event in events_to_show),
            len('Product')),
        'manufact':
        max(max(len(str(event['manufact'])) for event in events_to_show),
            len('Manufacturer')),
        'serial':
        max(max(len(str(event['serial'])) for event in events_to_show),
            len('Serial Number')),
        'port':
        max(max(len(event['port']) for event in events_to_show), len('Port')),
        'disconn':
        19
    }

    prev_cday = ''
    for event in events_to_show:
        if 'conn' in columns:
            curr_cday = event['conn'][:10]
            if prev_cday != curr_cday:
                cday = [
                    f'{curr_cday} {BULLET * (len(event["conn"])-len(curr_cday)-1)}'
                ]
                table_data.append(cday + [
                    SEPARATOR * max_len[name]
                    for name in columns if name != 'conn'
                ])
            prev_cday = curr_cday

        row = []
        for name in columns:
            if event[name] is None:
                event[name] = ABSENCE

            item = event[name]
            if name == 'conn' and cfg.ISATTY:
                item = colored(item, 'green')
            elif name == 'disconn' and cfg.ISATTY:
                item = colored(item, 'red')

            row.append(item)

        table_data.append(row)

    event_table = _build_single_table(USBEvents.TableClass, table_data,
                                      colored(title, 'white', attrs=['bold']))

    # Display as table
    if cfg.ISATTY and (repres['smart'] and event_table.ok or repres['table']):
        print_info('Representation: Table')
        print('\n' + event_table.table)

    # Display as list
    elif not cfg.ISATTY or (repres['smart'] and not event_table.ok
                            or repres['list']):
        if not event_table.ok:
            print_warning(
                'Terminal window is too small to display table properly')
            print_warning('Representation: List')
        else:
            print_info('Representation: List')

        max_len = max(
            len(str(val))
            for event in events_to_show for val in event.values()) + len(
                'Serial Number:  ')  # max length string
        if not max_len // 2:
            max_len += 1

        if cfg.ISATTY:
            cprint('\n' + title, 'white', attrs=['bold'])
        else:
            print('\n' + title)

        print(SEPARATOR * max_len)

        for event in events_to_show:
            if cfg.ISATTY:
                print(
                    colored('Connected:      ', 'magenta', attrs=['bold']) +
                    colored(event['conn'], 'green'))
                print(
                    colored('User:           '******'magenta', attrs=['bold']) +
                    event['user'])
                print(
                    colored('VID:            ', 'magenta', attrs=['bold']) +
                    event['vid'])
                print(
                    colored('PID:            ', 'magenta', attrs=['bold']) +
                    event['pid'])
                print(
                    colored('Product:        ', 'magenta', attrs=['bold']) +
                    str(event['prod']))
                print(
                    colored('Manufacturer:   ', 'magenta', attrs=['bold']) +
                    str(event['manufact']))
                print(
                    colored('Serial Number:  ', 'magenta', attrs=['bold']) +
                    str(event['serial']))
                print(
                    colored('Bus-Port:       ', 'magenta', attrs=['bold']) +
                    event['port'])
                print(
                    colored('Disconnected:   ', 'magenta', attrs=['bold']) +
                    colored(event['disconn'], 'red'))
            else:
                print('Connected:      ' + event['conn'])
                print('User:           '******'user'])
                print('VID:            ' + event['vid'])
                print('PID:            ' + event['pid'])
                print('Product:        ' + str(event['prod']))
                print('Manufacturer:   ' + str(event['manufact']))
                print('Serial Number:  ' + str(event['serial']))
                print('Bus-Port:       ' + event['port'])
                print('Disconnected:   ' + event['disconn'])

            print(SEPARATOR * max_len)
Пример #27
0
def _filter_events(all_events, sieve):
    # sieve = {
    #    'external': False,
    #    'dates':       [],
    #    'fields':      {},
    #    'number':      -1
    # }

    if sieve is None:
        return all_events

    else:
        print_info('Filtering events')

        events_by_external = []
        if sieve['external']:
            for event in all_events:
                if event['disconn'] is not None:
                    events_by_external.append(event)
                    continue
        else:
            events_by_external = all_events

        events_by_date = []
        if sieve['dates']:
            for event in all_events:
                for date in sieve['dates']:
                    if event['conn'].startswith(date):
                        events_by_date.append(event)
                        break
                continue
        else:
            events_by_date = all_events

        event_intersection = intersect_event_sets(events_by_external,
                                                  events_by_date)

        events_to_show = []
        if sieve['fields']:
            for event in event_intersection:
                for key, vals in sieve['fields'].items():
                    if any(event[key] == val for val in vals):
                        events_to_show.append(event)
                        break
        else:
            events_to_show = event_intersection

        if not events_to_show:
            return []

        SIZE = len(events_to_show)
        if sieve['number'] <= -1 or sieve['number'] > SIZE:
            if sieve['number'] < -1:
                print_warning(
                    f'usbrip can\'t handle dark matter \"--number={sieve["number"]}\", so it will show '
                    f'all {SIZE} USB history entries available')

            elif sieve['number'] > SIZE:
                print_warning(
                    f'USB history has only {SIZE} entries instead of requested {sieve["number"]}, '
                    f'displaying all of them...')

            sieve['number'] = SIZE

        return [
            events_to_show[SIZE - i] for i in range(sieve['number'], 0, -1)
        ]
Пример #28
0
    def create_storage(storage_type,
                       *,
                       password=None,
                       input_auth=None,
                       attributes=None,
                       compression_level='5',
                       indent=4,
                       sieve=None):
        if storage_type == 'history':
            events_to_show = _get_history_events(sieve)
        elif storage_type == 'violations':
            try:
                events_to_show = _get_violation_events(sieve, input_auth,
                                                       attributes, indent)
            except USBRipError as e:
                print_critical(str(e), initial_error=e.errors['initial_error'])
                return 1

        if events_to_show is None:
            return 1

        if events_to_show:
            min_date, max_date = _get_dates(events_to_show)
            json_file = '{}/{}-{}.json'.format(USBStorage._STORAGE_BASE,
                                               min_date, max_date)
        else:
            json_file = '{}/{}.json'.format(USBStorage._STORAGE_BASE,
                                            datetime.now().strftime('%m%d'))

        try:
            _dump_events(events_to_show, storage_type, json_file, indent)
        except USBRipError as e:
            print_critical(str(e), initial_error=e.errors['initial_error'])
            return 1

        if password is None:
            print_warning('No password provided, generating random one')
            password = _gen_random_password(12)

        storage_full_path = '{}/{}.7z'.format(USBStorage._STORAGE_BASE,
                                              storage_type)
        if os.path.exists(storage_full_path):
            os.remove(storage_full_path)

        try:
            out = _7zip_pack(storage_full_path, json_file, password,
                             compression_level)
        except USBRipError as e:
            os.remove(json_file)
            print_critical(str(e),
                           errcode=e.errors['errcode'],
                           initial_error=e.errors['initial_error'])
            return 1

        if 'Everything is Ok' in out:
            print_info('New {} storage: \'{}\''.format(storage_type,
                                                       storage_full_path))
            print_secret('Your password is', secret=password)
            os.remove(json_file)
        else:
            print_critical('Undefined behaviour while creating storage',
                           initial_error=out)
Пример #29
0
def _read_log_file(filename, log=None):
    filtered = []

    if log is None:
        abs_filename = os.path.abspath(filename)

        if abs_filename.endswith('.gz'):
            print_info(f'Unpacking "{abs_filename}"')

            try:
                log = gzip.open(abs_filename, 'rb')
            except PermissionError as e:
                print_warning(
                    f'Permission denied: "{abs_filename}". Retry with sudo',
                    initial_error=str(e))
                return filtered
            else:
                end_of_file = b''
                abs_filename = os.path.splitext(abs_filename)

        else:
            log = codecs.open(abs_filename,
                              'r',
                              encoding='utf-8',
                              errors='ignore')
            end_of_file = ''

        print_info(f'Reading "{abs_filename}"')

    else:
        abs_filename = 'journalctl output'
        end_of_file = ''
        print_info(f'Reading journalctl output')

    regex = re.compile(r'(?:]|:) usb (.*?): ')
    for line in tqdm(iter(log.readline, end_of_file), unit='line'):
        if isinstance(line, bytes):
            line = line.decode('utf-8', errors='ignore')

        if regex.search(line):
            # Case 1 -- Modified Timestamp ("%Y-%m-%dT%H:%M:%S.%f%z")

            date = line[:32].strip()
            if date.count(':') == 3:
                date = ''.join(
                    line[:32].rsplit(':', 1)
                )  # rreplace(':', '', 1) to remove the last ':' from "2019-08-09T06:15:49.655261-04:00" timestamp if there is one

            try:
                date = datetime.strptime(
                    date, '%Y-%m-%dT%H:%M:%S.%f%z'
                )  # ex. "2019-08-09T06:15:49.655261-0400"

            except ValueError:
                # Case 2 -- Non-Modified Timestamp ("%b %d %H:%M:%S")

                date = line[:15].strip()
                if '  ' in date:
                    date = date.replace('  ', ' 0',
                                        1)  # pad day of the week with zero

                try:
                    date = datetime.strptime(
                        date, '%b %d %H:%M:%S')  # ex. "Mar 18 13:56:07"
                except ValueError as e:
                    raise USBRipError(
                        f'Wrong timestamp format found in "{abs_filename}"',
                        errors={'initial_error': str(e)})
                else:
                    date = date.strftime('????-%m-%d %H:%M:%S')
                    logline = line[15:].strip()

            else:
                date = date.strftime('%Y-%m-%d %H:%M:%S')
                logline = line[32:].strip()

            if any(pat in line
                   for pat in ('New USB device found, ', 'Product: ',
                               'Manufacturer: ', 'SerialNumber: ')):
                filtered.append((date, 'c', logline))
            elif 'disconnect' in line:
                filtered.append((date, 'd', logline))

    log.close()
    return filtered
Пример #30
0
	def update_storage(
		storage_type,
		password,
		*,
		input_auth=None,
		attributes=None,
		compression_level='5',
		indent=4,
		sieve=None
	):
		if storage_type == 'history':
			events_to_show = _get_history_events(sieve)
		elif storage_type == 'violations':
			try:
				events_to_show = _get_violation_events(sieve, input_auth, attributes, indent)
			except USBRipError as e:
				print_critical(str(e), initial_error=e.errors['initial_error'])
				return 1

		if events_to_show is None:
			return 1

		if events_to_show:
			min_date, max_date = _get_dates(events_to_show)
		else:
			print_info('No events to append')
			return 1

		storage_full_path = f'{USBStorage._STORAGE_BASE}/{storage_type}.7z'
		if not os.path.isfile(storage_full_path):
			print_critical(f'Storage not found: "{storage_full_path}"')
			return 1

		print_info(f'Updating storage: "{storage_full_path}"')

		try:
			out = _7zip_unpack(storage_full_path, password)
		except USBRipError as e:
			print_critical(str(e), errcode=e.errors['errcode'], initial_error=e.errors['initial_error'])
			return 1

		if 'Everything is Ok' in out:
			base_filename = re.search(r'([^\n ]*\.json)', _7zip_list(storage_full_path, password), re.MULTILINE).group(1)
			json_file = f'{USBStorage._STORAGE_BASE}/{base_filename}'
			os.remove(storage_full_path)

			with open(json_file, 'r', encoding='utf-8') as dump:
				events_dumped = json.load(dump)
			os.remove(json_file)

			merged_events = _merge_json_events(events_dumped, events_to_show)

			if len(base_filename) > 9:  # len('mmdd.json') == 9
				min_date = base_filename[:4]

			new_json_file = f'{USBStorage._STORAGE_BASE}/{min_date}-{max_date}.json'
			_dump_events(merged_events, storage_type, new_json_file, indent)

			try:
				out = _7zip_pack(storage_full_path, new_json_file, password, compression_level)
			except USBRipError as e:
				os.remove(new_json_file)
				print_critical(str(e), errcode=e.errors['errcode'], initial_error=e.errors['initial_error'])
				return 1

			if 'Everything is Ok' in out:
				print_info('Storage was successfully updated')
			else:
				print_critical('Undefined behaviour while creating storage', initial_error=out)

			os.remove(new_json_file)

		else:
			print_critical('Undefined behaviour while unpacking storage', initial_error=out)