def test_generate_report(self): num_clickables = { 'unexamined': 5, 'true': 10, 'false': 30 } form1 = FormField('form1') form1.add_input(InputField('username', '//*[@id="username"]', 'castman')) form1.add_input(InputField('password', '', 'p@ssw0rd')) form_list = [{ 'state': 1, 'form': form1, 'execution_seq': [Clickable('exe1', '//html/body/button[1]'), Clickable('exe2', '//html/body/button[1]')], 'clickable': [Clickable('btn1', '//html/body/button[1]'), Clickable('btn2', '//html/body/button[1]')] }] inv_violation = [{ 'state': 2, 'name': '{"name": "file-not-found"}', 'sequence': [Clickable('inv-btn1', '//html/body/button[1]'), Clickable('inv-btn2', '//html/body/button[1]')] }] Visualizer.generate_report( 'web', 'trace/example-app-4-webide', 'automata.json', 3, num_clickables, form_list, inv_violation, 9.987 )
def setUp(self): dom1 = ''' <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body>dom1</body> </html> ''' state = State(dom1) self.automata = Automata() self.automata.add_state(state) self.assertEqual(len(self.automata.get_states()), 1) self.assertEqual(self.automata.get_initial_state().get_id(), self.automata.get_current_state().get_id()) self.assertEqual(self.automata.get_current_state().get_id(), '0') # test adding and removing inputs and forms form1 = FormField('form1') form1.add_input(InputField('username', '//*[@id="username"]', 'castman')) form1.add_input(InputField('password', '', 'p@ssw0rd')) form1.add_input(InputField('password', '', 'p@ssw0rd')) self.assertEqual(len(form1.get_inputs()), 2) form1.remove_input(InputField('username', '//*[@id="username"]', 'castman')) self.assertEqual(len(form1.get_inputs()), 1) form2 = FormField('', '//*[@id="lst-ib"]') clickable = Clickable('', '//*[@id="btn1"]') clickable.add_form(form1) clickable.add_form(FormField('form1')) clickable.add_form(form2) self.assertEqual(len(clickable.get_forms()), 2) clickable.remove_form(FormField('', '//*[@id="lst-ib"]')) self.assertEqual(len(clickable.get_forms()), 1) # add the clickable into state 0 self.automata.get_current_state().add_clickable(clickable)
def get_inputs(cls, dom): soup = BeautifulSoup(dom, 'html5lib') soup = cls.soup_visible(soup) inputs_list = [] for input_type in cls._input_types: inputs = soup.find_all('input', attrs={'type': input_type}) for my_input in inputs: input_id = cls.make_id(my_input.get('id')) input_name = my_input.get('name') if my_input.has_attr( 'name') else input_id inputs_list.append( InputField(input_id, input_name, cls._get_xpath(my_input), input_type)) return inputs_list
def __init__(self, fname=None, load_dom=False): self._states = [] self._edges = [] self._initial_state = None self._current_state = None if fname: assert os.path.isfile(fname) and os.path.exists(fname) t_start = time.time() with open(fname) as f: data = json.load(f) for state in data['state']: if load_dom: with open( os.path.join( os.path.dirname(os.path.realpath(fname)), state['dom_path']), 'r') as df: s = State(df.read()) else: s = State(state['id']) s.set_id(state['id']) for form in state['form']: f = FormField(form['id'], form['xpath']) for the_input in form['input']: f.add_input( InputField(the_input['id'], the_input['xpath'], the_input['type'], the_input['value'])) s.add_form(f) for clickable in state['clickable']: c = Clickable(clickable['id'], clickable['xpath'], clickable['tag']) for form in clickable['form']: f = s.get_form_by_id(form['id']) assert f c.add_form(f) s.add_clickable(c) self.add_state(s) for edge in data['edge']: from_state = self.get_state_by_id(edge['from']) to_state = self.get_state_by_id(edge['to']) clickable = from_state.get_clickable_by_id( edge['clickable']) assert from_state and to_state and clickable self.add_edge(from_state, to_state, clickable) logger.info('automata loaded. loading time: %f sec', time.time() - t_start)
def build_trace(self, data): try: edges = [] for edge in data['edges']: state_from = edge['from'] state_to = edge['to'] c = edge['clickable'] clickable = Clickable(c['id'], c['name'], c['xpath'], c['tag']) inputs = [] for i in edge['inputs']: inputs.append( InputField(i['id'], i['name'], i['xpath'], i['type'], i['value'])) selects = [] for s in edge['selects']: selects.append( SelectField(s['id'], s['name'], s['xpath'], s['value'], s['selected'])) checkboxes = [] for c_field in edge['checkboxes']: c_list = [] for c in c_field['checkbox_list']: c_list.append( Checkbox(c['id'], c['name'], c['xpath'], c['value'])) checkboxes.append( CheckboxField(c_list, c_field['checkbox_name'], c_field['checkbox_selected_list'])) radios = [] for r_field in edge['radios']: r_list = [] for r in r_field['radio_list']: r_list.append( Radio(r['id'], r['name'], r['xpath'], r['value'])) radios.append( RadioField(r_list, r_field['radio_name'], r_field['radio_selected'])) iframe_list = edge['iframe_list'] edges.append( Edge(state_from, state_to, clickable, inputs, selects, checkboxes, radios, iframe_list)) return edges except Exception as e: logging.error('can not build trace: %s', str(e))
def get_clickables(cls, dom, prev_dom=None): # only return newly discovered clickables and forms, i.e. clickables not in prev_clickables prev_clickables = [] prev_forms = [] if prev_dom: prev_soup = BeautifulSoup(prev_dom, 'html.parser') for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): prev_clickables += prev_soup.find_all( tag.get_name(), attrs={attr: value}) else: prev_clickables += prev_soup.find_all(tag.get_name()) prev_forms = prev_soup.find_all('form') soup = BeautifulSoup(dom, 'html.parser') forms = soup.find_all('form') clickables = [] # clickables with forms and inputs attached for form in forms: if form in prev_forms: continue form_id = form.get('id') if not form_id: form_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 f = FormField(form_id, cls._get_xpath(form)) for input_type in cls.input_types: inputs = form.find_all('input', attrs={'type': input_type}) for my_input in inputs: data_set = InlineDataBank.get_data(input_type) if data_set: value = random.choice(list(data_set)) else: value = ''.join( random.choice(string.lowercase) for i in xrange(8)) input_id = my_input.get('id') if not input_id: input_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 f.add_input( InputField(input_id, cls._get_xpath(my_input), input_type, value)) for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): candidate_clickables = form.find_all( tag.get_name(), attrs={attr: value}) else: candidate_clickables = form.find_all(tag.get_name()) for candidate_clickable in candidate_clickables: if candidate_clickable in prev_clickables: continue clickable_id = candidate_clickable.get('id') if not clickable_id: clickable_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 c = Clickable(clickable_id, cls._get_xpath(candidate_clickable), tag.get_name()) c.add_form(f) clickables.append(c) # other clickables for tag in cls._clickable_tags: if tag.get_attr(): for attr, value in tag.get_attr().items(): candidate_clickables = soup.find_all(tag.get_name(), attrs={attr: value}) else: candidate_clickables = soup.find_all(tag.get_name()) for candidate_clickable in candidate_clickables: #print candidate_clickable if candidate_clickable in prev_clickables: continue if not cls._is_duplicate(clickables, candidate_clickable): clickable_id = candidate_clickable.get('id') if not clickable_id: clickable_id = cls.serial_prefix + str(cls._serial_num) cls._serial_num += 1 clickables.append( Clickable(clickable_id, cls._get_xpath(candidate_clickable), tag.get_name())) return clickables