Merge branch 'commands' into 'master'
Commands See merge request ynerant/squinnondation!8
This commit is contained in:
commit
25e502ab45
|
@ -36,9 +36,9 @@ class TLV:
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Indicates what to do when this TLV is received from a given hazel.
|
Indicates what to do when this TLV is received from a given peer.
|
||||||
It is ensured that the data is valid.
|
It is ensured that the data is valid.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -72,14 +72,14 @@ class Pad1TLV(TLV):
|
||||||
"""
|
"""
|
||||||
return self.type.to_bytes(1, sys.byteorder)
|
return self.type.to_bytes(1, sys.byteorder)
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
if not sender.active or not sender.symmetric or not sender.id:
|
if not sender.active or not sender.symmetric or not sender.id:
|
||||||
# It doesn't say hello, we don't listen to it
|
# It doesn't say hello, we don't listen to it
|
||||||
squirrel.send_packet(sender, Packet.construct(WarningTLV.construct(
|
user.send_packet(sender, Packet.construct(WarningTLV.construct(
|
||||||
"You are not my neighbour, I don't listen to your Pad1TLV. Please say me Hello before.")))
|
"You are not my neighbour, I don't listen to your Pad1TLV. Please say me Hello before.")))
|
||||||
return
|
return
|
||||||
|
|
||||||
squirrel.add_system_message("I received a Pad1TLV, how disapointing.")
|
user.add_system_message("I received a Pad1TLV, how disapointing.")
|
||||||
|
|
||||||
def __len__(self) -> int:
|
def __len__(self) -> int:
|
||||||
"""
|
"""
|
||||||
|
@ -122,14 +122,14 @@ class PadNTLV(TLV):
|
||||||
return self.type.to_bytes(1, sys.byteorder) + self.length.to_bytes(1, sys.byteorder) \
|
return self.type.to_bytes(1, sys.byteorder) + self.length.to_bytes(1, sys.byteorder) \
|
||||||
+ self.mbz[:self.length]
|
+ self.mbz[:self.length]
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
if not sender.active or not sender.symmetric or not sender.id:
|
if not sender.active or not sender.symmetric or not sender.id:
|
||||||
# It doesn't say hello, we don't listen to it
|
# It doesn't say hello, we don't listen to it
|
||||||
squirrel.send_packet(sender, Packet.construct(WarningTLV.construct(
|
user.send_packet(sender, Packet.construct(WarningTLV.construct(
|
||||||
"You are not my neighbour, I don't listen to your PadNTLV. Please say me Hello before.")))
|
"You are not my neighbour, I don't listen to your PadNTLV. Please say me Hello before.")))
|
||||||
return
|
return
|
||||||
|
|
||||||
squirrel.add_system_message(f"I received {self.length} zeros.")
|
user.add_system_message(f"I received {self.length} zeros.")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def construct(length: int) -> "PadNTLV":
|
def construct(length: int) -> "PadNTLV":
|
||||||
|
@ -166,45 +166,48 @@ class HelloTLV(TLV):
|
||||||
data += self.dest_id.to_bytes(8, sys.byteorder)
|
data += self.dest_id.to_bytes(8, sys.byteorder)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
time_h = time.time()
|
time_h = time.time()
|
||||||
|
|
||||||
if sender.id > 0 and sender.id != self.source_id:
|
if sender.id > 0 and sender.id != self.source_id:
|
||||||
squirrel.send_packet(sender, Packet.construct(WarningTLV.construct(
|
user.send_packet(sender, Packet.construct(WarningTLV.construct(
|
||||||
f"You were known as the ID {sender.id}, but you declared that you have the ID {self.source_id}.")))
|
f"You were known as the ID {sender.id}, but you declared that you have the ID {self.source_id}.")))
|
||||||
squirrel.add_system_message(f"A client known as the id {sender.id} declared that it uses "
|
user.add_system_message(f"A client known as the id {sender.id} declared that it uses "
|
||||||
f"the id {self.source_id}.")
|
f"the id {self.source_id}.")
|
||||||
sender.id = self.source_id
|
sender.id = self.source_id
|
||||||
|
|
||||||
|
if self.source_id == user.id:
|
||||||
|
sender.marked_as_banned = True
|
||||||
|
|
||||||
if not sender.active:
|
if not sender.active:
|
||||||
sender.id = self.source_id # The sender we are given misses an id
|
sender.id = self.source_id # The sender we are given misses an id
|
||||||
time_hl = time.time()
|
time_hl = time.time()
|
||||||
else:
|
else:
|
||||||
time_hl = sender.last_long_hello_time
|
time_hl = sender.last_long_hello_time
|
||||||
if self.is_long and self.dest_id == squirrel.id:
|
if self.is_long and self.dest_id == user.id:
|
||||||
time_hl = time.time()
|
time_hl = time.time()
|
||||||
|
|
||||||
# Add entry to/actualize the active hazelnuts dictionnary
|
# Add entry to/actualize the active peers dictionnary
|
||||||
sender.last_hello_time = time_h
|
sender.last_hello_time = time_h
|
||||||
sender.last_long_hello_time = time_hl
|
sender.last_long_hello_time = time_hl
|
||||||
sender.symmetric = True
|
sender.symmetric = True
|
||||||
sender.active = True
|
sender.active = True
|
||||||
squirrel.update_hazelnut_table(sender)
|
user.update_peer_table(sender)
|
||||||
squirrel.nbNS += 1
|
user.nbNS += 1
|
||||||
squirrel.add_system_message(f"{self.source_id} sent me a Hello " + ("long" if self.is_long else "short"))
|
user.add_system_message(f"{self.source_id} sent me a Hello " + ("long" if self.is_long else "short"))
|
||||||
|
|
||||||
if not self.is_long:
|
if not self.is_long:
|
||||||
squirrel.send_packet(sender, Packet.construct(HelloTLV.construct(16, squirrel, sender)))
|
user.send_packet(sender, Packet.construct(HelloTLV.construct(16, user, sender)))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_long(self) -> bool:
|
def is_long(self) -> bool:
|
||||||
return self.length == 16
|
return self.length == 16
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def construct(length: int, squirrel: Any, destination: Any = None) -> "HelloTLV":
|
def construct(length: int, user: Any, destination: Any = None) -> "HelloTLV":
|
||||||
tlv = HelloTLV()
|
tlv = HelloTLV()
|
||||||
tlv.type = 2
|
tlv.type = 2
|
||||||
tlv.source_id = squirrel.id if squirrel else 0
|
tlv.source_id = user.id if user else 0
|
||||||
if (destination is None) or destination.id == -1 or length == 8:
|
if (destination is None) or destination.id == -1 or length == 8:
|
||||||
tlv.length = 8
|
tlv.length = 8
|
||||||
tlv.dest_id = None # if the destination id is not known, or
|
tlv.dest_id = None # if the destination id is not known, or
|
||||||
|
@ -238,28 +241,28 @@ class NeighbourTLV(TLV):
|
||||||
self.ip_address.packed + \
|
self.ip_address.packed + \
|
||||||
self.port.to_bytes(2, sys.byteorder)
|
self.port.to_bytes(2, sys.byteorder)
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
if not sender.active or not sender.symmetric or not sender.id:
|
if not sender.active or not sender.symmetric or not sender.id:
|
||||||
# It doesn't say hello, we don't listen to it
|
# It doesn't say hello, we don't listen to it
|
||||||
squirrel.send_packet(sender, Packet.construct(WarningTLV.construct(
|
user.send_packet(sender, Packet.construct(WarningTLV.construct(
|
||||||
"You are not my neighbour, I don't listen to your NeighbourTLV. Please say me Hello before.")))
|
"You are not my neighbour, I don't listen to your NeighbourTLV. Please say me Hello before.")))
|
||||||
return
|
return
|
||||||
|
|
||||||
if (self.ip_address, self.port) in squirrel.addresses:
|
if (self.ip_address, self.port) in user.addresses:
|
||||||
# This case should never happen (and in our protocol it is not possible),
|
# This case should never happen (and in our protocol it is not possible),
|
||||||
# but we include this test as a security measure.
|
# but we include this test as a security measure.
|
||||||
return
|
return
|
||||||
if not (str(self.ip_address), self.port) in squirrel.hazelnuts:
|
if not (str(self.ip_address), self.port) in user.neighbours:
|
||||||
hazelnut = squirrel.new_hazel(str(self.ip_address), self.port)
|
peer = user.new_peer(str(self.ip_address), self.port)
|
||||||
hazelnut.potential = True
|
peer.potential = True
|
||||||
squirrel.update_hazelnut_table(hazelnut)
|
user.update_peer_table(peer)
|
||||||
# squirrel.add_system_message(f"New potential friend {self.ip_address}:{self.port}!")
|
# user.add_system_message(f"New potential friend {self.ip_address}:{self.port}!")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def construct(address: str, port: int) -> "NeighbourTLV":
|
def construct(address: str, port: int) -> "NeighbourTLV":
|
||||||
tlv = NeighbourTLV()
|
tlv = NeighbourTLV()
|
||||||
tlv.type = 3
|
tlv.type = 3
|
||||||
tlv.length = 18 # A priori...
|
tlv.length = 18
|
||||||
tlv.ip_address = IPv6Address(address)
|
tlv.ip_address = IPv6Address(address)
|
||||||
tlv.port = port
|
tlv.port = port
|
||||||
return tlv
|
return tlv
|
||||||
|
@ -291,53 +294,53 @@ class DataTLV(TLV):
|
||||||
socket.htonl(self.nonce).to_bytes(4, sys.byteorder) + \
|
socket.htonl(self.nonce).to_bytes(4, sys.byteorder) + \
|
||||||
self.data
|
self.data
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
"""
|
"""
|
||||||
A message has been sent. We log it.
|
A message has been sent. We log it.
|
||||||
"""
|
"""
|
||||||
if not sender.active or not sender.symmetric or not sender.id:
|
if not sender.active or not sender.symmetric or not sender.id:
|
||||||
# It doesn't say hello, we don't listen to it
|
# It doesn't say hello, we don't listen to it
|
||||||
squirrel.send_packet(sender, Packet.construct(WarningTLV.construct(
|
user.send_packet(sender, Packet.construct(WarningTLV.construct(
|
||||||
"You are not my neighbour, I don't listen to your DataTLV. Please say me Hello before.")))
|
"You are not my neighbour, I don't listen to your DataTLV. Please say me Hello before.")))
|
||||||
return
|
return
|
||||||
|
|
||||||
msg = self.data.decode('UTF-8')
|
msg = self.data.decode('UTF-8')
|
||||||
|
|
||||||
# Acknowledge the packet
|
# Acknowledge the packet
|
||||||
squirrel.send_packet(sender, Packet.construct(AckTLV.construct(self.sender_id, self.nonce)))
|
user.send_packet(sender, Packet.construct(AckTLV.construct(self.sender_id, self.nonce)))
|
||||||
|
|
||||||
if not squirrel.receive_message_from(self, msg, self.sender_id, self.nonce, sender):
|
if not user.receive_message_from(self, msg, self.sender_id, self.nonce, sender):
|
||||||
# The message was already received, do not print it on screen
|
# The message was already received, do not print it on screen
|
||||||
squirrel.add_system_message(f"I was inundated a message which I already knew {self.sender_id, self.nonce}")
|
user.add_system_message(f"I was inundated a message which I already knew {self.sender_id, self.nonce}")
|
||||||
return
|
return
|
||||||
|
|
||||||
nickname_match = re.match("(.*): (.*)", msg)
|
nickname_match = re.match("(.*): (.*)", msg)
|
||||||
if nickname_match is None:
|
if nickname_match is None:
|
||||||
squirrel.send_packet(sender, Packet.construct(WarningTLV.construct(
|
user.send_packet(sender, Packet.construct(WarningTLV.construct(
|
||||||
"Unable to retrieve your username. Please use the syntax 'nickname: message'")))
|
"Unable to retrieve your username. Please use the syntax 'nickname: message'")))
|
||||||
else:
|
else:
|
||||||
nickname = nickname_match.group(1)
|
nickname = nickname_match.group(1)
|
||||||
author = squirrel.find_hazelnut_by_id(self.sender_id)
|
author = user.find_peer_by_id(self.sender_id)
|
||||||
if author:
|
if author:
|
||||||
if author.nickname is None:
|
if author.nickname is None:
|
||||||
author.nickname = nickname
|
author.nickname = nickname
|
||||||
elif author.nickname != nickname:
|
elif author.nickname != nickname:
|
||||||
squirrel.send_packet(author, Packet.construct(WarningTLV.construct(
|
user.send_packet(author, Packet.construct(WarningTLV.construct(
|
||||||
"It seems that you used two different nicknames. "
|
"It seems that you used two different nicknames. "
|
||||||
f"Known nickname: {author.nickname}, found: {nickname}")))
|
f"Known nickname: {author.nickname}, found: {nickname}")))
|
||||||
author.nickname = nickname
|
author.nickname = nickname
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def construct(message: str, squirrel: Any) -> "DataTLV":
|
def construct(message: str, user: Any) -> "DataTLV":
|
||||||
tlv = DataTLV()
|
tlv = DataTLV()
|
||||||
tlv.type = 4
|
tlv.type = 4
|
||||||
tlv.sender_id = squirrel.id if squirrel else 0
|
tlv.sender_id = user.id if user else 0
|
||||||
tlv.nonce = squirrel.incr_nonce if squirrel else 0
|
tlv.nonce = user.incr_nonce if user else 0
|
||||||
tlv.data = message.encode("UTF-8")
|
tlv.data = message.encode("UTF-8")
|
||||||
tlv.length = 12 + len(tlv.data)
|
tlv.length = 12 + len(tlv.data)
|
||||||
|
|
||||||
if squirrel:
|
if user:
|
||||||
squirrel.incr_nonce += 1
|
user.incr_nonce += 1
|
||||||
|
|
||||||
return tlv
|
return tlv
|
||||||
|
|
||||||
|
@ -360,18 +363,18 @@ class AckTLV(TLV):
|
||||||
self.sender_id.to_bytes(8, sys.byteorder) + \
|
self.sender_id.to_bytes(8, sys.byteorder) + \
|
||||||
socket.htonl(self.nonce).to_bytes(4, sys.byteorder)
|
socket.htonl(self.nonce).to_bytes(4, sys.byteorder)
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
"""
|
"""
|
||||||
When an AckTLV is received, we know that we do not have to inundate that neighbour anymore.
|
When an AckTLV is received, we know that we do not have to inundate that neighbour anymore.
|
||||||
"""
|
"""
|
||||||
if not sender.active or not sender.symmetric or not sender.id:
|
if not sender.active or not sender.symmetric or not sender.id:
|
||||||
# It doesn't say hello, we don't listen to it
|
# It doesn't say hello, we don't listen to it
|
||||||
squirrel.send_packet(sender, Packet.construct(WarningTLV.construct(
|
user.send_packet(sender, Packet.construct(WarningTLV.construct(
|
||||||
"You are not my neighbour, I don't listen to your AckTLV. Please say me Hello before.")))
|
"You are not my neighbour, I don't listen to your AckTLV. Please say me Hello before.")))
|
||||||
return
|
return
|
||||||
|
|
||||||
squirrel.add_system_message(f"I received an AckTLV from {sender}")
|
user.add_system_message(f"I received an AckTLV from {sender}")
|
||||||
squirrel.remove_from_inundation(sender, self.sender_id, self.nonce)
|
user.remove_from_inundation(sender, self.sender_id, self.nonce)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def construct(sender_id: int, nonce: int) -> "AckTLV":
|
def construct(sender_id: int, nonce: int) -> "AckTLV":
|
||||||
|
@ -408,17 +411,17 @@ class GoAwayTLV(TLV):
|
||||||
self.code.value.to_bytes(1, sys.byteorder) + \
|
self.code.value.to_bytes(1, sys.byteorder) + \
|
||||||
self.message.encode("UTF-8")[:self.length - 1]
|
self.message.encode("UTF-8")[:self.length - 1]
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
if not sender.active or not sender.symmetric or not sender.id:
|
if not sender.active or not sender.symmetric or not sender.id:
|
||||||
# It doesn't say hello, we don't listen to it
|
# It doesn't say hello, we don't listen to it
|
||||||
squirrel.send_packet(sender, Packet.construct(WarningTLV.construct(
|
user.send_packet(sender, Packet.construct(WarningTLV.construct(
|
||||||
"You are not my neighbour, I don't listen to your GoAwayTLV. Please say me Hello before.")))
|
"You are not my neighbour, I don't listen to your GoAwayTLV. Please say me Hello before.")))
|
||||||
return
|
return
|
||||||
|
|
||||||
if sender.active:
|
if sender.active:
|
||||||
sender.active = False
|
sender.active = False
|
||||||
squirrel.update_hazelnut_table(sender)
|
user.update_peer_table(sender)
|
||||||
squirrel.add_system_message("Some told me that he went away : " + self.message)
|
user.add_system_message("Some told me that he went away : " + self.message)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def construct(ga_type: GoAwayType, message: str) -> "GoAwayTLV":
|
def construct(ga_type: GoAwayType, message: str) -> "GoAwayTLV":
|
||||||
|
@ -445,9 +448,9 @@ class WarningTLV(TLV):
|
||||||
self.length.to_bytes(1, sys.byteorder) + \
|
self.length.to_bytes(1, sys.byteorder) + \
|
||||||
self.message.encode("UTF-8")[:self.length]
|
self.message.encode("UTF-8")[:self.length]
|
||||||
|
|
||||||
def handle(self, squirrel: Any, sender: Any) -> None:
|
def handle(self, user: Any, sender: Any) -> None:
|
||||||
squirrel.add_message(f"warning: *A client warned you: {self.message}*"
|
user.add_message(f"warning: *A client warned you: {self.message}*"
|
||||||
if not squirrel.squinnondation.no_markdown else
|
if not user.squinnondation.no_markdown else
|
||||||
f"warning: A client warned you: {self.message}")
|
f"warning: A client warned you: {self.message}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@ import curses
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from .hazel import Hazelnut, Squirrel
|
from .peers import Peer, User
|
||||||
from .messages import Packet, HelloTLV
|
from .messages import Packet, HelloTLV
|
||||||
from .term_manager import TermManager
|
from .term_manager import TermManager
|
||||||
|
|
||||||
|
@ -59,28 +59,28 @@ class Squinnondation:
|
||||||
nickname = screen.getstr(225).decode("UTF-8") # Limit nickname length to be included in a DataTLV
|
nickname = screen.getstr(225).decode("UTF-8") # Limit nickname length to be included in a DataTLV
|
||||||
curses.noecho()
|
curses.noecho()
|
||||||
|
|
||||||
squirrel = Squirrel(instance, nickname)
|
user = User(instance, nickname)
|
||||||
|
|
||||||
if not squirrel.squinnondation.no_emoji:
|
if not user.squinnondation.no_emoji:
|
||||||
# Check that the emoji lib is installed
|
# Check that the emoji lib is installed
|
||||||
try:
|
try:
|
||||||
import emoji
|
import emoji
|
||||||
_ = emoji
|
_ = emoji
|
||||||
except ImportError:
|
except ImportError:
|
||||||
squirrel.squinnondation.no_emoji = True
|
user.squinnondation.no_emoji = True
|
||||||
squirrel.add_system_message("Warning: the emoji lib is not installed. The support will be disabled."
|
user.add_system_message("Warning: the emoji lib is not installed. The support will be disabled."
|
||||||
"To use them, please consider to install the emoji package.")
|
"To use them, please consider to install the emoji package.")
|
||||||
|
|
||||||
squirrel.refresh_history()
|
user.refresh_history()
|
||||||
squirrel.refresh_input()
|
user.refresh_input()
|
||||||
if not instance.no_emoji:
|
if not instance.no_emoji:
|
||||||
squirrel.refresh_emoji_pad()
|
user.refresh_emoji_pad()
|
||||||
|
|
||||||
if instance.args.client_address and instance.args.client_port:
|
if instance.args.client_address and instance.args.client_port:
|
||||||
hazelnut = Hazelnut(address=instance.args.client_address, port=instance.args.client_port)
|
peer = Peer(address=instance.args.client_address, port=instance.args.client_port)
|
||||||
htlv = HelloTLV().construct(8, squirrel)
|
htlv = HelloTLV().construct(8, user)
|
||||||
pkt = Packet().construct(htlv)
|
pkt = Packet().construct(htlv)
|
||||||
squirrel.send_packet(hazelnut, pkt)
|
user.send_packet(peer, pkt)
|
||||||
|
|
||||||
squirrel.start_threads()
|
user.start_threads()
|
||||||
squirrel.wait_for_key()
|
user.wait_for_key()
|
||||||
|
|
Loading…
Reference in New Issue