Example #1
0
class CollectorApplication(QtGui.QApplication):
    """The GUI Application for Collector"""

    translators = {}
    current = None
    collector = None

    def __init__(self, argv, hidden=False):
        super(CollectorApplication, self).__init__(argv)

        # Create and display the splash screen
        if not hidden:
            self.splash = SplashScreen()
            self.splash.show()
        self.processEvents()
        self.view = None
        self.uri = None
        self.home = None
        if argv is not None:
            self.parse_args(argv)
        # Launch collector
        self.collector = Collector(self.home)

        self.load_translations(":/lang")

        # Create the main window
        # FIXME: Some view variables are language dependent,
        # is needed to import them after load the language settings
        from mainwindow import MainWindow

        self.main = MainWindow()
        self.main.views = CollectorApplication.get_views(self.main)
        self.main.display_view('dashboard')

        if not hidden:
            # Show main window
            self.main.show()
            # Hide splash
            self.splash.finish(self.main)

        # Bring window to front if development
        if 'COLLECTION_PATH' in os.environ:
            self.main.raise_()

        if self.view is not None:
            self.main.display_view(self.view)
        elif self.uri is not None:
            self.main.collector_uri_call(self.uri)

    def parse_args(self, argv):
        """Parse argv, the input arguments"""
        if '--view' in argv:
            self.view = argv[argv.index('--view') + 1]
        elif '--uri' in argv:
            self.uri = argv[argv.index('--uri') + 1]
        if '--home' in argv:
            self.home = self._checkhome(argv[argv.index('--home') + 1])
        elif '-h' in argv:
            self.home = self._checkhome(argv[argv.index('-h') + 1])

    def _checkhome(self, value):
        """Checks the home value"""
        truehome = os.path.realpath(value)
        if truehome is None:
            raise Exception("Wrong home folder")
            self.quit()
        return truehome

    # The language code selector is from:
    # "switch translations dynamically in a PyQt4 application"
    #
    # PyQt version by Hans-Peter Jansen <*****@*****.**>

    def load_translations(self, folder):
        """Loads the transaltions from the parameter folder, the translations
         must match the pattern *_*.qm"""
        if not isinstance(folder, QtCore.QDir):
            folder = QtCore.QDir(folder)
        pattern = "*_*.qm"  # <language>_<country>.qm
        filters = QtCore.QDir.Files | QtCore.QDir.Readable
        sort = QtCore.QDir.SortFlags(QtCore.QDir.Name)
        for lang_file in folder.entryInfoList([pattern], filters, sort):
            # pick country and language out of the file name
            language, country = lang_file.baseName().split("_", 1)
            language = language.toLower()
            country = country.toUpper()
            locale = language + "_" + country
            # only load translation, if it does not exist already
            if not locale in CollectorApplication.translators:
                # create and load translator
                translator = QtCore.QTranslator(self.instance())
                if translator.load(lang_file.absoluteFilePath()):
                    CollectorApplication.translators[locale] = translator

        system = QtCore.QLocale.system()
        # Get user language from collector.conf
        user_language = self.collector.conf('lang')
        # if user_language is ':system:' or is empty, use the system language
        if user_language in [':system:', '']:
            user_language = system.name()
        # Look if the user_language exists, then set as current language
        for lang in CollectorApplication.available_languages():
            if str(lang) == user_language:
                # language match the current system
                CollectorApplication.set_language(lang)

    @staticmethod
    def available_languages():
        """ Returns the avaible languages (code_country) as a list"""
        return sorted(CollectorApplication.translators.keys())

    @staticmethod
    def set_language(locale):
        """ Sets the language of the application using the deseired locale"""
        app = CollectorApplication
        if app.current:
            app.removeTranslator(app.current)
        app.current = app.translators.get(locale, None)
        if app.current is not None:
            app.installTranslator(app.current)
            qt_qm = app.translators.get('qt' + locale[2:], None)
            if qt_qm is not None:
                app.installTranslator(qt_qm)

    @staticmethod
    def get_views(parent):
        """ Initialize the avaible views, each view is loaded by a provider"""
        return {
            'dashboard': DashboardView(parent),
            'fitxa': FitxaView(parent),
            'edit': FitxaEditView(parent),
            'collection': CollectionView(parent),
            'add': FitxaNewView(parent),
            'search': SearchView(parent),
            'discover': DiscoverView(parent),
            'preferences': PreferencesView(parent),
            'quicksearch': SearchDialog(parent),
            'properties': PropertiesView(parent),
            'pluginfile': PluginFileView(parent),
            'filters': AdvancedSearch(parent),
            'import': ImportView(parent),
            'export': ExportView(parent),
        }
Example #2
0
class MainWindow(QMainWindow, Ui_main):
    
    _servers = {}
    _keys = {}
    _commit_keys = {}
    _items = {}
    _splash = None
    
    _profile = None
    
    _selected_key_name = None
    _reload_profiles = False
 
    def __init__(self, profile):
        self._splash = SplashScreen()
        QMainWindow.__init__(self)
        self.setupUi(self)
        
        self._profile = profile
        self.rollback_button.clicked.connect(self.load)
        self.commit_button.clicked.connect(self.commit)
        self.key_list.currentItemChanged.connect(self.key_item_selected)
        self.key_list.itemChanged.connect(self.key_item_changed)
        self.server_tree.itemChanged.connect(self.server_item_selected)
        
        self.add_key_button.clicked.connect(self.import_key)
        self.remove_key_button.clicked.connect(self.remove_key)
        
        self.action_import_key.triggered.connect(self.import_key)
        self.action_profiles.triggered.connect(self.open_profiles)
        self.action_exit.triggered.connect(self.close)
        self.action_about.triggered.connect(self.about)
        
        self.load()
        self.move(self._splash.pos() + self._splash.rect().center() - self.rect().center());
        
    def load(self, action=u'load'):   
        self.key_list.blockSignals(True)
         
        if action == u'commit':
            self._commit_keys = self._keys
        else:
            self._commit_keys = {}
        self._keys = {}
        self._items = {}
         
        self.hide() 
        self._splash.setProgress(0.0, u'Loading server list...')
        self._splash.show()
        
        for _ in range(20):
            time.sleep(0.001)
            QApplication.processEvents()
        
        try:
            self.load_server_list()
            self.load_key_list(action)
            
            self._splash.hide()
            self.show()
            self.key_list.blockSignals(False)
            
            item = self.key_list.item(0)
            item.setSelected(True)
            self.key_item_selected(item)
        except (jsonschema.SchemaError, jsonschema.ValidationError) as ex:
            self.key_list.blockSignals(False)
            self.server_tree.blockSignals(False)
            self._splash.close()
            raise ex
        
    def load_server_list(self):
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        
        try:
            ssh.connect(self._profile[u'host'], username=self._profile[u'user'], 
                        key_filename=self._profile[u'key'] if self._profile[u'key'] else None,
                        timeout=self._profile[u'timeout'])
        except socket.error as ex:
            self._splash.close()
            raise ex
        
        _, stdout, stderr = ssh.exec_command('cat %s' % self._profile['file'])
        error = stderr.read()
        if error:
            raise NameError(error)
        schema_file = open('media/servers-schema-1.0.json', 'r')
        schema = json.load(schema_file)
        schema_file.close()
        self._servers = json.load(stdout)
        validate(self._servers, schema)
        ssh.close()
        
        self.server_tree.blockSignals(True)
        self._items = {}
        while self.server_tree.topLevelItemCount() > 0:
            self.server_tree.takeTopLevelItem(0)
        for group, servers in self._servers[u'servers'].items():
            group_item = self.add_server_tree_item(group)
            for server_name, server in servers.items():
                server_item = self.add_server_tree_item(server_name, group_item)
                for user in server[u'users']:
                    item = self.add_server_tree_item(user, server_item, True)
                    self._items[server_name] = {user: item}          
        self.server_tree.expandAll()
        self.server_tree.blockSignals(False)
        
    def add_server_tree_item(self, label, parent=None, is_leaf=False):
        item = QTreeWidgetItem(parent)
        item.setText(0, unicode(label))
        if is_leaf:
            item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable)
        self.server_tree.addTopLevelItem(item)
        return item      
            
    def load_key_list(self, action):
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
          
        total = 1
        for servers in self._servers[u'servers'].values():
            for server in servers.values():
                total += len(server[u'users'])  
        
        i=0
        for servers in self._servers[u'servers'].values():
            for server_name, server in sorted(servers.items()):
                for user in server[u'users']:
                    i += 1
                    self._splash.setProgress(float(i)/float(total), u'%s %s %s settings...' % (u'Writing' if action == u'commit' else u'Loading', server_name, user))
                    self.load_key_list_from(ssh, server_name, server[u'host'], user, action)
            
        self.reload_key_list()
        
    def reload_key_list(self):
        while self.key_list.count() > 0:
            self.key_list.takeItem(0)
        for key in sorted(self._keys.keys()):
            item = QListWidgetItem(unicode(key))
            item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
            item.setData(Qt.UserRole, unicode(key))
            self.key_list.addItem(item)
        
    def load_key_list_from(self, ssh, server_name, host, user, action):
        try:
            ssh.connect(host, username=user, key_filename=self._profile[u'key'] if self._profile[u'key'] else None,
                        timeout=self._profile[u'timeout'])
        except:
            ssh.close()
            self.server_tree.blockSignals(True)
            self._items[server_name][user].setDisabled(True)
            self.server_tree.blockSignals(False)
            return
              
        if action == u'commit':
            sftp = ssh.open_sftp()
            keyfile = sftp.open('./.ssh/authorized_keys.new', 'w')

            content = u''
            for keyname, key in self._commit_keys.items():
                if (server_name, user) in key[u'servers']:
                    content += (key[u'full'] + u'\n' )
            keyfile.write(content)
            keyfile.close()
            sftp.close()
            ssh.exec_command('mv ./.ssh/authorized_keys.new ./.ssh/authorized_keys')
        
        _, stdout, _ = ssh.exec_command('cat ./.ssh/authorized_keys')
        for line in stdout.readlines():
            keyline = unicode(line).split(' ')
            if len(keyline) == 3:
                proto = keyline[0].rstrip()
                key = keyline[1].rstrip()
                keyname = keyline[2].rstrip()
                
                for i_keyname, i_key in self._keys.items():
                    if i_keyname != keyname and i_key[u'proto'] == proto and i_key[u'key'] == key:
                        keyname = i_keyname
                
                i = 1
                while self._keys.has_key(keyname):
                    if self._keys[keyname][u'proto'] != proto or self._keys[keyname][u'key'] != key:
                        i += 1
                        keyname = keyline[2] + u'_%s' % i
                    else:
                        if not (server_name, user) in self._keys[keyname][u'servers']:
                            self._keys[keyname][u'servers'].append((server_name, user))
                        break
                        
                if not self._keys.has_key(keyname):
                    self._keys[keyname] = {u'proto' : proto, u'key' : key, u'full' : line.rstrip(), u'servers' : [(server_name, user)]}
        
        ssh.close()
                
    def key_item_selected(self, item):
        if not item:
            return
        
        self.server_tree.blockSignals(True)
        self._selected_key_name = unicode(item.text())
        key = self._keys[self._selected_key_name]
        self.key_edit.setText(key[u'full'])
        for server, users in self._items.items():
            for user, item in users.items():
                if (server, user) in key[u'servers']:
                    item.setCheckState(0, Qt.Checked)
                else:
                    item.setCheckState(0, Qt.Unchecked)
        self.server_tree.blockSignals(False)
        
    def key_item_changed(self, item):
        if unicode(item.text()) != unicode(item.data(Qt.UserRole).toString()):
            self._keys[unicode(item.text())] = self._keys.pop(unicode(item.data(Qt.UserRole).toString()))
            self._keys[unicode(item.text())][u'full'] = '%s %s %s' % (self._keys[unicode(item.text())][u'proto'],
                                                                      self._keys[unicode(item.text())][u'key'],
                                                                      unicode(item.text()))
            item.setData(Qt.UserRole, unicode(item.text()))
                
    def server_item_selected(self, item):
        user = unicode(item.text(0))
        server_name = unicode(item.parent().text(0))
        if item.checkState(0) == Qt.Checked:
            if (server_name, user) not in self._keys[self._selected_key_name][u'servers']:
                self._keys[self._selected_key_name][u'servers'].append((server_name, user))
        else:
            if (server_name, user) in self._keys[self._selected_key_name][u'servers']:
                self._keys[self._selected_key_name][u'servers'].remove((server_name, user))
     
    def commit(self):
        self.load(u'commit')
        
    def import_key(self):
        add_key_dialog = AddKeyDialog()
        add_key_dialog.exec_()
        new_key = add_key_dialog.key()
        if new_key:
            self._keys[new_key['keyname']] = {
                u'proto' : new_key['proto'], 
                u'key' : new_key['key'], 
                u'full' : new_key['full'], 
                u'servers' : []
            }
            item = QListWidgetItem(unicode(new_key[u'keyname']))
            self.key_list.addItem(item)
            self.key_list.sortItems()
            item.setSelected(True)
            self.key_item_selected(item)

    def remove_key(self):
        del self._keys[self._selected_key_name]
        self.reload_key_list()
    
        item = self.key_list.item(0)
        item.setSelected(True)
        self.key_item_selected(item)
        
    def reload_profiles(self):
        if self._reload_profiles:
            self._reload_profiles = False
            return True
        return False
        
    def open_profiles(self):
        self._reload_profiles = True
        self.close()

    def about(self):
        QMessageBox.about(self.parent(), u"About SSH key manager", 
                          u"<big><b>SSH key manager</b></big><br/><i>v1.0_alpha1</i><br/><br/>" + 
                          u"<b>Author:</b>" + u"<br/>Hervé Martinet<br/><br/>" +
                          u'<b>Splashscreen Photo:</b><br/>Joel Bennett<br/><a href="http://www.flickr.com/photos/jaykul/">http://www.flickr.com/photos/jaykul/</a>' +
                          u'<br/><i>licensed under a Creative Commons (CC BY-NC-SA 2.0)</i><br/><br/>' +
                          u'<b>Icon Set:</b><br/>Default Icon by interactivemania<br/><a href="http://www.defaulticon.com/">http://www.defaulticon.com/</a>' +
                          u'<br/><i>licensed under a Creative Commons (CC BY-ND 3.0)</i>')