Example #1
0
    def __init__(self, parent=None, device_type='usb'):
        super().__init__(parent=parent)

        # dont show for local
        if device_type != 'usb':
            return

        self.parent = parent
        self.wait_for_devtype = device_type
        self.is_waiting = True
        self._adb = Adb()

        if not self._adb.min_required:
            raise Exception('Adb missing or no Device')

        self._git = Git()
        self.setAutoFillBackground(True)
        self.setStyleSheet(
            'background-color: crimson; color: white; font-weight: bold; margin: 0; padding: 10px;'
        )
        self.setup()
        self._timer = QTimer()
        self._timer.setInterval(500)
        self._timer.timeout.connect(self._on_timer)
        self._timer.start()
        self._timer_step = 0
        frida.get_device_manager().on('added', self._on_device)
        frida.get_device_manager().on('removed', self._on_device)
        self.devices_thread = DevicesUpdateThread(self)
        self.devices_thread.onAddDevice.connect(self.on_add_deviceitem)
        self.devices_thread.onDevicesUpdated.connect(self._on_devices_finished)
        self._update_thread = FridaUpdateThread(self)
        self._update_thread._adb = self._adb
        self._update_thread.onStatusUpdate.connect(self._update_statuslbl)
        self._update_thread.onFinished.connect(self._frida_updated)
        self._update_thread.onError.connect(self._on_download_error)
        self.updated_frida_version = ''
        self.updated_frida_assets_url = {}
        self._device_id = None
        self._devices = []
        remote_frida = self._git.get_frida_version()
        if remote_frida is None:
            self.updated_frida_version = ''
            self.updated_frida_assets_url.clear()
        else:
            remote_frida = remote_frida[0]
            self.updated_frida_version = remote_frida['tag_name']
            for asset in remote_frida['assets']:
                if 'android-' not in asset:
                    continue

                try:
                    name = asset['name']
                    tag_start = name.index('android-')
                    if name.index('server') >= 0:
                        tag = name[tag_start + 8:-3]
                        self.updated_frida_assets_url[tag] = asset[
                            'browser_download_url']
                except ValueError:
                    pass
Example #2
0
    def __init__(self, app_window):
        super(ScriptsDialog, self).__init__(app_window)

        self.script = None
        self._app_window = app_window
        self._script_manager = ScriptsManager()
        self._git = Git()

        self.setMinimumWidth(800)

        box = QVBoxLayout()
        self.table = ScriptsTable(self)
        self.table.onScriptSelected.connect(self._item_selected)
        self.table.setMinimumWidth(800)

        # create a centered dot icon
        _section_width = self.table.header().sectionSize(3)
        self._new_pixmap = QPixmap(max(_section_width, 40), 20)
        self._new_pixmap.fill(Qt.transparent)
        painter = QPainter(self._new_pixmap)
        rect = QRect((_section_width * 0.5) - 5, 0, 20, 20)
        painter.setBrush(QColor('#666'))
        painter.setPen(QColor('#666'))
        painter.drawEllipse(rect)
        self._dot_icon = QIcon(self._new_pixmap)

        box.addWidget(self.table)
        lbl = QLabel('OS Support - A: Android I: IOS W: Windows')
        box.addWidget(lbl)
        self.setLayout(box)
        self._init_list()
Example #3
0
class ScriptsManager(QObject):
    """ ScriptManager

        signals:
            scriptsUpdated()
    """

    scriptsUpdated = pyqtSignal(name='scriptsUpdated')

    def __init__(self):
        super(ScriptsManager, self).__init__()
        self._git = Git()
        self.scripts = {}

        self.update_scripts()

    def update_scripts(self):
        scripts = self._git.get_dwarf_scripts()

        if scripts is None:
            return

        scripts = scripts.replace(' ', '').replace('\t', '').split('\n')
        submodule_path = '[submodule"'
        url_path = 'url='
        module_name = ''

        for line in scripts:
            if line.startswith(submodule_path):
                module_name = line.replace(submodule_path, "")
                module_name = module_name[:-2]
            elif line.startswith(url_path):
                url = line.replace(url_path, "")
                if url.endswith('.git'):
                    url = url[:-4]
                url = url.replace('https://github.com',
                                  'https://raw.githubusercontent.com')

                info_url = url + '/master/dwarf.json'
                script_url = url + '/master/script.js'
                info = self._git.get_script_info(info_url)
                if info is None:
                    continue
                self.scripts[module_name] = {
                    'info': info,
                    'script': script_url
                }

        self.scriptsUpdated.emit()

    def get_script(self, script_name):
        return self.scripts[script_name]

    def get_scripts(self):
        return self.scripts
Example #4
0
    def run(self):
        self.on_status_text.emit('fetching commit list...')

        try:
            utils.do_shell_command('git --version')
        except IOError as io_error:
            if io_error.errno == 2:
                # git command not available
                self.on_status_text.emit(
                    'error: git not available on your system')
                return
        _git = Git()
        data = _git.get_dwarf_commits()
        if data is None:
            self.on_status_text.emit('Failed to fetch commit list. Try later.')
            return

        # TODO: check for dev/release version and updated version
        most_recent_remote_commit = ''
        most_recent_local_commit = utils.do_shell_command(
            'git log -1 master --pretty=format:%H')
        most_recent_date = ''
        for commit in data:
            if most_recent_remote_commit == '':
                most_recent_remote_commit = commit['sha']
                if most_recent_remote_commit != most_recent_local_commit:
                    self.on_update_available.emit()

            commit = commit['commit']
            date = commit['committer']['date'].split('T')
            if most_recent_date != date[0]:
                if most_recent_date != '':
                    self.on_add_commit.emit('', True)
                self.on_add_commit.emit(date[0], True)
                most_recent_date = date[0]

            s = ('{0} - {1} ({2})'.format(date[1][:-1], commit['message'],
                                          commit['author']['name']))
            self.on_add_commit.emit(s, False)

        if most_recent_remote_commit != most_recent_local_commit:
            self.on_finished.emit(
                'There is an newer Version available... You can use the UpdateButton in Menu'
            )
        else:
            # keep: it clears status text
            self.on_finished.emit('')
Example #5
0
class DeviceBar(QWidget):
    """ DeviceBar

        Signals:
            onDeviceUpdated()
            onDeviceSelected(str) # str = id
            onDeviceChanged(str) # str = id

    """

    onDeviceUpdated = pyqtSignal(str, name="onDeviceUpdated")
    onDeviceSelected = pyqtSignal(str, name="onDeviceSelected")
    onDeviceChanged = pyqtSignal(str, name="onDeviceChanged")

    def __init__(self, parent=None, device_type='usb'):
        super().__init__(parent=parent)

        # dont show for local
        if device_type != 'usb':
            return

        self.parent = parent
        self.wait_for_devtype = device_type
        self.is_waiting = True
        self._adb = Adb()

        if not self._adb.min_required:
            raise Exception('Adb missing or no Device')

        self._git = Git()
        self.setAutoFillBackground(True)
        self.setStyleSheet(
            'background-color: crimson; color: white; font-weight: bold; margin: 0; padding: 10px;'
        )
        self.setup()
        self._timer = QTimer()
        self._timer.setInterval(500)
        self._timer.timeout.connect(self._on_timer)
        self._timer.start()
        self._timer_step = 0
        frida.get_device_manager().on('added', self._on_device)
        frida.get_device_manager().on('removed', self._on_device)
        self.devices_thread = DevicesUpdateThread(self)
        self.devices_thread.onAddDevice.connect(self.on_add_deviceitem)
        self.devices_thread.onDevicesUpdated.connect(self._on_devices_finished)
        self._update_thread = FridaUpdateThread(self)
        self._update_thread._adb = self._adb
        self._update_thread.onStatusUpdate.connect(self._update_statuslbl)
        self._update_thread.onFinished.connect(self._frida_updated)
        self._update_thread.onError.connect(self._on_download_error)
        self.updated_frida_version = ''
        self.updated_frida_assets_url = {}
        self._device_id = None
        self._devices = []
        remote_frida = self._git.get_frida_version()
        if remote_frida is None:
            self.updated_frida_version = ''
            self.updated_frida_assets_url.clear()
        else:
            remote_frida = remote_frida[0]
            self.updated_frida_version = remote_frida['tag_name']
            for asset in remote_frida['assets']:
                if 'name' not in asset:
                    continue
                if 'android-' not in asset['name']:
                    continue

                try:
                    name = asset['name']
                    tag_start = name.index('android-')
                    if name.index('server') >= 0:
                        tag = name[tag_start + 8:-3]
                        self.updated_frida_assets_url[tag] = asset[
                            'browser_download_url']
                except ValueError:
                    pass

    def setup(self):
        """ Setup ui
        """
        h_box = QHBoxLayout()
        h_box.setContentsMargins(0, 0, 0, 0)
        self.update_label = QLabel('Waiting for Device')
        self.update_label.setFixedWidth(self.parent.width())
        self.update_label.setOpenExternalLinks(True)
        self.update_label.setTextFormat(Qt.RichText)
        self.update_label.setFixedHeight(35)
        self.update_label.setTextInteractionFlags(Qt.TextBrowserInteraction)
        self._install_btn = QPushButton('Install Frida', self.update_label)
        self._install_btn.setStyleSheet('padding: 0; border-color: white;')
        self._install_btn.setGeometry(self.update_label.width() - 110, 5, 100,
                                      25)
        self._install_btn.clicked.connect(self._on_install_btn)
        self._install_btn.setVisible(False)
        self._start_btn = QPushButton('Start Frida', self.update_label)
        self._start_btn.setStyleSheet('padding: 0; border-color: white;')
        self._start_btn.setGeometry(self.update_label.width() - 110, 5, 100,
                                    25)
        self._start_btn.clicked.connect(self._on_start_btn)
        self._start_btn.setVisible(False)
        self._update_btn = QPushButton('Update Frida', self.update_label)
        self._update_btn.setStyleSheet('padding: 0; border-color: white;')
        self._update_btn.setGeometry(self.update_label.width() - 110, 5, 100,
                                     25)
        self._update_btn.clicked.connect(self._on_install_btn)
        self._update_btn.setVisible(False)
        self._restart_btn = QPushButton('Restart Frida', self.update_label)
        self._restart_btn.setStyleSheet('padding: 0; border-color: white;')
        self._restart_btn.setGeometry(self.update_label.width() - 110, 5, 100,
                                      25)
        self._restart_btn.clicked.connect(self._on_restart_btn)
        self._restart_btn.setVisible(False)
        self._devices_combobox = QComboBox(self.update_label)
        self._devices_combobox.setStyleSheet(
            'padding: 2px 5px; border-color: white;')
        self._devices_combobox.setGeometry(self.update_label.width() - 320, 5,
                                           200, 25)
        self._devices_combobox.currentIndexChanged.connect(
            self._on_device_changed)
        self._devices_combobox.setVisible(False)
        h_box.addWidget(self.update_label)
        self.setLayout(h_box)

    def on_add_deviceitem(self, device_ident):
        """ Adds an Item to the DeviceComboBox
        """
        if device_ident['type'] == self.wait_for_devtype:
            if device_ident['name'] not in self._devices:
                self._devices.append(device_ident)
            self._timer_step = -1
            self.is_waiting = False

    def _on_device_changed(self, index):
        device = None
        device_id = self._devices_combobox.itemData(index)
        if device_id:
            try:
                device = frida.get_device(device_id)
            except:
                return

            if device:
                self._device_id = device.id
                self._check_device(device)
                self.onDeviceChanged.emit(self._device_id)

    def _check_device(self, frida_device):
        self.update_label.setStyleSheet('background-color: crimson;')
        self._install_btn.setVisible(False)
        self._update_btn.setVisible(False)
        self._start_btn.setVisible(False)
        self._restart_btn.setVisible(False)
        self._adb.device = frida_device.id
        self._device_id = frida_device.id
        if self._adb.available():
            self.update_label.setText('Device: ' + frida_device.name)
            # try getting frida version
            device_frida = self._adb.get_frida_version()
            # frida not found show install button
            if device_frida is None:
                self._install_btn.setVisible(True)
            else:
                # frida is old show update button
                if self.updated_frida_version != device_frida:
                    self._start_btn.setVisible(True)
                    self._update_btn.setVisible(False)
                    # old frida is running allow use of this version
                    if self._adb.is_frida_running():
                        self._start_btn.setVisible(False)
                        if self.updated_frida_assets_url:
                            self._update_btn.setVisible(True)
                        self.update_label.setStyleSheet(
                            'background-color: yellowgreen;')
                        self.onDeviceUpdated.emit(frida_device.id)
                # frida not running show start button
                elif device_frida and not self._adb.is_frida_running():
                    self._start_btn.setVisible(True)
                # frida is running with last version show restart button
                elif device_frida and self._adb.is_frida_running():
                    self.update_label.setStyleSheet(
                        'background-color: yellowgreen;')
                    self._restart_btn.setVisible(True)
                    self.onDeviceUpdated.emit(frida_device.id)

        elif self._adb.non_root_available():
            self.update_label.setText('Device: ' + frida_device.name +
                                      ' (NOROOT!)')
            self.onDeviceUpdated.emit(frida_device.id)

    def _on_devices_finished(self):
        if self._devices:
            if len(self._devices) > 1:
                self._devices_combobox.clear()
                self._devices_combobox.setVisible(True)
                self.update_label.setText('Please select the Device: ')
                for device in self._devices:
                    self._devices_combobox.addItem(device['name'],
                                                   device['id'])
            else:
                self._devices_combobox.setVisible(False)
                try:
                    device = frida.get_device(self._devices[0]['id'])
                    self._check_device(device)
                except:
                    pass

    def _on_timer(self):
        if self._timer_step == -1:
            self._timer.stop()
            return

        if self._timer_step == 0:
            self.update_label.setText(self.update_label.text() + ' .')
            self._timer_step = 1
        elif self._timer_step == 1:
            self.update_label.setText(self.update_label.text() + '.')
            self._timer_step = 2
        elif self._timer_step == 2:
            self.update_label.setText(self.update_label.text() + '.')
            self._timer_step = 3
        else:
            self.update_label.setText(
                self.update_label.text()[:-self._timer_step])
            self._timer_step = 0
            if self.is_waiting and self.devices_thread is not None:
                if not self.devices_thread.isRunning():
                    self.devices_thread.start()

    def _on_download_error(self, text):
        self._timer_step = -1
        self.update_label.setStyleSheet('background-color: crimson;')
        self.update_label.setText(text)
        self._install_btn.setVisible(True)
        self._update_btn.setVisible(False)

    def _on_device(self):
        self.update_label.setText('Waiting for Device ...')
        self._timer_step = 3
        self.is_waiting = True
        self._on_timer()

    def _on_install_btn(self):
        # urls are empty
        if not self.updated_frida_assets_url:
            return

        arch = self._adb.get_device_arch()
        request_url = ''

        if arch is not None and len(arch) > 1:
            arch = arch.join(arch.split())

            if arch == 'arm64' or arch == 'arm64-v8a':
                request_url = self.updated_frida_assets_url['arm64']
            elif arch == 'armeabi-v7a':
                request_url = self.updated_frida_assets_url['arm']
            else:
                if arch in self.updated_frida_assets_url:
                    request_url = self.updated_frida_assets_url[arch]

            try:
                if self._adb.available() and request_url.index(
                        'https://') == 0:
                    self._install_btn.setVisible(False)
                    self._update_btn.setVisible(False)
                    qApp.processEvents()
                    if self._update_thread is not None:
                        if not self._update_thread.isRunning():
                            self._update_thread.frida_update_url = request_url
                            self._update_thread.adb = self._adb
                            self._update_thread.start()

            except ValueError:
                # something wrong in .git_cache folder
                print("request_url not set")

    def _update_statuslbl(self, text):
        self._timer.stop()
        self._timer_step = 0
        self._timer.start()
        self.update_label.setText(text)

    def _frida_updated(self):
        # self._timer_step = 3
        # self.is_waiting = True
        self._on_devices_finished()

    def _on_start_btn(self):
        if self._adb.available():
            self._start_btn.setVisible(False)
            qApp.processEvents()
            if self._adb.start_frida():
                # self.onDeviceUpdated.emit(self._device_id)
                self._on_devices_finished()
            else:
                self._start_btn.setVisible(True)

    def _on_restart_btn(self):
        if self._adb.available():
            self._restart_btn.setVisible(False)
            qApp.processEvents()
            if self._adb.start_frida(restart=True):
                self._restart_btn.setVisible(True)
                # self.onDeviceUpdated.emit(self._device_id)
                self._on_devices_finished()
Example #6
0
class ScriptsDialog(QDialog):
    """ Scripts
    """
    def __init__(self, app_window):
        super(ScriptsDialog, self).__init__(app_window)

        self.script = None
        self._app_window = app_window
        self._script_manager = ScriptsManager()
        self._git = Git()

        self.setMinimumWidth(800)

        box = QVBoxLayout()
        self.table = ScriptsTable(self)
        self.table.onScriptSelected.connect(self._item_selected)
        self.table.setMinimumWidth(800)

        # create a centered dot icon
        _section_width = self.table.header().sectionSize(3)
        self._new_pixmap = QPixmap(max(_section_width, 40), 20)
        self._new_pixmap.fill(Qt.transparent)
        painter = QPainter(self._new_pixmap)
        rect = QRect((_section_width * 0.5) - 5, 0, 20, 20)
        painter.setBrush(QColor('#666'))
        painter.setPen(QColor('#666'))
        painter.drawEllipse(rect)
        self._dot_icon = QIcon(self._new_pixmap)

        box.addWidget(self.table)
        lbl = QLabel('OS Support - A: Android I: IOS W: Windows')
        box.addWidget(lbl)
        self.setLayout(box)
        self._init_list()

    def _init_list(self):
        for script_name in sorted(self._script_manager.get_scripts().keys()):
            script = self._script_manager.get_script(script_name)
            info = script['info']

            if 'dwarf' in info:
                continue

            _name = QStandardItem()
            _name.setText(script_name)
            _name.setToolTip(info['name'])

            _author = QStandardItem()
            if 'author' in info:
                _author.setTextAlignment(Qt.AlignCenter)
                _author.setText(info['author'])

            _android = QStandardItem()
            if 'android' in info:
                _android.setIcon(self._dot_icon)

            _ios = QStandardItem()
            if 'ios' in info:
                _ios.setIcon(self._dot_icon)

            _windows = QStandardItem()
            if 'windows' in info:
                _windows.setIcon(self._dot_icon)

            _desc = QStandardItem()
            if 'description' in info:
                _desc.setText(info['description'])

            self.table.add_item(
                [_name, _author, _android, _ios, _windows, _desc])

    def _item_selected(self, script_name):
        script_url = self._script_manager.get_script(script_name)['script']
        script = self._git.get_script(script_url)
        self.script = script
        self.accept()

    @staticmethod
    def pick(app):
        """ helper
        """
        dialog = ScriptsDialog(app)
        result = dialog.exec_()
        return result == QDialog.Accepted, dialog.script
Example #7
0
def run_dwarf():
    """ fire it up
    """
    os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
    # os.environ["QT_SCALE_FACTOR"] = "1"
    # os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "0"
    # os.environ["QT_SCREEN_SCALE_FACTORS"] = "1"

    from dwarf_debugger.lib import utils
    from dwarf_debugger.lib.git import Git
    from dwarf_debugger.lib.prefs import Prefs
    from dwarf_debugger.ui.app import AppWindow

    from PyQt5.QtCore import Qt
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QApplication

    import dwarf_debugger.resources  # pylint: disable=unused-import

    QApplication.setDesktopSettingsAware(True)
    QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
    QApplication.setLayoutDirection(Qt.LeftToRight)

    QApplication.setOrganizationName("https://github.com/iGio90/Dwarf")
    QApplication.setApplicationName("Dwarf")
    QApplication.setApplicationDisplayName('Dwarf')

    qapp = QApplication([])

    # set icon
    _icon = None
    if os.name == "nt":
        if os.path.exists(utils.resource_path('assets/dwarf.ico')):
            _icon = QIcon(utils.resource_path('assets/dwarf.ico'))
        else:
            _icon = QIcon(':/assets/dwarf.ico')
    else:
        if os.path.exists(utils.resource_path('assets/dwarf.png')):
            _icon = QIcon(utils.resource_path('assets/dwarf.png'))
        else:
            _icon = QIcon(':/assets/dwarf.png')

    if _icon:
        qapp.setWindowIcon(_icon)

    _prefs = Prefs()
    local_update_disabled = _prefs.get('disable_local_frida_update', False)

    args = process_args()
    """
    did_first_run = _prefs.get('did_first_run', False)
    if False:
        from dwarf_debugger.ui.dialogs.dialog_setup import SetupDialog
        # did_first_run:
        _prefs.put('did_first_run', True)
        SetupDialog.showDialog(_prefs)
    """

    if not local_update_disabled:
        _git = Git()
        import frida
        remote_frida = _git.get_frida_version()
        local_frida = frida.__version__

        if remote_frida and local_frida != remote_frida['tag_name']:
            print('Updating local frida version to ' +
                  remote_frida['tag_name'])
            try:
                res = utils.do_shell_command(
                    'pip3 install frida --upgrade --user')
                if 'Successfully installed frida-' + remote_frida[
                        'tag_name'] in res:
                    _on_restart()
                elif 'Requirement already up-to-date' in res:
                    if os.path.exists('.git_cache'):
                        shutil.rmtree('.git_cache', ignore_errors=True)
                else:
                    print('failed to update local frida')
                    print(res)
            except Exception as e:  # pylint: disable=broad-except, invalid-name
                print('failed to update local frida')
                print(str(e))

    if os.name == 'nt':
        # windows stuff
        import ctypes
        try:
            if os.path.exists(utils.resource_path('assets/dwarf.ico')):
                # write ini to show folder with dwarficon
                folder_stuff = "[.ShellClassInfo]\n"
                folder_stuff += "IconResource=dwarf\\assets\\dwarf.ico,0\n"
                folder_stuff += "[ViewState]\n"
                folder_stuff += "Mode=\n"
                folder_stuff += "Vid=\n"
                folder_stuff += "FolderType=Generic\n"
                try:
                    ini_path = os.path.dirname(
                        os.path.abspath(__file__)
                    ) + os.sep + os.pardir + os.sep + 'desktop.ini'
                    with open(ini_path, 'w') as ini:
                        ini.writelines(folder_stuff)

                    # set fileattributes to hidden + systemfile
                    ctypes.windll.kernel32.SetFileAttributesW(
                        ini_path, 0x02 | 0x04 | ~0x20
                    )  # FILE_ATTRIBUTE_HIDDEN = 0x02 | FILE_ATTRIBUTE_SYSTEM = 0x04
                except PermissionError:
                    # its hidden+system already
                    pass

            # fix for showing dwarf icon in windows taskbar instead of pythonicon
            _appid = u'iGio90.dwarf.debugger'
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
                _appid)

            ctypes.windll.user32.SetProcessDPIAware()

        except Exception:  # pylint: disable=broad-except
            pass

    try:
        # parse target as pid
        args.pid = int(args.any)
    except ValueError:
        args.pid = 0

    # default to local if not specified
    if args.target is None:
        args.target = 'local'

    app_window = AppWindow(args)
    if _icon:
        app_window.setWindowIcon(_icon)

    app_window.onRestart.connect(_on_restart)

    try:
        sys.exit(qapp.exec_())
    except SystemExit as sys_err:
        if sys_err.code == 0:
            # thanks for using dwarf
            print('Thank\'s for using Dwarf\nHave a nice day...')
        else:
            # something was wrong
            print('sysexit with: %d' % sys_err.code)
Example #8
0
    def __init__(self):
        super(ScriptsManager, self).__init__()
        self._git = Git()
        self.scripts = {}

        self.update_scripts()
Example #9
0
class ScriptsManager(QObject):
    """ ScriptManager

        signals:
            scriptsUpdated()
    """

    scriptsUpdated = pyqtSignal(name='scriptsUpdated')

    def __init__(self):
        super(ScriptsManager, self).__init__()
        self._git = Git()
        self.scripts = {}

        self.update_scripts()

    def _check_version(self, required_dwarf):
        from dwarf_debugger.version import DWARF_VERSION
        required_dwarf = required_dwarf.split('.')
        dwarf_version = DWARF_VERSION.split('.')
        print(required_dwarf)
        if int(dwarf_version[0]) < int(required_dwarf[0]):
            return False
        elif (int(dwarf_version[0]) <= int(required_dwarf[0])) and (int(
                dwarf_version[1]) < int(required_dwarf[1])):
            return False
        elif (int(dwarf_version[1]) <= int(required_dwarf[1])) and (int(
                dwarf_version[2]) < int(required_dwarf[2])):
            return False

        return True

    def update_scripts(self):
        scripts = self._git.get_dwarf_scripts()

        if scripts is None:
            return

        scripts = scripts.replace(' ', '').replace('\t', '').split('\n')
        submodule_path = '[submodule"'
        url_path = 'url='
        module_name = ''

        for line in scripts:
            if line.startswith(submodule_path):
                module_name = line.replace(submodule_path, "")
                module_name = module_name[:-2]
            elif line.startswith(url_path):
                url = line.replace(url_path, "")
                if url.endswith('.git'):
                    url = url[:-4]
                url = url.replace('https://github.com',
                                  'https://raw.githubusercontent.com')

                info_url = url + '/master/dwarf.json'
                script_url = url + '/master/script.js'
                info = self._git.get_script_info(info_url)
                if info is None:
                    continue
                if 'dwarf' in info:
                    if not self._check_version(info['dwarf']):
                        continue
                self.scripts[module_name] = {
                    'info': info,
                    'script': script_url
                }

        self.scriptsUpdated.emit()

    def get_script(self, script_name):
        return self.scripts[script_name]

    def get_scripts(self):
        return self.scripts