Token stored as bytes and not limited to ascii chars anymore

This commit is contained in:
Björn Freise 2019-04-23 11:43:02 +02:00
parent 36fb9f243a
commit 2eafa64308
7 changed files with 81 additions and 57 deletions

View file

@ -1,5 +1,7 @@
import logging import logging
from coapthon import defines from coapthon import defines
from coapthon import utils
from coapthon.messages.request import Request from coapthon.messages.request import Request
from coapthon.messages.response import Response from coapthon.messages.response import Response
@ -49,7 +51,7 @@ class BlockLayer(object):
""" """
if transaction.request.block2 is not None: if transaction.request.block2 is not None:
host, port = transaction.request.source host, port = transaction.request.source
key_token = hash(str(host) + str(port) + str(transaction.request.token)) key_token = utils.str_append_hash(host, port, transaction.request.token)
num, m, size = transaction.request.block2 num, m, size = transaction.request.block2
if key_token in self._block2_receive: if key_token in self._block2_receive:
self._block2_receive[key_token].num = num self._block2_receive[key_token].num = num
@ -65,7 +67,7 @@ class BlockLayer(object):
elif transaction.request.block1 is not None: elif transaction.request.block1 is not None:
# POST or PUT # POST or PUT
host, port = transaction.request.source host, port = transaction.request.source
key_token = hash(str(host) + str(port) + str(transaction.request.token)) key_token = utils.str_append_hash(host, port, transaction.request.token)
num, m, size = transaction.request.block1 num, m, size = transaction.request.block1
if transaction.request.size1 is not None: if transaction.request.size1 is not None:
# What to do if the size1 is larger than the maximum resource size or the maxium server buffer # What to do if the size1 is larger than the maximum resource size or the maxium server buffer
@ -122,7 +124,7 @@ class BlockLayer(object):
:return: the edited transaction :return: the edited transaction
""" """
host, port = transaction.response.source host, port = transaction.response.source
key_token = hash(str(host) + str(port) + str(transaction.response.token)) key_token = utils.str_append_hash(host, port, transaction.response.token)
if key_token in self._block1_sent and transaction.response.block1 is not None: if key_token in self._block1_sent and transaction.response.block1 is not None:
item = self._block1_sent[key_token] item = self._block1_sent[key_token]
transaction.block_transfer = True transaction.block_transfer = True
@ -214,7 +216,7 @@ class BlockLayer(object):
:return: the edited transaction :return: the edited transaction
""" """
host, port = transaction.request.source host, port = transaction.request.source
key_token = hash(str(host) + str(port) + str(transaction.request.token)) key_token = utils.str_append_hash(host, port, transaction.request.token)
if (key_token in self._block2_receive and transaction.response.payload is not None) or \ if (key_token in self._block2_receive and transaction.response.payload is not None) or \
(transaction.response.payload is not None and len(transaction.response.payload) > defines.MAX_PAYLOAD): (transaction.response.payload is not None and len(transaction.response.payload) > defines.MAX_PAYLOAD):
if key_token in self._block2_receive: if key_token in self._block2_receive:
@ -260,7 +262,7 @@ class BlockLayer(object):
assert isinstance(request, Request) assert isinstance(request, Request)
if request.block1 or (request.payload is not None and len(request.payload) > defines.MAX_PAYLOAD): if request.block1 or (request.payload is not None and len(request.payload) > defines.MAX_PAYLOAD):
host, port = request.destination host, port = request.destination
key_token = hash(str(host) + str(port) + str(request.token)) key_token = utils.str_append_hash(host, port, request.token)
if request.block1: if request.block1:
num, m, size = request.block1 num, m, size = request.block1
else: else:
@ -277,7 +279,7 @@ class BlockLayer(object):
request.block1 = (num, m, size) request.block1 = (num, m, size)
elif request.block2: elif request.block2:
host, port = request.destination host, port = request.destination
key_token = hash(str(host) + str(port) + str(request.token)) key_token = utils.str_append_hash(host, port, request.token)
num, m, size = request.block2 num, m, size = request.block2
item = BlockItem(size, num, m, size, "", None) item = BlockItem(size, num, m, size, "", None)
self._block2_sent[key_token] = item self._block2_sent[key_token] = item

View file

@ -2,6 +2,8 @@ import logging
import random import random
import time import time
import socket import socket
from coapthon import utils
from coapthon.messages.message import Message from coapthon.messages.message import Message
from coapthon import defines from coapthon import defines
from coapthon.messages.request import Request from coapthon.messages.request import Request
@ -12,15 +14,6 @@ __author__ = 'Giacomo Tanganelli'
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def str_append_hash(*args):
""" Convert each argument to a lower case string, appended, then hash """
ret_hash = ""
for i in args:
ret_hash += str(i).lower()
return hash(ret_hash)
class MessageLayer(object): class MessageLayer(object):
""" """
Handles matching between messages (Message ID) and request/response (Token) Handles matching between messages (Message ID) and request/response (Token)
@ -77,8 +70,8 @@ class MessageLayer(object):
host, port = request.source host, port = request.source
except AttributeError: except AttributeError:
return return
key_mid = str_append_hash(host, port, request.mid) key_mid = utils.str_append_hash(host, port, request.mid)
key_token = str_append_hash(host, port, request.token) key_token = utils.str_append_hash(host, port, request.token)
if key_mid in list(self._transactions.keys()): if key_mid in list(self._transactions.keys()):
# Duplicated # Duplicated
@ -107,10 +100,10 @@ class MessageLayer(object):
except AttributeError: except AttributeError:
return return
all_coap_nodes = defines.ALL_COAP_NODES_IPV6 if socket.getaddrinfo(host, None)[0][0] == socket.AF_INET6 else defines.ALL_COAP_NODES all_coap_nodes = defines.ALL_COAP_NODES_IPV6 if socket.getaddrinfo(host, None)[0][0] == socket.AF_INET6 else defines.ALL_COAP_NODES
key_mid = str_append_hash(host, port, response.mid) key_mid = utils.str_append_hash(host, port, response.mid)
key_mid_multicast = str_append_hash(all_coap_nodes, port, response.mid) key_mid_multicast = utils.str_append_hash(all_coap_nodes, port, response.mid)
key_token = str_append_hash(host, port, response.token) key_token = utils.str_append_hash(host, port, response.token)
key_token_multicast = str_append_hash(all_coap_nodes, port, response.token) key_token_multicast = utils.str_append_hash(all_coap_nodes, port, response.token)
if key_mid in list(self._transactions.keys()): if key_mid in list(self._transactions.keys()):
transaction = self._transactions[key_mid] transaction = self._transactions[key_mid]
if response.token != transaction.request.token: if response.token != transaction.request.token:
@ -154,10 +147,10 @@ class MessageLayer(object):
except AttributeError: except AttributeError:
return return
all_coap_nodes = defines.ALL_COAP_NODES_IPV6 if socket.getaddrinfo(host, None)[0][0] == socket.AF_INET6 else defines.ALL_COAP_NODES all_coap_nodes = defines.ALL_COAP_NODES_IPV6 if socket.getaddrinfo(host, None)[0][0] == socket.AF_INET6 else defines.ALL_COAP_NODES
key_mid = str_append_hash(host, port, message.mid) key_mid = utils.str_append_hash(host, port, message.mid)
key_mid_multicast = str_append_hash(all_coap_nodes, port, message.mid) key_mid_multicast = utils.str_append_hash(all_coap_nodes, port, message.mid)
key_token = str_append_hash(host, port, message.token) key_token = utils.str_append_hash(host, port, message.token)
key_token_multicast = str_append_hash(all_coap_nodes, port, message.token) key_token_multicast = utils.str_append_hash(all_coap_nodes, port, message.token)
if key_mid in list(self._transactions.keys()): if key_mid in list(self._transactions.keys()):
transaction = self._transactions[key_mid] transaction = self._transactions[key_mid]
elif key_token in self._transactions_token: elif key_token in self._transactions_token:
@ -216,10 +209,10 @@ class MessageLayer(object):
if transaction.request.mid is None: if transaction.request.mid is None:
transaction.request.mid = self.fetch_mid() transaction.request.mid = self.fetch_mid()
key_mid = str_append_hash(host, port, request.mid) key_mid = utils.str_append_hash(host, port, request.mid)
self._transactions[key_mid] = transaction self._transactions[key_mid] = transaction
key_token = str_append_hash(host, port, request.token) key_token = utils.str_append_hash(host, port, request.token)
self._transactions_token[key_token] = transaction self._transactions_token[key_token] = transaction
return self._transactions[key_mid] return self._transactions[key_mid]
@ -252,7 +245,7 @@ class MessageLayer(object):
host, port = transaction.response.destination host, port = transaction.response.destination
except AttributeError: except AttributeError:
return return
key_mid = str_append_hash(host, port, transaction.response.mid) key_mid = utils.str_append_hash(host, port, transaction.response.mid)
self._transactions[key_mid] = transaction self._transactions[key_mid] = transaction
transaction.request.acknowledged = True transaction.request.acknowledged = True
@ -274,8 +267,8 @@ class MessageLayer(object):
host, port = message.destination host, port = message.destination
except AttributeError: except AttributeError:
return return
key_mid = str_append_hash(host, port, message.mid) key_mid = utils.str_append_hash(host, port, message.mid)
key_token = str_append_hash(host, port, message.token) key_token = utils.str_append_hash(host, port, message.token)
if key_mid in self._transactions: if key_mid in self._transactions:
transaction = self._transactions[key_mid] transaction = self._transactions[key_mid]
related = transaction.response related = transaction.response

View file

@ -1,6 +1,8 @@
import logging import logging
import time import time
from coapthon import defines from coapthon import defines
from coapthon import utils
__author__ = 'Giacomo Tanganelli' __author__ = 'Giacomo Tanganelli'
@ -40,7 +42,7 @@ class ObserveLayer(object):
if request.observe == 0: if request.observe == 0:
# Observe request # Observe request
host, port = request.destination host, port = request.destination
key_token = hash(str(host) + str(port) + str(request.token)) key_token = utils.str_append_hash(host, port, request.token)
self._relations[key_token] = ObserveItem(time.time(), None, True, None) self._relations[key_token] = ObserveItem(time.time(), None, True, None)
@ -56,7 +58,7 @@ class ObserveLayer(object):
:return: the modified transaction :return: the modified transaction
""" """
host, port = transaction.response.source host, port = transaction.response.source
key_token = hash(str(host) + str(port) + str(transaction.response.token)) key_token = utils.str_append_hash(host, port, transaction.response.token)
if key_token in self._relations and transaction.response.type == defines.Types["CON"]: if key_token in self._relations and transaction.response.type == defines.Types["CON"]:
transaction.notification = True transaction.notification = True
return transaction return transaction
@ -70,7 +72,7 @@ class ObserveLayer(object):
:return: the message unmodified :return: the message unmodified
""" """
host, port = message.destination host, port = message.destination
key_token = hash(str(host) + str(port) + str(message.token)) key_token = utils.str_append_hash(host, port, message.token)
if key_token in self._relations and message.type == defines.Types["RST"]: if key_token in self._relations and message.type == defines.Types["RST"]:
del self._relations[key_token] del self._relations[key_token]
return message return message
@ -88,7 +90,7 @@ class ObserveLayer(object):
if transaction.request.observe == 0: if transaction.request.observe == 0:
# Observe request # Observe request
host, port = transaction.request.source host, port = transaction.request.source
key_token = hash(str(host) + str(port) + str(transaction.request.token)) key_token = utils.str_append_hash(host, port, transaction.request.token)
non_counter = 0 non_counter = 0
if key_token in self._relations: if key_token in self._relations:
# Renew registration # Renew registration
@ -98,7 +100,7 @@ class ObserveLayer(object):
self._relations[key_token] = ObserveItem(time.time(), non_counter, allowed, transaction) self._relations[key_token] = ObserveItem(time.time(), non_counter, allowed, transaction)
elif transaction.request.observe == 1: elif transaction.request.observe == 1:
host, port = transaction.request.source host, port = transaction.request.source
key_token = hash(str(host) + str(port) + str(transaction.request.token)) key_token = utils.str_append_hash(host, port, transaction.request.token)
logger.info("Remove Subscriber") logger.info("Remove Subscriber")
try: try:
del self._relations[key_token] del self._relations[key_token]
@ -120,7 +122,7 @@ class ObserveLayer(object):
""" """
if empty.type == defines.Types["RST"]: if empty.type == defines.Types["RST"]:
host, port = transaction.request.source host, port = transaction.request.source
key_token = hash(str(host) + str(port) + str(transaction.request.token)) key_token = utils.str_append_hash(host, port, transaction.request.token)
logger.info("Remove Subscriber") logger.info("Remove Subscriber")
try: try:
del self._relations[key_token] del self._relations[key_token]
@ -138,7 +140,7 @@ class ObserveLayer(object):
:return: the transaction unmodified :return: the transaction unmodified
""" """
host, port = transaction.request.source host, port = transaction.request.source
key_token = hash(str(host) + str(port) + str(transaction.request.token)) key_token = utils.str_append_hash(host, port, transaction.request.token)
if key_token in self._relations: if key_token in self._relations:
if transaction.response.code == defines.Codes.CONTENT.number: if transaction.response.code == defines.Codes.CONTENT.number:
if transaction.resource is not None and transaction.resource.observable: if transaction.resource is not None and transaction.resource.observable:
@ -190,7 +192,7 @@ class ObserveLayer(object):
""" """
logger.info("Remove Subcriber") logger.info("Remove Subcriber")
host, port = message.destination host, port = message.destination
key_token = hash(str(host) + str(port) + str(message.token)) key_token = utils.str_append_hash(host, port, message.token)
try: try:
self._relations[key_token].transaction.completed = True self._relations[key_token].transaction.completed = True
del self._relations[key_token] del self._relations[key_token]

View file

@ -1,5 +1,9 @@
from coapthon.utils import parse_blockwise # -*- coding: utf-8 -*-
import binascii
from coapthon import defines from coapthon import defines
from coapthon import utils
from coapthon.messages.option import Option from coapthon.messages.option import Option
__author__ = 'Giacomo Tanganelli' __author__ = 'Giacomo Tanganelli'
@ -122,8 +126,10 @@ class Message(object):
if value is None: if value is None:
self._token = value self._token = value
return return
if not isinstance(value, str): if isinstance(value, int):
value = str(value) value = bytes([value])
if not isinstance(value, bytes):
value = bytes(value, "utf-8")
if len(value) > 256: if len(value) > 256:
raise AttributeError raise AttributeError
self._token = value self._token = value
@ -547,7 +553,7 @@ class Message(object):
value = None value = None
for option in self.options: for option in self.options:
if option.number == defines.OptionRegistry.BLOCK1.number: if option.number == defines.OptionRegistry.BLOCK1.number:
value = parse_blockwise(option.value) value = utils.parse_blockwise(option.value)
return value return value
@block1.setter @block1.setter
@ -599,7 +605,7 @@ class Message(object):
value = None value = None
for option in self.options: for option in self.options:
if option.number == defines.OptionRegistry.BLOCK2.number: if option.number == defines.OptionRegistry.BLOCK2.number:
value = parse_blockwise(option.value) value = utils.parse_blockwise(option.value)
return value return value
@block2.setter @block2.setter
@ -691,12 +697,14 @@ class Message(object):
if self._code is None: if self._code is None:
self._code = defines.Codes.EMPTY.number self._code = defines.Codes.EMPTY.number
token = binascii.hexlify(self._token).decode("utf-8") if self._token is not None else str(None)
msg = "From {source}, To {destination}, {type}-{mid}, {code}-{token}, ["\ msg = "From {source}, To {destination}, {type}-{mid}, {code}-{token}, ["\
.format(source=self._source, destination=self._destination, type=inv_types[self._type], mid=self._mid, .format(source=self._source, destination=self._destination, type=inv_types[self._type], mid=self._mid,
code=defines.Codes.LIST[self._code].name, token=self._token) code=defines.Codes.LIST[self._code].name, token=token)
for opt in self._options: for opt in self._options:
if 'Block' in opt.name: if 'Block' in opt.name:
msg += "{name}: {value}, ".format(name=opt.name, value=parse_blockwise(opt.value)) msg += "{name}: {value}, ".format(name=opt.name, value=utils.parse_blockwise(opt.value))
else: else:
msg += "{name}: {value}, ".format(name=opt.name, value=opt.value) msg += "{name}: {value}, ".format(name=opt.name, value=opt.value)
msg += "]" msg += "]"
@ -726,9 +734,9 @@ class Message(object):
msg += "MID: " + str(self._mid) + "\n" msg += "MID: " + str(self._mid) + "\n"
if self._code is None: if self._code is None:
self._code = 0 self._code = 0
token = binascii.hexlify(self._token).decode("utf-8") if self._token is not None else str(None)
msg += "Code: " + str(defines.Codes.LIST[self._code].name) + "\n" msg += "Code: " + str(defines.Codes.LIST[self._code].name) + "\n"
msg += "Token: " + str(self._token) + "\n" msg += "Token: " + token + "\n"
for opt in self._options: for opt in self._options:
msg += str(opt) msg += str(opt)
msg += "Payload: " + "\n" msg += "Payload: " + "\n"

View file

@ -51,10 +51,7 @@ class Serializer(object):
message.type = message_type message.type = message_type
message.mid = mid message.mid = mid
if token_length > 0: if token_length > 0:
fmt = "%ss" % token_length message.token = datagram[pos:pos+token_length]
s = struct.Struct(fmt)
token_value = s.unpack_from(datagram[pos:])[0]
message.token = token_value.decode("utf-8")
else: else:
message.token = None message.token = None
@ -144,7 +141,7 @@ class Serializer(object):
""" """
fmt = "!BBH" fmt = "!BBH"
if message.token is None or message.token == "": if message.token is None:
tkl = 0 tkl = 0
else: else:
tkl = len(message.token) tkl = len(message.token)
@ -157,9 +154,9 @@ class Serializer(object):
if message.token is not None and tkl > 0: if message.token is not None and tkl > 0:
for b in str(message.token): for b in message.token:
fmt += "c" fmt += "B"
values.append(bytes(b, "utf-8")) values.append(b)
options = Serializer.as_sorted_list(message.options) # already sorted options = Serializer.as_sorted_list(message.options) # already sorted
lastoptionnumber = 0 lastoptionnumber = 0

View file

@ -1,9 +1,24 @@
# -*- coding: utf-8 -*-
import binascii
import random import random
import string import string
__author__ = 'Giacomo Tanganelli' __author__ = 'Giacomo Tanganelli'
def str_append_hash(*args):
""" Convert each argument to a lower case string, appended, then hash """
ret_hash = ""
for i in args:
if isinstance(i, (str, int)):
ret_hash += str(i).lower()
elif isinstance(i, bytes):
ret_hash += binascii.hexlify(i).decode("utf-8")
return hash(ret_hash)
def check_nocachekey(option): def check_nocachekey(option):
""" """
checks if an option is a NoCacheKey option or Etag checks if an option is a NoCacheKey option or Etag
@ -51,7 +66,7 @@ def is_uri_option(number):
def generate_random_token(size): def generate_random_token(size):
return ''.join(random.choice(string.ascii_letters) for _ in range(size)) return bytes([random.randint(0, 255) for _ in range(size)])
def parse_blockwise(value): def parse_blockwise(value):

View file

@ -1,3 +1,5 @@
import os
import logging.config
from queue import Queue from queue import Queue
import random import random
import socket import socket
@ -6,6 +8,7 @@ import unittest
from coapclient import HelperClient from coapclient import HelperClient
from coapserver import CoAPServer from coapserver import CoAPServer
from coapthon import defines from coapthon import defines
from coapthon.utils import create_logging
from coapthon.messages.message import Message from coapthon.messages.message import Message
from coapthon.messages.option import Option from coapthon.messages.option import Option
from coapthon.messages.request import Request from coapthon.messages.request import Request
@ -57,6 +60,10 @@ PAYLOAD = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam no
"erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd " \ "erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd " \
"gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." "gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
if not os.path.isfile("logging.conf"):
create_logging()
logging.config.fileConfig("logging.conf", disable_existing_loggers=False)
class Tests(unittest.TestCase): class Tests(unittest.TestCase):
@ -1397,7 +1404,7 @@ class Tests(unittest.TestCase):
expected.type = defines.Types["ACK"] expected.type = defines.Types["ACK"]
expected._mid = self.current_mid expected._mid = self.current_mid
expected.code = defines.Codes.NOT_FOUND.number expected.code = defines.Codes.NOT_FOUND.number
expected.token = "100" expected.token = 100
expected.payload = None expected.payload = None
exchange1 = (req, expected) exchange1 = (req, expected)