class CampaignViewMessagesTab(CampaignViewGenericTableTab): """Display campaign information regarding sent messages.""" table_name = 'messages' label_text = 'Messages' node_query = """\ query getMessage($id: String!) { db { node: message(id: $id) { id targetEmail sent trained companyDepartment { name } opened openerIp openerUserAgent } } } """ table_query = """\ query getMessages($campaign: String!, $count: Int!, $cursor: String) { db { campaign(id: $campaign) { messages(first: $count, after: $cursor) { total edges { node { id targetEmail sent trained companyDepartment { name } opened openerIp openerUserAgent } } pageInfo { endCursor hasNextPage } } } } } """ view_columns = ('Email Address', 'Sent', 'Trained', 'Department', 'Opened', 'Opener IP Address', 'Opener User Agent') xlsx_worksheet_options = export.XLSXWorksheetOptions( column_widths=(30, 30, 30, 15, 20, 20, 25, 90), title=label_text) def format_node_data(self, node): department = node['companyDepartment'] if department: department = department['name'] row = (node['targetEmail'], node['sent'], ('Yes' if node['trained'] else ''), department, node['opened'], node['openerIp'], node['openerUserAgent']) return row
class CampaignViewCredentialsTab(CampaignViewGenericTableTab): """Display campaign information regarding submitted credentials.""" remote_table_name = 'credentials' label_text = 'Credentials' view_columns = ('Email Address', 'Username', 'Password', 'Submitted') xlsx_worksheet_options = export.XLSXWorksheetOptions(column_widths=(20, 30, 30, 30, 25), title=label_text) def __init__(self, *args, **kwargs): super(CampaignViewCredentialsTab, self).__init__(*args, **kwargs) treeview = self.gobjects['treeview_campaign'] pwd_column_id = self.view_columns.index('Password') treeview.get_column(pwd_column_id).set_property('visible', False) def format_row_data(self, credential): msg_details = self.rpc.remote_table_row('messages', credential.message_id, cache=True) if not msg_details: return None row = (msg_details.target_email, credential.username, credential.password, credential.submitted) return row def signal_button_toggled_show_passwords(self, button): treeview = self.gobjects['treeview_campaign'] pwd_column_id = self.view_columns.index('Password') treeview.get_column(pwd_column_id).set_property( 'visible', button.get_property('active'))
class CampaignViewVisitsTab(CampaignViewGenericTableTab): """Display campaign information regarding incoming visitors.""" remote_table_name = 'visits' label_text = 'Visits' view_columns = ('Email Address', 'IP Address', 'Visit Count', 'Visitor User Agent', 'Visitor Location', 'First Visit', 'Last Visit') xlsx_worksheet_options = export.XLSXWorksheetOptions( column_widths=(30, 30, 25, 15, 90, 30, 25, 25), title=label_text) def __init__(self, *args, **kwargs): super(CampaignViewVisitsTab, self).__init__(*args, **kwargs) self._ips_for_georesolution = {} def format_row_data(self, visit): msg_details = self.rpc.remote_table_row('messages', visit.message_id, cache=True) if not msg_details: return None visitor_ip = ipaddress.ip_address(visit.visitor_ip) geo_location = UNKNOWN_LOCATION_STRING if visitor_ip.is_loopback: geo_location = 'N/A (Loopback)' elif visitor_ip.is_private: geo_location = 'N/A (Private)' elif isinstance(visitor_ip, ipaddress.IPv6Address): geo_location = 'N/A (IPv6 Address)' else: if not visitor_ip in self._ips_for_georesolution: self._ips_for_georesolution[visitor_ip] = visit.first_visit elif self._ips_for_georesolution[visitor_ip] > visit.first_visit: self._ips_for_georesolution[visitor_ip] = visit.first_visit row = (msg_details.target_email, str(visitor_ip), visit.visit_count, visit.visitor_details, geo_location, visit.first_visit, visit.last_visit) return row def loader_thread_routine(self, store): self._ips_for_georesolution = {} super(CampaignViewVisitsTab, self).loader_thread_routine(store) ips_for_geores = [ ip for (ip, _) in sorted(self._ips_for_georesolution.items(), key=lambda x: x[1]) ] locations = {} for ip_addresses in iterutils.chunked(ips_for_geores, 50): locations.update(self.rpc.geoip_lookup_multi(ip_addresses)) for row in store: if row[2] in locations: row[5] = str(locations[row[2]])
class CampaignViewMessagesTab(CampaignViewGenericTableTab): """Display campaign information regarding sent messages.""" remote_table_name = 'messages' label_text = 'Messages' view_columns = ('Email Address', 'Sent', 'Trained', 'Department', 'Opened', 'Opener IP Address', 'Opener User Agent') xlsx_worksheet_options = export.XLSXWorksheetOptions( column_widths=(30, 30, 30, 15, 20, 20, 25, 90), title=label_text) def format_row_data(self, message): department = message.company_department if department: department = department.name row = (message.target_email, message.sent, ('Yes' if message.trained else ''), department, message.opened, message.opener_ip, message.opener_user_agent) return row
def export_table_to_xlsx_worksheet(self, worksheet, title_format): """ Export the data represented by the view to an XLSX worksheet. :param worksheet: The destination sheet for the store's data. :type worksheet: :py:class:`xlsxwriter.worksheet.Worksheet` :param title_format: The formatting to use for the title row. :type title_format: :py:class:`xlsxwriter.format.Format` """ if not self._export_lock(): return store = self._tv_model columns = dict(enumerate(('UID',) + self.view_column_titles)) xlsx_worksheet_options = export.XLSXWorksheetOptions( column_widths=(20,) + tuple(column.width for column in self.view_columns), title=self.label_text ) export.liststore_to_xlsx_worksheet(store, worksheet, columns, title_format, xlsx_options=xlsx_worksheet_options) self.loader_thread_lock.release()
class CampaignViewVisitsTab(CampaignViewGenericTableTab): """Display campaign information regarding incoming visitors.""" table_name = 'visits' label_text = 'Visits' node_query = """\ query getVisit($id: String!) { db { node: visit(id: $id) { id message { targetEmail } visitorIp visitCount visitorDetails visitorGeoloc { city } firstVisit lastVisit } } } """ table_query = """\ query getVisits($campaign: String!, $count: Int!, $cursor: String) { db { campaign(id: $campaign) { visits(first: $count, after: $cursor) { total edges { node { id message { targetEmail } visitorIp visitCount visitorDetails visitorGeoloc { city } firstVisit lastVisit } } pageInfo { endCursor hasNextPage } } } } } """ view_columns = ('Email Address', 'IP Address', 'Visit Count', 'Visitor User Agent', 'Visitor Location', 'First Visit', 'Last Visit') xlsx_worksheet_options = export.XLSXWorksheetOptions( column_widths=(30, 30, 25, 15, 90, 30, 25, 25), title=label_text) def format_node_data(self, node): geo_location = UNKNOWN_LOCATION_STRING visitor_ip = node['visitorIp'] if visitor_ip is None: visitor_ip = '' else: visitor_ip = ipaddress.ip_address(visitor_ip) if visitor_ip.is_loopback: geo_location = 'N/A (Loopback)' elif visitor_ip.is_private: geo_location = 'N/A (Private)' elif isinstance(visitor_ip, ipaddress.IPv6Address): geo_location = 'N/A (IPv6 Address)' elif node['visitorGeoloc']: geo_location = node['visitorGeoloc']['city'] row = (node['message']['targetEmail'], str(visitor_ip), node['visitCount'], node['visitorDetails'], geo_location, node['firstVisit'], node['lastVisit']) return row
class CampaignViewCredentialsTab(CampaignViewGenericTableTab): """Display campaign information regarding submitted credentials.""" table_name = 'credentials' label_text = 'Credentials' node_query = """\ query getCredential($id: String!) { db { node: credential(id: $id) { id message { targetEmail } username password submitted } } } """ table_query = """\ query getCredentials($campaign: String!, $count: Int!, $cursor: String) { db { campaign(id: $campaign) { credentials(first: $count, after: $cursor) { total edges { node { id message { targetEmail } username password submitted } } pageInfo { endCursor hasNextPage } } } } } """ view_columns = ('Email Address', 'Username', 'Password', 'Submitted') xlsx_worksheet_options = export.XLSXWorksheetOptions(column_widths=(20, 30, 30, 30, 25), title=label_text) def __init__(self, *args, **kwargs): super(CampaignViewCredentialsTab, self).__init__(*args, **kwargs) treeview = self.gobjects['treeview_campaign'] pwd_column_id = self.view_columns.index('Password') treeview.get_column(pwd_column_id).set_property('visible', False) def format_node_data(self, node): row = (node['message']['targetEmail'], node['username'], node['password'], node['submitted']) return row def signal_button_toggled_show_passwords(self, button): treeview = self.gobjects['treeview_campaign'] pwd_column_id = self.view_columns.index('Password') treeview.get_column(pwd_column_id).set_property( 'visible', button.get_property('active'))
class CampaignViewCredentialsTab(CampaignViewGenericTableTab): """Display campaign information regarding submitted credentials.""" table_name = 'credentials' label_text = 'Credentials' node_query = """\ query getCredential($id: String!) { db { node: credential(id: $id) { id submitted message { targetEmail } username password mfaToken regexValidated } } } """ table_query = """\ query getCredentials($campaign: String!, $count: Int!, $cursor: String) { db { campaign(id: $campaign) { credentials(first: $count, after: $cursor) { total edges { node { id message { targetEmail } submitted username password mfaToken regexValidated } } pageInfo { endCursor hasNextPage } } } } } """ secret_columns = ('Password', 'MFA Token') view_columns = ( 'Email Address', 'Submitted', 'Validation', 'Username', ) + secret_columns xlsx_worksheet_options = export.XLSXWorksheetOptions( column_widths=(20, 30, 25, 30, 30, 30, 20), title=label_text) def __init__(self, *args, **kwargs): super(CampaignViewCredentialsTab, self).__init__(*args, **kwargs) treeview = self.gobjects['treeview_campaign'] for column_name in self.secret_columns: treeview.get_column( self.view_columns.index(column_name)).set_property( 'visible', False) def format_node_data(self, node): regex_validated = '' if node['regexValidated'] is not None: regex_validated = 'Pass' if node['regexValidated'] else 'Fail' row = (node['message']['targetEmail'], node['submitted'], regex_validated, node['username'], node['password'], node['mfaToken']) return row def signal_button_toggled_show_secrets(self, button): treeview = self.gobjects['treeview_campaign'] visible = button.get_property('active') for column_name in self.secret_columns: treeview.get_column( self.view_columns.index(column_name)).set_property( 'visible', visible)