示例#1
0
 def signal_server_event_db(self, _, event_type, rows):
     get_node = lambda id: self.rpc.graphql(self.node_query,
                                            {'id': str(id)})['db']['node']
     for row in rows:
         if str(row.campaign_id) != self.config['campaign_id']:
             continue
         model = self.gobjects['treeview_campaign'].get_model()
         for case in utilities.switch(event_type):
             if case('inserted'):
                 row_data = self.format_node_data(get_node(row.id))
                 row_data = list(map(self.format_cell_data, row_data))
                 row_data.insert(0, str(row.id))
                 gui_utilities.glib_idle_add_wait(model.append, row_data)
             ti = gui_utilities.gtk_list_store_search(model, str(row.id))
             if ti is None:
                 self.logger.warning(
                     "received server db event: {0} for non-existent row {1}:{2}"
                     .format(event_type, self.table_name, str(row.id)))
                 break
             if case('deleted'):
                 model.remove(ti)
                 break
             if case('updated'):
                 row_data = self.format_node_data(get_node(row.id))
                 for idx, cell_data in enumerate(row_data, 1):
                     model[ti][idx] = self.format_cell_data(cell_data)
                 break
示例#2
0
	def session_has_permissions(self, access, session):
		"""
		Check that the authenticated session has the permissions specified in
		*access*. The permissions in *access* are abbreviated with the first
		letter of create, read, update, and delete.

		:param str access: The desired permissions.
		:param session: The authenticated session to check access for.
		:return: Whether the session has the desired permissions.
		:rtype: bool
		"""
		if self.is_private:
			return False
		access = access.lower()
		for case in utilities.switch(access, comp=operator.contains, swapped=True):
			if case('c') and not self.session_has_create_access(session):
				break
			if case('r') and not self.session_has_read_access(session):
				break
			if case('u') and not self.session_has_update_access(session):
				break
			if case('d') and not self.session_has_delete_access(session):
				break
		else:
			return True
		return False
示例#3
0
	def session_has_permissions(self, access, session):
		"""
		Check that the authenticated session has the permissions specified in
		*access*. The permissions in *access* are abbreviated with the first
		letter of create, read, update, and delete.

		:param str access: The desired permissions.
		:param session: The authenticated session to check access for.
		:return: Whether the session has the desired permissions.
		:rtype: bool
		"""
		if self.is_private:
			return False
		access = access.lower()
		for case in utilities.switch(access, comp=operator.contains, swapped=True):
			if case('c') and not self.session_has_create_access(session):
				break
			if case('r') and not self.session_has_read_access(session):
				break
			if case('u') and not self.session_has_update_access(session):
				break
			if case('d') and not self.session_has_delete_access(session):
				break
		else:
			return True
		return False
示例#4
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher TOTP Enrollment Utility', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	config_group = parser.add_mutually_exclusive_group(required=True)
	config_group.add_argument('-c', '--config', dest='server_config', type=argparse.FileType('r'), help='the server configuration file')
	config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url')
	parser.add_argument('--otp', dest='otp_secret', help='a specific otp secret')
	parser.add_argument('user', help='the user to mange')
	parser.add_argument('action', choices=('remove', 'set', 'show'), help='the action to preform')
	parser.epilog = PARSER_EPILOG
	arguments = parser.parse_args()

	utilities.configure_stream_logger(arguments.loglvl, arguments.logger)

	if arguments.database_url:
		database_connection_url = arguments.database_url
	elif arguments.server_config:
		server_config = yaml.load(arguments.server_config)
		database_connection_url = server_config['server']['database']
	else:
		raise RuntimeError('no database connection was specified')

	manager.init_database(database_connection_url)
	session = manager.Session()
	user = session.query(models.User).filter_by(id=arguments.user).first()
	if not user:
		color.print_error("invalid user id: {0}".format(arguments.user))
		return

	for case in utilities.switch(arguments.action):
		if case('remove'):
			user.otp_secret = None
			break
		if case('set'):
			if user.otp_secret:
				color.print_error("the specified user already has an otp secret set")
				return
			if arguments.otp_secret:
				new_otp = arguments.otp_secret
			else:
				new_otp = pyotp.random_base32()
			if len(new_otp) != 16:
				color.print_error("invalid otp secret length, must be 16")
				return
			user.otp_secret = new_otp
			break

	if user.otp_secret:
		color.print_status("user: {0} otp: {1}".format(user.id, user.otp_secret))
		totp = pyotp.TOTP(user.otp_secret)
		uri = totp.provisioning_uri(user.id + '@king-phisher') + '&issuer=King%20Phisher'
		color.print_status("provisioning uri: {0}".format(uri))
	else:
		color.print_status("user: {0} otp: N/A".format(user.id))
	session.commit()
示例#5
0
def to_elementtree_subelement(parent, tag, value, attrib=None):
    """
	Serialize *value* to an :py:class:`xml.etree.ElementTree.SubElement` with
	appropriate information describing it's type. If *value* is not of a
	supported type, a :py:exc:`TypeError` will be raised.

	:param parent: The parent element to associate this subelement with.
	:type parent: :py:class:`xml.etree.ElementTree.Element`
	:param str tag: The name of the XML tag.
	:param value: The value to serialize to an XML element.
	:param dict attrib: Optional attributes to include in the element.
	:return: The newly created XML element, representing *value*.
	:rtype: :py:class:`xml.etree.ElementTree.Element`
	"""
    attrib = attrib or {}
    for case in switch(type(value)):
        if case(type(None)):
            value = ''
            type_ = 'null'
            break
        if case(bool):
            value = str(value).lower()
            type_ = 'boolean'
            break
        if case(datetime.date):
            value = value.isoformat()
            type_ = 'date'
            break
        if case(datetime.datetime):
            value = value.isoformat()
            type_ = 'datetime'
            break
        if case(float):
            value = str(value)
            type_ = 'float'
            break
        if case(int):
            value = str(value)
            type_ = 'integer'
            break
        if case(str):
            type_ = 'string'
            break
        if case(datetime.time):
            value = value.isoformat()
            type_ = 'time'
            break
    else:
        raise TypeError('can not serialize value to an xml subelement')
    attrib['type'] = type_
    sub_element = ET.SubElement(parent, tag, attrib=attrib)
    sub_element.text = value
    return sub_element
示例#6
0
def to_elementtree_subelement(parent, tag, value, attrib=None):
	"""
	Serialize *value* to an :py:class:`xml.etree.ElementTree.SubElement` with
	appropriate information describing it's type. If *value* is not of a
	supported type, a :py:exc:`TypeError` will be raised.

	:param parent: The parent element to associate this subelement with.
	:type parent: :py:class:`xml.etree.ElementTree.Element`
	:param str tag: The name of the XML tag.
	:param value: The value to serialize to an XML element.
	:param dict attrib: Optional attributes to include in the element.
	:return: The newly created XML element, representing *value*.
	:rtype: :py:class:`xml.etree.ElementTree.Element`
	"""
	attrib = attrib or {}
	for case in switch(type(value)):
		if case(type(None)):
			value = ''
			type_ = 'null'
			break
		if case(bool):
			value = str(value).lower()
			type_ = 'boolean'
			break
		if case(datetime.date):
			value = value.isoformat()
			type_ = 'date'
			break
		if case(datetime.datetime):
			value = value.isoformat()
			type_ = 'datetime'
			break
		if case(float):
			value = str(value)
			type_ = 'float'
			break
		if case(int):
			value = str(value)
			type_ = 'integer'
			break
		if case(str) or (its.py_v2 and case(unicode)):
			type_ = 'string'
			break
		if case(datetime.time):
			value = value.isoformat()
			type_ = 'time'
			break
	else:
		raise TypeError('can not serialize value to an xml subelement')
	attrib['type'] = type_
	sub_element = ET.SubElement(parent, tag, attrib=attrib)
	sub_element.text = value
	return sub_element
示例#7
0
def _json_default(obj):
	for case in switch(obj.__class__):
		if case(datetime.date):
			obj_type, obj_value = 'datetime.date', obj.isoformat()
			break
		if case(datetime.datetime):
			obj_type, obj_value = 'datetime.datetime', obj.isoformat()
			break
		if case(datetime.time):
			obj_type, obj_value = 'datetime.time', obj.isoformat()
			break
	else:
		raise TypeError('Unknown type: ' + repr(obj))
	return {'__complex_type__': obj_type, 'value': obj_value}
示例#8
0
def _serialize_ext_load(obj_type, obj_value, default):
	for case in switch(obj_type):
		if case('datetime.date'):
			value = datetime.datetime.strptime(obj_value, '%Y-%m-%d').date()
			break
		if case('datetime.datetime'):
			value = datetime.datetime.strptime(obj_value, '%Y-%m-%dT%H:%M:%S' + ('.%f' if '.' in obj_value else ''))
			break
		if case('datetime.time'):
			value = datetime.datetime.strptime(obj_value, '%H:%M:%S' + ('.%f' if '.' in obj_value else '')).time()
			break
	else:
		return default
	return value
示例#9
0
def _serialize_ext_dump(obj):
    for case in switch(obj.__class__):
        if case(datetime.date):
            obj_type, obj_value = 'datetime.date', obj.isoformat()
            break
        if case(datetime.datetime):
            obj_type, obj_value = 'datetime.datetime', obj.isoformat()
            break
        if case(datetime.time):
            obj_type, obj_value = 'datetime.time', obj.isoformat()
            break
    else:
        raise TypeError('Unknown type: ' + repr(obj))
    return obj_type, obj_value
示例#10
0
def _serialize_ext_load(obj_type, obj_value, default):
    for case in switch(obj_type):
        if case('datetime.date'):
            value = dateutil.parser.parse(obj_value).date()
            break
        if case('datetime.datetime'):
            value = dateutil.parser.parse(obj_value)
            break
        if case('datetime.time'):
            value = dateutil.parser.parse(obj_value).time()
            break
    else:
        return default
    return value
示例#11
0
def _serialize_ext_load(obj_type, obj_value, default):
	for case in switch(obj_type):
		if case('datetime.date'):
			value = dateutil.parser.parse(obj_value).date()
			break
		if case('datetime.datetime'):
			value = dateutil.parser.parse(obj_value)
			break
		if case('datetime.time'):
			value = dateutil.parser.parse(obj_value).time()
			break
	else:
		return default
	return value
示例#12
0
def _json_default(obj):
	for case in switch(obj.__class__):
		if case(datetime.date):
			obj_type, obj_value = 'datetime.date', obj.isoformat()
			break
		if case(datetime.datetime):
			obj_type, obj_value = 'datetime.datetime', obj.isoformat()
			break
		if case(datetime.time):
			obj_type, obj_value = 'datetime.time', obj.isoformat()
			break
	else:
		raise TypeError('Unknown type: ' + repr(obj))
	return {'__complex_type__': obj_type, 'value': obj_value}
示例#13
0
def _serialize_ext_dump(obj):
	for case in switch(obj.__class__):
		if case(datetime.date):
			obj_type, obj_value = 'datetime.date', obj.isoformat()
			break
		if case(datetime.datetime):
			obj_type, obj_value = 'datetime.datetime', obj.isoformat()
			break
		if case(datetime.time):
			obj_type, obj_value = 'datetime.time', obj.isoformat()
			break
	else:
		raise TypeError('Unknown type: ' + repr(obj))
	return obj_type, obj_value
示例#14
0
def _json_object_hook(obj):
	obj_type = obj.get('__complex_type__')
	obj_value = obj.get('value')
	for case in switch(obj_type):
		if case('datetime.date'):
			value = datetime.datetime.strptime(obj_value, '%Y-%m-%d').date()
			break
		if case('datetime.datetime'):
			value = datetime.datetime.strptime(obj_value, '%Y-%m-%dT%H:%M:%S' + ('.%f' if '.' in obj_value else ''))
			break
		if case('datetime.time'):
			value = datetime.datetime.strptime(obj_value, '%H:%M:%S' + ('.%f' if '.' in obj_value else '')).time()
			break
	else:
		return obj
	return value
示例#15
0
def _json_object_hook(obj):
	obj_type = obj.get('__complex_type__')
	obj_value = obj.get('value')
	for case in switch(obj_type):
		if case('datetime.date'):
			value = datetime.datetime.strptime(obj_value, '%Y-%m-%d').date()
			break
		if case('datetime.datetime'):
			value = datetime.datetime.strptime(obj_value, '%Y-%m-%dT%H:%M:%S' + ('.%f' if '.' in obj_value else ''))
			break
		if case('datetime.time'):
			value = datetime.datetime.strptime(obj_value, '%H:%M:%S' + ('.%f' if '.' in obj_value else '')).time()
			break
	else:
		return obj
	return value
示例#16
0
def from_elementtree_element(element, require_type=True):
    """
	Load a value from an :py:class:`xml.etree.ElementTree.SubElement` instance.
	If *require_type* is True, then the element must specify an acceptable
	value via the "type" attribute. If *require_type* is False and no type
	attribute is specified, the value is returned as a string.

	:param element: The element to load a value from.
	:type element: :py:class:`xml.etree.ElementTree.Element`
	:param bool require_type: Whether or not to require type information.
	:return: The deserialized value from the element.
	"""
    if require_type and not 'type' in element.attrib:
        raise TypeError('type is not specified in the element attributes')
    type_ = element.attrib.get('type', 'string')
    value = element.text
    for case in switch(type_):
        if case('boolean'):
            value = value.lower()
            if not value in ('true', 'false'):
                raise ValueError('unknown boolean value: ' + value)
            value = value == 'true'
            break
        if case('date'):
            value = dateutil.parser.parse(value).date()
            break
        if case('datetime'):
            value = dateutil.parser.parse(value)
            break
        if case('float'):
            value = float(value)
            break
        if case('integer'):
            value = int(value)
            break
        if case('null'):
            value = None
            break
        if case('string'):
            value = value or ''
            break
        if case('time'):
            value = dateutil.parser.parse(value).time()
    else:
        raise TypeError('can not serialize value to an xml subelement')
    return value
示例#17
0
def from_elementtree_element(element, require_type=True):
	"""
	Load a value from an :py:class:`xml.etree.ElementTree.SubElement` instance.
	If *require_type* is True, then the element must specify an acceptable
	value via the "type" attribute. If *require_type* is False and no type
	attribute is specified, the value is returned as a string.

	:param element: The element to load a value from.
	:type element: :py:class:`xml.etree.ElementTree.Element`
	:param bool require_type: Whether or not to require type information.
	:return: The deserialized value from the element.
	"""
	if require_type and not 'type' in element.attrib:
		raise TypeError('type is not specified in the element attributes')
	type_ = element.attrib.get('type', 'string')
	value = element.text
	for case in switch(type_):
		if case('boolean'):
			value = value.lower()
			if not value in ('true', 'false'):
				raise ValueError('unknown boolean value: ' + value)
			value = value == 'true'
			break
		if case('date'):
			value = dateutil.parser.parse(value).date()
			break
		if case('datetime'):
			value = dateutil.parser.parse(value)
			break
		if case('float'):
			value = float(value)
			break
		if case('integer'):
			value = int(value)
			break
		if case('null'):
			value = None
			break
		if case('string'):
			value = value or ''
			break
		if case('time'):
			value = dateutil.parser.parse(value).time()
	else:
		raise TypeError('can not serialize value to an xml subelement')
	return value
示例#18
0
    def session_has_permissions(self, access, session):
        """
		Check that the authenticated session has the permissions specified in
		*access*. The permissions in *access* are abbreviated with the first
		letter of create, read, update, and delete. For example, to check for
		read and update permissions, *access* would be ``'ru'``.

		.. note::
			This will always return ``True`` for sessions which are for
			administrative users. To maintain this logic, this method **should
			not** be overridden in subclasses. Instead override the specific
			``_session_has_*_access`` methods as necessary.

		:param str access: The desired permissions.
		:param session: The authenticated session to check access for.
		:return: Whether the session has the desired permissions.
		:rtype: bool
		"""
        if session.user_is_admin:
            return True
        cls = self.__class__
        if cls.is_private:
            return False
        access = access.lower()
        for case in utilities.switch(access,
                                     comp=operator.contains,
                                     swapped=True):
            if case('c') and not cls.session_has_create_access(session,
                                                               instance=self):
                break
            if case('r') and not cls.session_has_read_access(session,
                                                             instance=self):
                break
            if case('u') and not cls.session_has_update_access(session,
                                                               instance=self):
                break
            if case('d') and not cls.session_has_delete_access(session,
                                                               instance=self):
                break
        else:
            return True
        return False
示例#19
0
	def signal_server_event_db(self, _, event_type, rows):
		get_node = lambda id: self.rpc.graphql(self.node_query, {'id': str(id)})['db']['node']
		for row in rows:
			if str(row.campaign_id) != self.config['campaign_id']:
				continue
			for case in utilities.switch(event_type):
				if case('inserted'):
					row_data = (str(row.id),) + tuple(self.format_node_data(get_node(row.id)))
					gui_utilities.glib_idle_add_wait(self._tv_model.append, row_data)
				ti = gui_utilities.gtk_list_store_search(self._tv_model, str(row.id))
				if ti is None:
					self.logger.warning("received server db event: {0} for non-existent row {1}:{2}".format(event_type, self.table_name, str(row.id)))
					break
				if case('deleted'):
					self._tv_model.remove(ti)
					break
				if case('updated'):
					row_data = self.format_node_data(get_node(row.id))
					for idx, cell_data in enumerate(row_data, 1):
						self._tv_model[ti][idx] = cell_data
					break
示例#20
0
	def session_has_permissions(self, access, session):
		"""
		Check that the authenticated session has the permissions specified in
		*access*. The permissions in *access* are abbreviated with the first
		letter of create, read, update, and delete. For example, to check for
		read and update permissions, *access* would be ``'ru'``.

		.. note::
			This will always return ``True`` for sessions which are for
			administrative users. To maintain this logic, this method **should
			not** be overridden in subclasses. Instead override the specific
			``_session_has_*_access`` methods as necessary.

		:param str access: The desired permissions.
		:param session: The authenticated session to check access for.
		:return: Whether the session has the desired permissions.
		:rtype: bool
		"""
		if session.user_is_admin:
			return True
		cls = self.__class__
		if cls.is_private:
			return False
		access = access.lower()
		for case in utilities.switch(access, comp=operator.contains, swapped=True):
			if case('c') and not cls.session_has_create_access(session, instance=self):
				break
			if case('r') and not cls.session_has_read_access(session, instance=self):
				break
			if case('u') and not cls.session_has_update_access(session, instance=self):
				break
			if case('d') and not cls.session_has_delete_access(session, instance=self):
				break
		else:
			return True
		return False
示例#21
0
	def __init__(self, organizer_email, start, summary, organizer_cn=None, description=None, duration='1h', location=None):
		"""
		:param str organizer_email: The email of the event organizer.
		:param start: The start time for the event.
		:type start: :py:class:`datetime.datetime`
		:param str summary: A short summary of the event.
		:param str organizer_cn: The name of the event organizer.
		:param str description: A more complete description of the event than
			what is provided by the *summary* parameter.
		:param duration: The events scheduled duration.
		:type duration: int, str, :py:class:`~datetime.timedelta`, :py:class:`.DurationAllDay`
		:param str location: The location for the event.
		"""
		utilities.assert_arg_type(start, datetime.datetime, 2)
		super(Calendar, self).__init__()
		if start.tzinfo is None:
			start = start.replace(tzinfo=dateutil.tz.tzlocal())
		start = start.astimezone(dateutil.tz.tzutc())

		for case in utilities.switch(duration, comp=isinstance):
			if case(str):
				duration = smoke_zephyr.utilities.parse_timespan(duration)
				duration = datetime.timedelta(seconds=duration)
				break
			if case(int):
				duration = datetime.timedelta(seconds=duration)
				break
			if case(datetime.timedelta):
				break
			if case(DurationAllDay):
				break
		else:
			raise TypeError('unknown duration type')

		self.add('method', 'REQUEST')
		self.add('prodid', 'Microsoft Exchange Server 2010')
		self.add('version', '2.0')

		self._event = icalendar.Event()
		event = self._event
		self.add_component(event)
		self.add_component(Timezone())

		organizer = icalendar.vCalAddress('MAILTO:' + organizer_email)
		organizer.params['cn'] = icalendar.vText(organizer_cn or organizer_email)
		event['organizer'] = organizer

		event.add('description', description or summary)
		event.add('uid', str(uuid.uuid4()))
		event.add('summary', summary)
		if isinstance(duration, DurationAllDay):
			event.add('dtstart', start.date())
			event.add('dtend', (start + datetime.timedelta(days=duration.days)).date())
		else:
			event.add('dtstart', start)
			event.add('dtend', start + duration)
		event.add('class', 'PUBLIC')
		event.add('priority', 5)
		event.add('dtstamp', datetime.datetime.now(dateutil.tz.tzutc()))
		event.add('transp', 'OPAQUE')
		event.add('status', 'CONFIRMED')
		event.add('sequence', 0)
		if location:
			event.add('location', icalendar.vText(location))

		alarm = icalendar.Alarm()
		alarm.add('description', 'REMINDER')
		alarm.add('trigger;related=start', '-PT1H')
		alarm.add('action', 'DISPLAY')
		event.add_component(alarm)
示例#22
0
    def __init__(self,
                 organizer_email,
                 start,
                 summary,
                 organizer_cn=None,
                 description=None,
                 duration='1h',
                 location=None):
        """
		:param str organizer_email: The email of the event organizer.
		:param start: The start time for the event.
		:type start: :py:class:`datetime.datetime`
		:param str summary: A short summary of the event.
		:param str organizer_cn: The name of the event organizer.
		:param str description: A more complete description of the event than
			what is provided by the *summary* parameter.
		:param duration: The events scheduled duration.
		:type duration: int, str, :py:class:`~datetime.timedelta`, :py:class:`.DurationAllDay`
		:param str location: The location for the event.
		"""
        utilities.assert_arg_type(start, datetime.datetime, 2)
        super(Calendar, self).__init__()
        if start.tzinfo is None:
            start = start.replace(tzinfo=dateutil.tz.tzlocal())
        start = start.astimezone(dateutil.tz.tzutc())

        for case in utilities.switch(duration, comp=isinstance):
            if case(str):
                duration = smoke_zephyr.utilities.parse_timespan(duration)
                duration = datetime.timedelta(seconds=duration)
                break
            if case(int):
                duration = datetime.timedelta(seconds=duration)
                break
            if case(datetime.timedelta):
                break
            if case(DurationAllDay):
                break
        else:
            raise TypeError('unknown duration type')

        self.add('method', 'REQUEST')
        self.add('prodid', 'Microsoft Exchange Server 2010')
        self.add('version', '2.0')

        self._event = icalendar.Event()
        event = self._event
        self.add_component(event)
        self.add_component(Timezone())

        organizer = icalendar.vCalAddress('MAILTO:' + organizer_email)
        organizer.params['cn'] = icalendar.vText(organizer_cn
                                                 or organizer_email)
        event['organizer'] = organizer

        event.add('description', description or summary)
        event.add('uid', str(uuid.uuid4()))
        event.add('summary', summary)
        if isinstance(duration, DurationAllDay):
            event.add('dtstart', start.date())
            event.add('dtend',
                      (start + datetime.timedelta(days=duration.days)).date())
        else:
            event.add('dtstart', start)
            event.add('dtend', start + duration)
        event.add('class', 'PUBLIC')
        event.add('priority', 5)
        event.add('dtstamp', datetime.datetime.now(dateutil.tz.tzutc()))
        event.add('transp', 'OPAQUE')
        event.add('status', 'CONFIRMED')
        event.add('sequence', 0)
        if location:
            event.add('location', icalendar.vText(location))

        alarm = icalendar.Alarm()
        alarm.add('description', 'REMINDER')
        alarm.add('trigger;related=start', '-PT1H')
        alarm.add('action', 'DISPLAY')
        event.add_component(alarm)
示例#23
0
def main():
    parser = argparse.ArgumentParser(
        conflict_handler='resolve',
        description=PARSER_DESCRIPTION,
        epilog=PARSER_EPILOG,
        formatter_class=argparse.RawTextHelpFormatter)
    utilities.argp_add_args(parser)
    config_group = parser.add_mutually_exclusive_group(required=True)
    config_group.add_argument('-c',
                              '--config',
                              dest='server_config',
                              help='the server configuration file')
    config_group.add_argument('-u',
                              '--url',
                              dest='database_url',
                              help='the database connection url')
    parser.add_argument('--force',
                        dest='force',
                        action='store_true',
                        default=False,
                        help='create the user if necessary')
    parser.add_argument('--otp',
                        dest='otp_secret',
                        help='a specific otp secret')
    if has_qrcode:
        parser.add_argument('--qrcode',
                            dest='qrcode_filename',
                            help='generate a qrcode image file')
    parser.add_argument('user', help='the user to mange')
    parser.add_argument('action',
                        choices=('remove', 'set', 'show'),
                        help='the action to preform')
    parser.epilog = PARSER_EPILOG
    arguments = parser.parse_args()

    if arguments.database_url:
        database_connection_url = arguments.database_url
    elif arguments.server_config:
        server_config = configuration.ex_load_config(arguments.server_config)
        database_connection_url = server_config.get('server.database')
    else:
        raise RuntimeError('no database connection was specified')

    manager.init_database(database_connection_url)
    session = manager.Session()
    user = session.query(models.User).filter_by(name=arguments.user).first()
    if not user:
        if not arguments.force:
            color.print_error("invalid user id: {0}".format(arguments.user))
            return
        user = models.User(name=arguments.user)
        session.add(user)
        color.print_status('the specified user was created')

    for case in utilities.switch(arguments.action):
        if case('remove'):
            user.otp_secret = None
            break
        if case('set'):
            if user.otp_secret:
                color.print_error(
                    "the specified user already has an otp secret set")
                return
            if arguments.otp_secret:
                new_otp = arguments.otp_secret
            else:
                new_otp = pyotp.random_base32()
            if len(new_otp) != 16:
                color.print_error("invalid otp secret length, must be 16")
                return
            user.otp_secret = new_otp
            break

    if user.otp_secret:
        color.print_status("user: {0} otp: {1}".format(user.name,
                                                       user.otp_secret))
        totp = pyotp.TOTP(user.otp_secret)
        uri = totp.provisioning_uri(user.name +
                                    '@king-phisher') + '&issuer=King%20Phisher'
        color.print_status("provisioning uri: {0}".format(uri))
        if has_qrcode and arguments.qrcode_filename:
            img = qrcode.make(uri)
            img.save(arguments.qrcode_filename)
            color.print_status("wrote qrcode image to: " +
                               arguments.qrcode_filename)
    else:
        color.print_status("user: {0} otp: N/A".format(user.id))
    session.commit()
示例#24
0
def main():
	parser = argparse.ArgumentParser(description='King Phisher TOTP Enrollment Utility', conflict_handler='resolve')
	utilities.argp_add_args(parser)
	config_group = parser.add_mutually_exclusive_group(required=True)
	config_group.add_argument('-c', '--config', dest='server_config', help='the server configuration file')
	config_group.add_argument('-u', '--url', dest='database_url', help='the database connection url')
	parser.add_argument('--force', dest='force', action='store_true', default=False, help='create the user if necessary')
	parser.add_argument('--otp', dest='otp_secret', help='a specific otp secret')
	if has_qrcode:
		parser.add_argument('--qrcode', dest='qrcode_filename', help='generate a qrcode image file')
	parser.add_argument('user', help='the user to mange')
	parser.add_argument('action', choices=('remove', 'set', 'show'), help='the action to preform')
	parser.epilog = PARSER_EPILOG
	arguments = parser.parse_args()

	if arguments.database_url:
		database_connection_url = arguments.database_url
	elif arguments.server_config:
		server_config = configuration.ex_load_config(arguments.server_config)
		database_connection_url = server_config.get('server.database')
	else:
		raise RuntimeError('no database connection was specified')

	manager.init_database(database_connection_url)
	session = manager.Session()
	user = session.query(models.User).filter_by(name=arguments.user).first()
	if not user:
		if not arguments.force:
			color.print_error("invalid user id: {0}".format(arguments.user))
			return
		user = models.User(name=arguments.user)
		session.add(user)
		color.print_status('the specified user was created')

	for case in utilities.switch(arguments.action):
		if case('remove'):
			user.otp_secret = None
			break
		if case('set'):
			if user.otp_secret:
				color.print_error("the specified user already has an otp secret set")
				return
			if arguments.otp_secret:
				new_otp = arguments.otp_secret
			else:
				new_otp = pyotp.random_base32()
			if len(new_otp) != 16:
				color.print_error("invalid otp secret length, must be 16")
				return
			user.otp_secret = new_otp
			break

	if user.otp_secret:
		color.print_status("user: {0} otp: {1}".format(user.name, user.otp_secret))
		totp = pyotp.TOTP(user.otp_secret)
		uri = totp.provisioning_uri(user.name + '@king-phisher') + '&issuer=King%20Phisher'
		color.print_status("provisioning uri: {0}".format(uri))
		if has_qrcode and arguments.qrcode_filename:
			img = qrcode.make(uri)
			img.save(arguments.qrcode_filename)
			color.print_status("wrote qrcode image to: " + arguments.qrcode_filename)
	else:
		color.print_status("user: {0} otp: N/A".format(user.id))
	session.commit()