Exemplo n.º 1
0
    def initializePage(self, _id):
        logger.info('Initializing page with id %d' % _id)
        if (_id) == 1:
            if self.ui.createNewMnemonicRadio.isChecked():
                logger.info('Creating new mnemonic from urandom')
                self.mnemonic = mnemonic.to_mnemonic(os.urandom(32))
            self.ui.mnemonicEdit.setPlainText(' '.join(self.mnemonic))

        elif (_id) == 2:
            logger.info('Writing secret')
            if not usb_comm.is_device_available():
                logger.info('No device found')
                QMessageBox.critical(self, 'Device not found',
                                     'No Snopf device found.', QMessageBox.Ok)
                self.reject()
                return

            dev = usb_comm.get_standard_device()
            msg = usb_comm.build_new_secret_message(
                mnemonic.to_entropy(self.mnemonic))
            usb_comm.send_message(dev, msg)

        elif (_id) == 3:
            logger.info('Starting challenge response')
            rq = os.urandom(16)
            msg = usb_comm.build_request_message(rq, 42, 0, [],
                                                 pg.keymaps['all'])
            dev = usb_comm.get_standard_device()
            usb_comm.send_message(dev, msg)
            expected = pg.get_mapped_password(
                mnemonic.to_entropy(self.mnemonic), rq, 42, 0,
                pg.keymaps['all'])
            self.ui.expectedPasswordLabel.setText(
                pg.map_to_characters(expected))
Exemplo n.º 2
0
 def setKeyboardLayout(self):
     '''Set a new keyboard layout on a connected Snopf device'''
     fileName, _ = QFileDialog.getOpenFileName(self,
                                               'Open Keyboard Layout File',
                                               str(Path.home()),
                                               'Json (*.json)')
     if not fileName:
         return
     layout = json.load(open(fileName))
     try:
         keyboard_layouts.check_keyboard_layout(layout)
     except ValueError as e:
         logger.info('Invalid keyboard layout file. Reason: %s' % e)
         QMessageBox.critical(self, 'Invalid Keyboard Layout File', str(e),
                              QMessageBox.Ok)
         return
     bytesLayout = keyboard_layouts.to_bytes(layout)
     if not usb_comm.is_device_available():
         QMessageBox.critical(self, 'Device not found',
                              'The device is not plugged in.',
                              QMessageBox.Ok)
         return
     dev = usb_comm.get_standard_device()
     msg = usb_comm.build_new_keyboard_keycodes_message(bytesLayout)
     usb_comm.send_message(dev, msg)
     QMessageBox.information(
         self, 'Setting Keyboard Layout',
         'Press the Button on the device for five seconds to set new keyboard layout.',
         QMessageBox.Ok)
     logger.info('New Keyboard layout set')
Exemplo n.º 3
0
    def requestPassword(self, service=None, account=None, makeNewEntry=False):
        '''
        Make a password request using the given service and account combination.
        If no service and account are submitted the currently selected item from the account table
        widget is used
        If makeNewEntry is set to True a non-existing service-account tuple will be added to the
        account table if necessary
        '''
        if not service:
            entry = self.atModel.table[self.mapSelectedEntryIndex().row()]
        else:
            try:
                entry = self.atModel.getEntry(service, account)
            except KeyError:
                logger.info(
                    'Password request with unknown service-account combination'
                )
                if makeNewEntry:
                    logger.info('Creating new entry')
                    self.atModel.newEntry(service, account)
                    entry = self.atModel.getEntry(service, account)
                else:
                    logger.warning(
                        'Unknown service-account but no new entry created')
                    return

        if not usb_comm.is_device_available():
            QMessageBox.critical(self, 'Device not found',
                                 'The device is not plugged in.',
                                 QMessageBox.Ok)
            return

        req_msg = requests.combine_standard_request(
            entry['service'].encode(), entry['account'].encode(),
            self.masterPassphrase, entry['password_iteration'])

        req = usb_comm.build_request_message(req_msg, entry['password_length'],
                                             pg.bool_to_rules(entry),
                                             entry['appendix'],
                                             entry['keymap'])
        dev = usb_comm.get_standard_device()
        if not dev:
            QMessageBox.critical(self, 'Device not found',
                                 'The device is not plugged in.',
                                 QMessageBox.Ok)
            return

        try:
            usb_comm.send_message(dev, req)
        except USBError as e:
            QMessageBox.critical(self, 'USB error',
                                 'Cannot send to USB device. %s' % str(e),
                                 QMessageBox.Ok)
            logger.error('USB Error', exc_info=sys.exc_info())
Exemplo n.º 4
0
 def setKeyboardDelay(self):
     '''Set the keyboard delay for a connected snopf device'''
     delay, ok = QInputDialog.getInt(self, 'Set Keyboard Delay',
                                     'Delay in ms', 10, 0, 255)
     if ok:
         if not usb_comm.is_device_available():
             QMessageBox.critical(self, 'Device not found',
                                  'The device is not plugged in.',
                                  QMessageBox.Ok)
             return
         dev = usb_comm.get_standard_device()
         msg = usb_comm.build_set_keyboard_delay_message(delay)
         usb_comm.send_message(dev, msg)
         QMessageBox.information(
             self, 'Setting Keyboard Delay',
             'Press the Button on the device to set the new delay.',
             QMessageBox.Ok)
Exemplo n.º 5
0
def main_loop():
    account_table_path = app_path + '/../snopf_manager/account_table.json'
    account_table = load_account_table(account_table_path)
    
    try:        
        while True:
            cmd, msg = get_msg()
            
            if cmd == 'get_account_table':
                send_msg(cmd, account_table)
                    
            elif cmd == 'check_device_available':
                send_msg(cmd, str(usb_comm.is_device_available()))
            
            elif cmd == 'request_password':
                msg['password_iteration'] = int(msg['password_iteration'])
                msg['password_length'] = int(msg['password_length'])
                if msg['save_new_info']:
                    if entry_is_new(msg, account_table):
                        if save_new_entry(msg, account_table_path):
                            account_table = load_account_table(
                                account_table_path)
                            send_msg('get_account_table', account_table)
                        else:
                            error('Cannot lock account table file')
                
                request = requests.combine_standard_request(msg)
                try:
                    usb_comm.send_standard_pw_request(
                        request, msg['password_length'],
                        hit_enter=msg['hit_enter'])
                except usb_comm.DeviceNotFound:
                    error('Device not connected')
            
            elif cmd == 'version':
                send_msg(cmd, get_commit())
                
            elif cmd == 'debug':
                logging.info(msg)
                
            else:
                error('Wrong message format')

    except Exception as e:
        logging.exception(str(e))
Exemplo n.º 6
0
    def __init__(self, configPath=None):
        super().__init__()
        self.ui = Ui_SnopfManager()
        self.ui.setupUi(self)

        # Log uncaught exceptions
        sys.excepthook = self.logException

        logger.info('Application started')

        # Setting up directories for app
        self.user_data_dir = appdirs.user_data_dir('snopf-manager', 'snopf')
        if not os.path.exists(self.user_data_dir):
            logger.info('Creating user data dir: %s' % str(self.user_data_dir))
            os.makedirs(self.user_data_dir)

        self.user_config_dir = configPath
        if not self.user_config_dir:
            self.user_config_dir = appdirs.user_config_dir(
                'snopf-manager', 'snopf')
        if not os.path.exists(self.user_config_dir):
            logger.info('Creating user config dir: %s' %
                        str(self.user_config_dir))
            os.makedirs(self.user_config_dir)
        logger.info('Working with user config dir: %s' %
                    str(self.user_config_dir))

        # Initialize tray icon
        self.tray = QSystemTrayIcon()
        self.tray.setIcon(QIcon(':/icon/icon/icon.svg'))
        self.tray.setToolTip('Snopf')
        trayMenu = QMenu(self)
        actionExit = trayMenu.addAction('Exit')
        actionExit.triggered.connect(self.exit)
        self.tray.setContextMenu(trayMenu)
        self.tray.activated.connect(self.trayIconActivated)
        self.tray.show()

        # Master passphrase for current account table
        self.masterPassphrase = None

        # Filename of open account table
        self.__fileName = None

        # Model for Account Table data
        self.atModel = None
        # Mapper for widgets <> model
        self.atMapper = None

        # Software version
        self.commitHash = get_commit_hash()
        logger.info('Git hash: %s' % self.commitHash)

        # Connect menu actions
        self.ui.actionNew.triggered.connect(self.newAccountTable)
        self.ui.actionOpen.triggered.connect(self.openAccountTable)
        self.ui.actionSave.triggered.connect(self.saveAccountTable)
        self.ui.actionSaveAs.triggered.connect(self.saveAccountTableAs)
        self.ui.actionSave.setEnabled(False)
        self.ui.actionSaveAs.setEnabled(False)
        self.ui.actionOptions.triggered.connect(self.editOptions)
        self.ui.actionExit.triggered.connect(self.exit)

        self.ui.actionNewEntry.triggered.connect(self.newEntry)
        self.ui.actionDeleteEntry.triggered.connect(self.deleteEntry)
        # Entry modyfing only makes sense if we have an active account table
        self.ui.actionNewEntry.setEnabled(False)
        self.ui.actionDeleteEntry.setEnabled(False)

        self.ui.actionVersionInfo.triggered.connect(self.showVersionInfo)
        self.ui.actionSetSnopfSecret.triggered.connect(self.startSecretWizard)
        self.ui.actionSetKeyboardDelay.triggered.connect(self.setKeyboardDelay)
        self.ui.actionSetKeyboardLayout.triggered.connect(
            self.setKeyboardLayout)

        # Account table
        self.ui.deleteEntryButton.clicked.connect(self.deleteEntry)
        self.ui.requestPasswordButton.clicked.connect(
            lambda x: self.requestPassword())
        self.ui.accountTableView.activated.connect(self.entrySelected)
        self.ui.entropyEdit.textChanged.connect(self.decorateEntropy)

        # Keymap editing
        self.ui.keymapEdit.keymapChanged.connect(
            lambda remKeys: self.ui.remainingKeysEdit.setText(''.join(remKeys)
                                                              ))
        self.ui.addLowercaseButton.clicked.connect(
            self.ui.keymapEdit.addLowercase)
        self.ui.addUppercaseButton.clicked.connect(
            self.ui.keymapEdit.addUppercase)
        self.ui.addNumericalButton.clicked.connect(
            self.ui.keymapEdit.addNumerical)
        self.ui.addSpecialButton.clicked.connect(self.ui.keymapEdit.addSpecial)
        self.ui.applyKeymapButton.clicked.connect(self.selectPresetKeymap)
        self.fillKeymapCombobox()

        # Appendix
        self.addAppendixValidator()

        # Password settings
        self.ui.lengthSpinner.setMinimum(pg.MIN_PW_LENGTH)
        self.ui.lengthSpinner.setMaximum(pg.MAX_PW_LENGTH)
        self.ui.lengthSpinner.setValue(pg.DEFAULT_PW_LENGTH)

        # Load snopf options file
        self.loadOptions()

        # Init websocket server
        self.websocketServer = SnopfWebsocketServer(
            self, self.options['websocket-port'],
            self.options['websocket-whitelist'])
        self.websocketServer.deviceAvailableRequest.connect(
            lambda ws: self.websocketServer.sendDeviceAvailable(
                ws, usb_comm.is_device_available()))
        self.websocketServer.accountsRequest.connect(
            lambda ws: self.websocketServer.sendAccountsList(
                ws, self.getAccounts()))
        self.websocketServer.passwordRequest.connect(self.requestPassword)

        # Load last loaded file if available
        if self.options['last-filename']:
            try:
                self.openAccountTable(self.options['last-filename'])
            except FileNotFoundError:
                logger.warning('Last file % s not found, skipping auto load' %
                               lastFileName)