def ccid_add_credential( self, name, secret, issuer, oath_type, algo, digits, period, touch, overwrite=False): secret = parse_b32_key(secret) with self._open_oath() as oath_controller: try: self._unlock(oath_controller) cred_data = CredentialData( secret, issuer, name, OATH_TYPE[oath_type], ALGO[algo], int(digits), int(period), 0, touch ) if not overwrite: key = cred_data.make_key() if key in [cred.key for cred in oath_controller.list()]: return failure('credential_already_exists') oath_controller.put(cred_data) except APDUError as e: # NEO doesn't return a no space error if full, # but a command aborted error. Assume it's because of # no space in this context. if e.sw in (SW.NO_SPACE, SW.COMMAND_ABORTED): return failure('no_space') else: raise return success()
def test_credential_data_make_key(self): self.assertEqual(b'name', CredentialData(b'', None, 'name').make_key()) self.assertEqual(b'Issuer:name', CredentialData(b'', 'Issuer', 'name').make_key()) self.assertEqual(b'20/Issuer:name', CredentialData(b'', 'Issuer', 'name', period=20 ).make_key()) self.assertEqual(b'Issuer:name', CredentialData(b'', 'Issuer', 'name', period=30 ).make_key()) self.assertEqual(b'20/name', CredentialData(b'', None, 'name', period=20 ).make_key())
def test_parse_uri_issuer(self): no_issuer = CredentialData.from_uri('otpauth://totp/account' '?secret=abba') self.assertIsNone(no_issuer.issuer) from_param = CredentialData.from_uri('otpauth://totp/account' '?secret=abba&issuer=Test') self.assertEqual('Test', from_param.issuer) from_name = CredentialData.from_uri('otpauth://totp/Test:account' '?secret=abba') self.assertEqual('Test', from_name.issuer) with_both = CredentialData.from_uri('otpauth://totp/TestA:account' '?secret=abba&issuer=TestB') self.assertEqual('TestB', with_both.issuer)
def parse_qr(self, screenshot): data = b64decode(screenshot['data']) image = PixelImage(data, screenshot['width'], screenshot['height']) for qr in qrparse.parse_qr_codes(image, 2): try: return success( credential_data_to_dict( CredentialData.from_uri(qrdecode.decode_qr_data(qr)))) except Exception as e: logger.error('Failed to parse uri', exc_info=e) return failure('failed_to_parse_uri') return failure('no_credential_found')
def test_parse_uri(self): data = CredentialData.from_uri('otpauth://totp/Issuer:account' '?secret=abba&issuer=Issuer' '&algorithm=SHA256&digits=7' '&period=20&counter=5') self.assertEqual(b'\0B', data.secret) self.assertEqual('Issuer', data.issuer) self.assertEqual('account', data.name) self.assertEqual(OATH_TYPE.TOTP, data.oath_type) self.assertEqual(ALGO.SHA256, data.algorithm) self.assertEqual(7, data.digits) self.assertEqual(20, data.period) self.assertEqual(5, data.counter) self.assertEqual(False, data.touch)
def add_credential(self, name, secret, issuer, oath_type, algo, digits, period, touch): dev = self._descriptor.open_device(TRANSPORT.CCID) controller = OathController(dev.driver) self._unlock(controller) try: secret = parse_b32_key(secret) except Exception as e: return str(e) try: controller.put( CredentialData(secret, issuer, name, OATH_TYPE[oath_type], ALGO[algo], int(digits), int(period), 0, touch)) except APDUError as e: # NEO doesn't return a no space error if full, # but a command aborted error. Assume it's because of # no space in this context. if e.sw in (SW.NO_SPACE, SW.COMMAND_ABORTED): return 'No space' else: raise
def parse_qr(self, screenshot): data = b64decode(screenshot['data']) image = PixelImage(data, screenshot['width'], screenshot['height']) for qr in qrparse.parse_qr_codes(image, 2): return credential_data_to_dict( CredentialData.from_uri(qrdecode.decode_qr_data(qr)))