def disable(self, url, server): resp = baseconv.decodeNameValue(server) tif = int(resp['tif'], 16) client = "ver=1\r\n" client += "cmd=disable\r\n" client += "idk=%s\r\n" % self.enc.getPublicKey(url.getDomain()) client = baseconv.encode(client) ids = self.enc.sign(client + server) url = URLParser(url.scheme + "://" + url.netloc + resp['qry']) success, data = self._post_form(url, "client=%s&server=%s&ids=%s" % (client, server, ids)) logging.debug("client") for param in baseconv.decode(client).rstrip('\r\n').split('\r\n'): logging.debug(' %r', param) logging.debug("server") for param in baseconv.decode(server).rstrip('\r\n').split('\r\n'): logging.debug(' %r', param) logging.debug(' ids %r', ids) if success: resp = baseconv.decodeNameValue(data) logging.debug("resp %r", resp) tif = int(resp['tif'], 16) if tif & 0x10 == 0x10: return False, "0x10 Function(s) not supported" if tif & 0x08 == 0x08: return True, "0x08 SQRL disabled" return False, data
def _check_signature(self, idk, client, server, ids): verifying_key = ed25519.VerifyingKey(baseconv.decode(idk)) try: verifying_key.verify(baseconv.decode(ids), str(client + server)) return True except ed25519.BadSignatureError: return False
def ident(self, url, server): resp = baseconv.decodeNameValue(server) tif = int(resp['tif'], 16) client = "ver=1\r\n" client += "cmd=ident\r\n" client += "idk=%s\r\n" % self.enc.getPublicKey(url.getDomain()) if self.cps: client += "opt=cps\r\n" if tif & 0x01 == 0x00: client += "suk=dMRXbs49XNmVUhsKzta7ESD-cP2QlnxkSaORsswOAj4\r\n" # TODO: ehhh... client += "vuk=q13E_hd5CR0WE0A9ZD8571te0Ul47YfsDCWpETuCGcI\r\n" # TODO: ehhh... client = baseconv.encode(client) ids = self.enc.sign(client + server) url = URLParser(url.scheme + "://" + url.netloc + resp['qry']) success, data = self._post_form(url, "client=%s&server=%s&ids=%s" % (client, server, ids)) logging.debug("client") for param in baseconv.decode(client).rstrip('\r\n').split('\r\n'): logging.debug(' %r', param) logging.debug("server") for param in baseconv.decode(server).rstrip('\r\n').split('\r\n'): logging.debug(' %r', param) logging.debug(' ids %r', ids) if success: resp = baseconv.decodeNameValue(data) logging.debug("resp %r", resp) tif = int(resp['tif'], 16) if tif & 0x08 == 0x08: return False, "0x08 SQRL disabled" if tif & 0x10 == 0x10: return False, "0x10 Function(s) not supported" #if tif > 0x04: # TODO: Check tif failure values # return False, "Tif 0x%02x" % tif if 'url' in resp: return True, resp['url'] else: return True, None return False, data
def post(self, client_str, server_str, ids, sqrl_callback): client_str = str(client_str) # TODO(vw): Do we want to support u'nicode' or just convert? server_str = str(server_str) # TODO(vw): Do we want to support u'nicode' or just convert? client = baseconv.decodeNameValue(client_str) server = baseconv.decodeNameValue(server_str) cmd = self._get_value(client, 'cmd') idk = self._get_value(client, 'idk') logging.info("cmd: %r", cmd) logging.debug('client:') for key, value in client.iteritems(): logging.debug(" %r: %r", key, value) logging.debug('server:') for key, value in server.iteritems(): logging.debug(" %r: %r", key, value) logging.debug('ids:') logging.debug(" %r", ids) tif = 0 tif ^= 4 # TODO: Check if IP matches session_id = None if not self._check_signature(idk, client_str, server_str, ids): logging.warn("signature failed") tif ^= 80 # We always included a session_id, so something has gone wrong elif cmd == 'query': session_id = self._get_url_nut(baseconv.decode(server_str)) if sqrl_callback.id_found(idk): tif ^= 1 elif cmd == 'ident': session_id = self._get_value(server, 'session_id') if not session_id: tif ^= 80 # We always included a session_id, so something has gone wrong else: if sqrl_callback.id_found(idk): tif ^= 1 suk = self._get_value(server, 'suk') # TODO: Can be '' vuk = self._get_value(server, 'vuk') sqrl_callback.ident(session_id, idk, suk, vuk) else: tif ^= 10 # Not supported new_nut = get_nut() server = "ver=1\r\n" server += "nut=%s\r\n" % new_nut server += "qry=/sqrl?nut=%s\r\n" % new_nut server += "tif=%x\r\n" % tif if session_id: server += "session_id=%s\r\n" % session_id logging.debug('response') for param in server.split('\r\n')[:-1]: logging.debug(' %r', param) return server
def query(self, url, server, automatic_retry=True): client = "ver=1\r\n" client += "cmd=query\r\n" client += "idk=%s\r\n" % self.enc.getPublicKey(url.getDomain()) if self.cps: client += "opt=cps\r\n" client = baseconv.encode(client) ids = self.enc.sign(client + server) success, data = self._post_form(url, "client=%s&server=%s&ids=%s" % (client, server, ids)) logging.debug("client") for param in baseconv.decode(client).rstrip('\r\n').split('\r\n'): logging.debug(' %r', param) logging.debug("server") for param in baseconv.decode(server).rstrip('\r\n').split('\r\n'): logging.debug(' %r', param) logging.debug(' ids %r', ids) if success: resp = baseconv.decodeNameValue(data) logging.debug("resp %r", resp) tif = int(resp['tif'], 16) if tif & 0x01 == 0x01: logging.info("ID match") if tif & 0x04 == 0x04: logging.info("IP matched") #if tif > 0x04: # TODO: Check tif failure values # logging.warn("Problems with query, tif 0x%02x", tif) if tif & 0x20 == 0x20: if automatic_retry: logging.debug("0x20 Transient error. Trying again") url = URLParser(url.scheme + "://" + url.netloc + resp['qry']) return self.query(url, data, False) return success, data
def test_decode_unicode(self): self.assertEqual(baseconv.decode(u"YWJjZA"), 'abcd')
def test_decode_padding_added_back(self): self.assertEqual(baseconv.decode("YWJjZA"), 'abcd') self.assertEqual(baseconv.decode("YWJjZGU"), 'abcde')
def test_decode_no_padding(self): self.assertEqual(baseconv.decode("YWJj"), 'abc')