Example #1
0
class wcagScan(QThread):
    signalConsole = pyqtSignal(str)
    scanSignal = pyqtSignal(str)
    signalFinished = pyqtSignal(bool)

    def __init__(self,
                 url: str,
                 filename: str,
                 driver: str,
                 headers: bool,
                 targetDevice: Union[str, None],
                 configuration: Optional[Dict] = None) -> None:

        super().__init__()
        self.targetDevice = targetDevice
        self.headers = headers
        self.url = url
        self.filename = filename
        self.configuration = configuration
        self.driver = driver
        self.subSystemDatabase = WACDatabase("sqlite/database.db")
        self.numxpath = 4
        print(self.targetDevice)

    def _setupScrap(self) -> bool:

        self.setupDriver()

        if not self.isDriverInitialized():
            print("driver not initialized!")
            return False

        return True

    def __getattribute__(self, name, *args, **kwargs):
        def make_interceptor(callble):
            def func(*args, **kwargs):
                logger.info(f"{name} {args} {kwargs}")
                return callble(*args, **kwargs)

            return func

        returned = object.__getattribute__(self, name)
        if inspect.isfunction(returned) or inspect.ismethod(returned):
            return make_interceptor(returned)
        return returned

    def checkTabbing(self):
        self.subsystem = Scrap(self.url, 0, self.driver, self.targetDevice,
                               self.configuration, False)
        return self.subsystem.checkTabbing()

    def run(self):
        self.signalConsole.emit(f"Starting scan of {self.url}")
        self.subSystem = Scrap(self.url, 0, self.driver, self.targetDevice,
                               self.configuration, False)

        paths = self.subSystem.loadXPaths(self.filename)

        if paths == False:
            self.signalConsole.emit(f"Unable to find path file.")
        else:
            scans = self.subSystemDatabase.getScanTable()

            id = 0
            if len(scans) >= 1:
                for x in scans:
                    #print(f"x: {x}")
                    if x[0] > id:
                        id = x[0]
            id += 1

            time = datetime.now()
            dt = time.strftime("%d/%m/%Y %H:%M")
            self.subSystemDatabase.addScan(id, ".com", "Chrome", dt)
            self.signalConsole.emit(f"New scanID created: {id}")

            self.subSystem.openSite(self.url)
            self.signalConsole.emit(f"Chrome driver started...")
            try:
                count = int(self.subSystemDatabase.getMaxElemID()[0][0]) + 1
            except:
                count = 0
            #print(f'count: {count}')
            total = len(paths)
            completed = 0
            #self.subSystemDatabase.conn.cursor.fast_executemany = True
            elements = []
            self.scanSignal.emit(str(id))
            for item in paths[1:]:
                #print(completed)
                if not ((('header' in item) or
                         ('svg' in item)) and self.headers):
                    #time.sleep(1)
                    #print('inside')
                    ats = self.subSystem.getAllAttributes(self.url, item)
                    #print('mid')
                    if ats['type'] != "":

                        #print(ats)

                        #self.subSystemDatabase.insertSiteTable(id, count, ats['type'], self.url, item, ats['alt'], ats['aria-current'], ats['aria-describedby'], ats['aria-hidden'],ats['aria-label'],ats['aria-required'],
                        #                                        ats['class'], ats['id'], ats['name'], ats['role'], ats['src'], ats['tabindex'], ats['target'],ats['title'], ats['href'], ats['text'], ats['type id'])

                        elements.append(
                            (id, count, ats['type'], self.url, item,
                             ats['alt'], ats['aria-current'],
                             ats['aria-describedby'], ats['aria-hidden'],
                             ats['aria-label'], ats['aria-required'],
                             ats['class'], ats['id'], ats['name'], ats['role'],
                             ats['src'], ats['tabindex'], ats['target'],
                             ats['title'], ats['href'], ats['text'],
                             ats['type id'], ats['scope'], ats['imgText'],
                             ats['imgTable'],
                             ats['imgIcon'], ats['srcset'], ats['lang'],
                             str('html'), ats['fontSize'], ats['data-src']))
                        count += 1
                    #print('next')
                    #print(elements)
                completed += 1
                if completed == 1:
                    self.signalConsole.emit(
                        f"First Element scanned of {total} elements.")
                if completed % (int(len(paths) / 20)) == 0:
                    perc = int((completed / len(paths)) * 100)
                    self.signalConsole.emit(
                        f'Completed scan of {completed}/{total} elements. {perc}%'
                    )
                    #print('before')
                    self.subSystemDatabase.insertLargeSiteTable(elements)
                    self.subSystemDatabase.conn.commit()
                    elements = []
                    #print('after')
                #print('done')

            ret1, ret2 = self.checkTabbing()
            print('got back')
            if len(ret1) > 0:
                err = "Tab progression respects a logical sequence. Error found in tab numbers: "
                for item in ret1:
                    err = err + f'{item},'
                self.subSystemDatabase.addNotesToSite("elements", "Rule 1",
                                                      '/html', err, id)
            if len(ret2) > 0:
                err = "Each tab should have h2 element even if blank. These did not "
                for item in ret2:
                    err = err + f'{item},'
                self.subSystemDatabase.addNotesToSite("elements", "Rule 2",
                                                      '/html', err, id)
            #self.subSystemDatabase.conn.cursor.fast_executemany = False
            self.signalConsole.emit(f"Scan Complete.")
            self.signalFinished.emit(True)

    def mapSite(self, filename):
        self.subSystem = Scrap(self.url, 0, self.driver, self.targetDevice,
                               self.configuration, False)
        self.subSystem.getXPaths(self.url, filename)

    def openElem(self, xPath):
        self.subsystem = Scrap(self.url, 0, self.driver, self.targetDevice,
                               self.configuration, False)
        self.signalConsole.emit("Opening Element")
        self.subsystem.openSite(self.url)
        self.subsystem.openWebElement(self.url, str(xPath))

    def output(self, scanID, filename):
        errors = []
        print(scanID)
        #self.subSystemDatabase2 = WACDatabase("sqlite/database.db")
        data = self.subSystemDatabase.getSiteErrors('elements', scanID)
        #print(data[0:200])
        for item in data:
            #print(item[self.numxpath])
            add = False
            ers = []

            ers.append(item[3])
            ers.append(item[4])
            ers.append(item[2])

            for i in range(60):
                #print(f'item: {item[i + 31]} i = {i}')
                if item[i + 30] != None:

                    if len(item[i + 30]) > 2:
                        ers.append(f"Rule {i}, {item[i + 30]}")
                        print(item[i + 30])
                        add = True
            if add:
                print(f"{item[0:4]} +    {ers}")
                errors.append(ers)

        print(f"errors: {errors[0:10]}")
        self.ws = Xlsx(filename + '_errors.xlsx', "Sheet1")
        for x in errors:
            self.ws.addRows(x)

        self.ws.set_col_widths_errors(100)
        self.ws.saveWorkbook()
Example #2
0
class wcag11(QThread):
    signalConsole = pyqtSignal(str)

    def __init__(self,
                 url: str,
                 driver: str,
                 targetDevice: Union[str, None],
                 configuration: Optional[Dict] = None) -> None:

        super().__init__()
        self.targetDevice = targetDevice
        self.url = url
        self.configuration = configuration
        self.driver = driver
        self.subSystemDatabase = WACDatabase("sqlite/database.db")

    def _setupScrap(self) -> bool:

        self.setupDriver()

        if not self.isDriverInitialized():
            print("driver not initialized!")
            return False

        return True

    #def run

    def __getattribute__(self, name, *args, **kwargs):
        def make_interceptor(callble):
            def func(*args, **kwargs):
                logger.info(f"{name} {args} {kwargs}")
                return callble(*args, **kwargs)

            return func

        returned = object.__getattribute__(self, name)
        if inspect.isfunction(returned) or inspect.ismethod(returned):
            return make_interceptor(returned)
        return returned

    def start(self):
        self.subSystemDatabase.createSiteTable("Test")

    def testing(self, siteID, url):
        #self.subsystem.driver.get("https://www.jackboxgames.com/party-pack-five/")
        self.subsystem = Scrap(self.url, 0, self.driver, self.targetDevice,
                               self.configuration, False)
        data = self.subSystemDatabase.getSiteData('elements', siteID)
        #print(data)
        #print(f"Data: {data}")
        back = self.subsystem.nonText(self.url, data)
        #print(f"Back: {back}")
        for item in back:
            #print(item["xPath"])
            self.subSystemDatabase.addNotesToSite('elements', "wcag11",
                                                  item["xPath"],
                                                  str(item["errors"]), siteID)

    def scan(self, filename):
        self.subSystem = Scrap(self.url, 0, self.driver, self.targetDevice,
                               self.configuration, False)
        paths = self.subSystem.loadXPaths(filename)
        #print(paths)
        scans = self.subSystemDatabase.getScanTable()
        #print(scans)
        id = 0
        if len(scans) >= 1:
            for x in scans:
                id += 1
        #table = "site_" + str(id)
        #print(table)
        time = datetime.now()
        dt = time.strftime("%d/%m/%Y %H:%M")
        self.subSystemDatabase.addScan(id, ".com", "Chrome", dt)
        #self.subSystemDatabase.createSiteTable(table)
        self.subSystem.openSite(self.url)
        try:
            count = int(self.subSystemDatabase.getMaxElemID()[0][0]) + 1
        except:
            count = 0
        #print(count)
        for item in paths:
            #print(item)
            ats = self.subSystem.getAllAttributes(self.url, item)
            if ats['type'] != "":
                self.subSystemDatabase.insertSiteTable(
                    id, count, ats['type'], self.url, item, ats['nonText'],
                    ats['decorative'], ats['class'], ats['name'], ats['id'],
                    ats['alt'], ats['aria-label'], ats['src'])
                self.subSystemDatabase.conn.commit()
                count += 1

    def nonText(self, url, data):
        altNum = 10
        nameNum = 8
        idNum = 9
        ariaNum = 11
        classNum = 7

        nonTextElems = ['img', 'button', 'input', 'video']

        elements = []
        #print(data)
        for item in data:

            #print(item)

            #if nonText
            if item[5] == "True":
                xPath = item[4]  #.replace('[1]', '')
                #elem = self.driver.find_element_by_xpath(xPath)
                #elements.append(self.driver.find_element_by_xpath(xPath))
                elements.append({
                    'type': item[2],
                    'attributes': item,
                    'element': None,
                    'errors': [],
                    'xPath': xPath
                })
                #print(elements)
            #except:
            #print(f'Failed Path: {item}')

        #print(elements)
        for item in elements:
            #print(item)

            # Get name and alt text
            try:
                alt = item['attributes'][altNum]
                #print(f"alt: {alt}")
            except:
                item['errors'].append(
                    "WCAG 1.1.1 - All non-text content should have an alt text."
                )
                alt = "Broke"
            #print(f"alt: {alt}")
            try:
                name = item['attributes'][nameNum]
                #print(f"name: {name}")
            except:
                item['errors'].append(
                    "Non-text content should have a name. Controls Must have a name."
                )
                name = ""
            #item['errors'].append(f"Id: {item['attributes'][idNum]}")
            try:
                if item['type'] == "input" or item['type'] == "button":
                    aria = item['attributes'][ariaNum]
                    if not aria == "":
                        alt = aria
                    else:
                        item['errors'].append(
                            "WCAG 1.1.1 - Control did not have an aria label to replace alt."
                        )
                elif "captcha" in item['attributes'][classNum]:
                    item['errors'].append(
                        "WCAG 1.1.1 - Exception: Captcha not tested for alt text."
                    )
            except:

                pass

            #Is displayed
            #Error not displayed - never displayed?

            #item['errors'].append(f"alt = {alt}")

            item['attributes'] = (f"Name: {name}   Alt: {alt}.  ")
            #print(item['attributes'])

            # Test for name and alt text
            if not len(str(alt)) >= 1:
                item['errors'].append(
                    "WCAG 1.1.1 - All non-text content should have an alt text."
                )

            if not len(str(name)) >= 1:
                item['errors'].append(
                    "Non-text content should have a name. Controls Must have a name."
                )

            # compare textdistance
            temp = textdistance.jaro_winkler(
                str(name).lower(),
                str(alt).lower())
            if temp <= .2:
                item['errors'].append(
                    f"WCAG 1.1.1 - Name of element should match alt text or aria-label."
                )

        #print(elements)
        return elements
        '''self.ws = Xlsx('WWC.xlsx', "Sheet1")
        for x in elems:
            self.ws.addRows([x['type'], x['attributes'], x['errors']])
    
        self.ws.set_col_widths(80)
        self.ws.saveWorkbook()
        self.driver.close()'''

    def mapSite(self, filename):
        self.subSystem = Scrap(self.url, 0, self.driver, self.targetDevice,
                               self.configuration, False)
        self.subSystem.getXPaths(self.url, filename)

    def openElem(self, xPath):
        self.subsystem = Scrap(self.url, 0, self.driver, self.targetDevice,
                               self.configuration, False)
        self.signalConsole.emit("Opening Element")
        self.subsystem.openWebElement(self.url, str(xPath))