update xmpp sasl

This commit is contained in:
AleaJactaEst 2023-12-19 01:18:26 +01:00
parent 72ad3bf8e5
commit 7d3f028768

View file

@ -5,6 +5,7 @@ extends Node
# #
# https://xmpp.org/extensions/xep-0178.html # https://xmpp.org/extensions/xep-0178.html
# https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml # https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml
# https://datatracker.ietf.org/doc/html/rfc6120#section-6.5
# Boucle # Boucle
@ -40,11 +41,12 @@ enum XMPPState {
MISSING_TLS, # Missing feature TLS -> wait 30min and retry MISSING_TLS, # Missing feature TLS -> wait 30min and retry
STARTED_TLS, # TLS connection is done STARTED_TLS, # TLS connection is done
SELECT_MECHANISM_AUTHENTICATE, SELECT_MECHANISM_AUTHENTICATE,
AUTHENTICATE_STEP_PLAIN, # Select mechanism authenticate PLAIN AUTHENTICATE_STEP_PLAIN, # Select mechanism authenticate PLAIN
AUTHENTICATE_STEP_1, # Launch authenticate AUTHENTICATE_STEP_DIGEST_MD5,
AUTHENTICATE_STEP_2, # Launch authenticate # AUTHENTICATE_STEP_1, # Launch authenticate
AUTHENTICATE_STEP_3, # Launch authenticate # AUTHENTICATE_STEP_2, # Launch authenticate
AUTHENTICATE_CHECK_RESULT, # Last time check result # AUTHENTICATE_STEP_3, # Launch authenticate
# AUTHENTICATE_CHECK_RESULT, # Last time check result
AUTHENTICATE_FAILURE, AUTHENTICATE_FAILURE,
AUTHENTICATE_SUCCESS, AUTHENTICATE_SUCCESS,
AUTHENTICATED, # We finished authenticate AUTHENTICATED, # We finished authenticate
@ -141,22 +143,26 @@ var status:StreamState = StreamState.END
var xmpp_state = XMPPState.NONE var xmpp_state = XMPPState.NONE
var authentication_methods = [] var authentication_methods = []
var selected_mechanism_authenticate:String = "" var selected_mechanism_authenticate:String = ""
var order_preference_mechanism_authenticate: Array = ['PLAIN'] #var order_preference_mechanism_authenticate: Array = ['PLAIN']
var order_preference_mechanism_authenticate: Array = ['DIGEST-MD5']
var banned_mechanism_authenticate:Array = [] var banned_mechanism_authenticate:Array = []
#DIGEST-MD5, PLAIN, SCRAM-SHA-512-PLUS, SCRAM-SHA-512, SCRAM-SHA-256-PLUS, SCRAM-SHA-256, SCRAM-SHA-1-PLUS, SCRAM-SHA-1, X-OAUTH2
var auhtentification_step:int = 0
var auhtentification_challenge:Array = []
func reinit_stream(): #func reinit_stream():
if ssl_peer != null: # if ssl_peer != null:
ssl_peer.disconnect_from_stream() # ssl_peer.disconnect_from_stream()
else: # else:
ssl_peer = StreamPeerTLS.new() # ssl_peer = StreamPeerTLS.new()
if tcp_peer != null: # if tcp_peer != null:
tcp_peer.disconnect_from_host() # tcp_peer.disconnect_from_host()
else: # else:
tcp_peer = StreamPeerTCP.new() # tcp_peer = StreamPeerTCP.new()
tgt_peer = tcp_peer # tgt_peer = tcp_peer
start_stream() ## start_stream()
stream_status = self.StreamState.START # stream_status = self.StreamState.START
func _init() -> void: func _init() -> void:
@ -167,7 +173,7 @@ func _init() -> void:
func _process(delta) -> void: func _process(delta) -> void:
print(server_xmpp_name, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status, " / xmpp_state:", XMPPState.keys()[xmpp_state]) #print(server_xmpp_name, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status, " / xmpp_state:", XMPPState.keys()[xmpp_state])
if xmppclient == false: if xmppclient == false:
return return
# Wait MAX_WAIT_MISSING_TLS (s) if server can't negociate with TLS # Wait MAX_WAIT_MISSING_TLS (s) if server can't negociate with TLS
@ -327,7 +333,13 @@ func _process(delta) -> void:
return return
elif selected_mechanism_authenticate == "PLAIN": elif selected_mechanism_authenticate == "PLAIN":
xmpp_state = XMPPState.AUTHENTICATE_STEP_PLAIN xmpp_state = XMPPState.AUTHENTICATE_STEP_PLAIN
auhtentification_step = 0
elif selected_mechanism_authenticate == "DIGEST-MD5":
xmpp_state = XMPPState.AUTHENTICATE_STEP_DIGEST_MD5
auhtentification_step = 0
auhtentification_challenge = []
if xmpp_state == XMPPState.AUTHENTICATE_STEP_PLAIN: if xmpp_state == XMPPState.AUTHENTICATE_STEP_PLAIN:
# https://datatracker.ietf.org/doc/html/rfc4616
if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED: if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED:
xmpp_state = XMPPState.NONE xmpp_state = XMPPState.NONE
count_connecting_time = 0 count_connecting_time = 0
@ -365,10 +377,112 @@ func _process(delta) -> void:
count_connecting_time = 0 count_connecting_time = 0
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
banned_mechanism_authenticate.append(selected_mechanism_authenticate) banned_mechanism_authenticate.append(selected_mechanism_authenticate)
if xmpp_state == XMPPState.AUTHENTICATE_STEP_DIGEST_MD5:
# https://datatracker.ietf.org/doc/html/rfc2831
if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED:
xmpp_state = XMPPState.NONE
count_connecting_time = 0
return
if count_connecting_time >= MAX_WAIT_CONNECTING:
count_connecting_time = 0
negotiate_ssl_authenticate_digest_md5()
else:
count_connecting_time += delta
if (ssl_peer.has_method("poll")):
ssl_peer.poll()
if ssl_peer.get_available_bytes()>0:
var response = ssl_peer.get_string(ssl_peer.get_available_bytes())
send_msg_debug.emit("Stream: response: " + response)
response = remove_stream_header(response)
if response.begins_with("<challenge"):
var data:String = get_xml_data(response, ["challenge"])
#var xmlns:String = get_xml_attribute(response, ["challenge"], "xmlns")
print(auhtentification_step, " / ", data)
auhtentification_challenge.append(data)
if ! negotiate_ssl_authenticate_digest_md5():
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
banned_mechanism_authenticate.append(selected_mechanism_authenticate)
return
else:
var res:SASLReturn = get_result_authenticate(response)
if res == SASLReturn.SUCCESS:
count_connecting_time = 0
xmpp_state = XMPPState.AUTHENTICATED
elif res == SASLReturn.NOT_AUTHORIZED:
count_connecting_time = 0
xmpp_state = XMPPState.NOT_AUTHORIZED
elif res == SASLReturn.ACCOUNT_DISABLED:
count_connecting_time = 0
xmpp_state = XMPPState.ACCOUNT_DISABLED
elif res == SASLReturn.NOT_AUTHORIZED:
count_connecting_time = 0
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
banned_mechanism_authenticate.append(selected_mechanism_authenticate)
elif res == SASLReturn.INVALID_MECHANISM:
count_connecting_time = 0
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
banned_mechanism_authenticate.append(selected_mechanism_authenticate)
else:
count_connecting_time = 0
xmpp_state = XMPPState.SELECT_MECHANISM_AUTHENTICATE
banned_mechanism_authenticate.append(selected_mechanism_authenticate)
func get_xml_data(response:String, nodes:Array) -> String:
var node_name:String = ""
var data:String = ""
var parser:XMLParser = XMLParser.new()
var cur:Array = []
parser.open_buffer(response.to_utf8_buffer())
while (parser.read() == OK):
if (parser.get_node_type()== XMLParser.NODE_ELEMENT):
node_name = parser.get_node_name()
cur.append(node_name)
print("node_name:", node_name)
var attributes_dict = {}
for idx in range(parser.get_attribute_count()):
attributes_dict[parser.get_attribute_name(idx)] = parser.get_attribute_value(idx)
print("The ", node_name, " element has the following attributes: ", attributes_dict)
elif (parser.get_node_type()== XMLParser.NODE_TEXT):
var correctpath:bool = true
print(nodes.size() , " != ", cur.size())
if nodes.size() != cur.size():
continue
for i in range(0, nodes.size()):
print(cur[i] , " != ", nodes[i])
if cur[i] != nodes[i]:
correctpath = false
break
if correctpath:
data = parser.get_node_data()
print("data:", data)
return data
elif (parser.get_node_type()== XMLParser.NODE_ELEMENT_END):
cur.pop_back()
return ""
func get_xml_attribute(response:String, nodes:Array, attribute:String) -> String:
var node_name:String = ""
var data:String = ""
var parser:XMLParser = XMLParser.new()
var cur:Array = []
parser.open_buffer(response.to_utf8_buffer())
while (parser.read() == OK):
if (parser.get_node_type()== XMLParser.NODE_ELEMENT):
node_name = parser.get_node_name()
cur.append(node_name)
print("node_name:", node_name)
var attributes_dict = {}
for idx in range(parser.get_attribute_count()):
if parser.get_attribute_name(idx) == attribute:
return parser.get_attribute_value(idx)
elif (parser.get_node_type()== XMLParser.NODE_ELEMENT_END):
cur.pop_back()
return ""
func get_result_authenticate(response:String) -> SASLReturn: func get_result_authenticate(response:String) -> SASLReturn:
response = remove_stream_header(response)
if response.begins_with("<success"): if response.begins_with("<success"):
count_connecting_time = 0 count_connecting_time = 0
return SASLReturn.SUCCESS return SASLReturn.SUCCESS
@ -493,13 +607,18 @@ func select_mechanism_authenticate(authentication_methods : Array) -> void:
func negotiate_ssl_authenticate_plain() -> void: func negotiate_ssl_authenticate_plain() -> void:
send_msg_debug.emit("Stream: sending request for plain") send_msg_debug.emit("Stream: sending request for PLAIN")
var msg:PackedByteArray = PackedByteArray() var msg:PackedByteArray = PackedByteArray()
# [authzid]
#msg += server_xmpp_name.to_ascii_buffer()
# UTF8NUL
msg.push_back(0) msg.push_back(0)
# authcid
var t = account_name.split("@")[0] var t = account_name.split("@")[0]
msg += t.to_ascii_buffer() msg += t.to_ascii_buffer()
#msg += conv_string_to_PackedByteArray(account_name.split("@")[0]) # UTF8NUL
msg.push_back(0) msg.push_back(0)
# passwd
msg += password.to_ascii_buffer() msg += password.to_ascii_buffer()
var auth_account:String = Marshalls.raw_to_base64(msg) var auth_account:String = Marshalls.raw_to_base64(msg)
var request_sasl:String = "<auth" + \ var request_sasl:String = "<auth" + \
@ -509,6 +628,56 @@ func negotiate_ssl_authenticate_plain() -> void:
send_ssl_string(request_sasl) send_ssl_string(request_sasl)
func negotiate_ssl_authenticate_digest_md5() -> bool:
send_msg_debug.emit("Stream: sending request for DIGEST-MD5 (step:%d)" % auhtentification_step)
if auhtentification_step == 0:
var request_sasl:String = "<auth" + \
" xmlns='urn:ietf:params:xml:ns:xmpp-sasl'" + \
" mechanism='DIGEST-MD5'" + \
" >" + "</auth>"
send_ssl_string(request_sasl)
auhtentification_step += 1
return true
elif auhtentification_step == 1:
var tmp:String = Marshalls.base64_to_utf8(auhtentification_challenge[0])
var tab:Array = tmp.split(",")
var realm:String = ""
var nonce:String = ""
var qop:String = ""
var charset:String = ""
var algorithm:String = ""
print(str(tab))
for item in tab:
var tab2:Array = item.split("=")
var key:String = tab2[0]
var value:String = tab2[1]
if key == "realm":
realm = value.trim_prefix('"').trim_suffix('"')
if key == "nonce":
nonce = value.trim_prefix('"').trim_suffix('"')
elif key == "qop":
qop = value.trim_prefix('"').trim_suffix('"')
elif key == "charset":
charset = value
elif key == "algorithm":
algorithm = value
print(key," = ", value)
print(tmp, " ", qop, " ", charset, " ",nonce)
if qop != "auth":
send_msg_error.emit("Stream: Authenticate digest-md5, qop unknonw (%s)" % qop)
return false
if charset != "utf-8":
send_msg_error.emit("Stream: Authenticate digest-md5, charset unknonw (%s)" % charset)
return false
if algorithm != "md5-sess":
send_msg_error.emit("Stream: Authenticate digest-md5, algorithm unknonw (%s)" % algorithm)
return false
print(tmp)
auhtentification_step += 1
return true
return false
func negotiate_ssl_sasl(authentication_methods : Array) -> bool: func negotiate_ssl_sasl(authentication_methods : Array) -> bool:
if ( authentication_methods.has("PLAIN")): if ( authentication_methods.has("PLAIN")):
send_msg_debug.emit("Stream: sending request for plain") send_msg_debug.emit("Stream: sending request for plain")
@ -535,53 +704,53 @@ func negotiate_ssl_sasl(authentication_methods : Array) -> bool:
# #
# #
func connect_to_server_xmpp() -> void: #func connect_to_server_xmpp() -> void:
var res = tcp_peer.connect_to_host(server_xmpp_name, port_number) # var res = tcp_peer.connect_to_host(server_xmpp_name, port_number)
if res == OK: # if res == OK:
count_connecting_time = 0 # count_connecting_time = 0
stream_status = self.StreamState.END # stream_status = self.StreamState.END
set_process(true) # set_process(true)
tgt_peer = tcp_peer # tgt_peer = tcp_peer
func _process_old(delta) -> void: #func _process_old(delta) -> void:
print(server_xmpp_name, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status) # print(server_xmpp_name, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status)
if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED: # if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED:
print("STATUS_CONNECTED:", delta) # print("STATUS_CONNECTED:", delta)
if (tgt_peer.has_method("poll")): # if (tgt_peer.has_method("poll")):
tgt_peer.poll() # tgt_peer.poll()
if tgt_peer.get_available_bytes()>0: # if tgt_peer.get_available_bytes()>0:
var response = tgt_peer.get_string(tgt_peer.get_available_bytes()) # var response = tgt_peer.get_string(tgt_peer.get_available_bytes())
send_msg_debug.emit("Stream: response: " + response) # send_msg_debug.emit("Stream: response: " + response)
if stream_status == self.StreamState.STANZA: # if stream_status == self.StreamState.STANZA:
#collect_stanza(remove_stream_header(response)) # #collect_stanza(remove_stream_header(response))
print("collect_stanza") # print("collect_stanza")
else: # else:
print("stream_process") # print("stream_process")
stream_process(remove_stream_header(response)) # stream_process(remove_stream_header(response))
# print(remove_stream_header(response)) ## print(remove_stream_header(response))
elif stream_status == self.StreamState.END: # elif stream_status == self.StreamState.END:
reinit_stream() # reinit_stream()
#start_stream() # #start_stream()
#stream_status = self.StreamState.START # #stream_status = self.StreamState.START
count_connecting_time = 0 # count_connecting_time = 0
if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTING: # if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTING:
print("STATUS_CONNECTING:", delta) # print("STATUS_CONNECTING:", delta)
count_connecting_time += delta # count_connecting_time += delta
if (tgt_peer.has_method("poll")): # if (tgt_peer.has_method("poll")):
tgt_peer.poll() # tgt_peer.poll()
if count_connecting_time > 60: # (1 -> 1s) if it took more than 1s to connect, error # if count_connecting_time > 60: # (1 -> 1s) if it took more than 1s to connect, error
print("**** Stream: Stuck connecting, will now disconnect") # print("**** Stream: Stuck connecting, will now disconnect")
Global.msg_error("Stream: Stuck connecting, will now disconnect", []) # Global.msg_error("Stream: Stuck connecting, will now disconnect", [])
send_msg_debug.emit("Stream: Stuck connecting, will now disconnect") # send_msg_debug.emit("Stream: Stuck connecting, will now disconnect")
tgt_peer.disconnect_from_host() #interrupts connection to nothing # tgt_peer.disconnect_from_host() #interrupts connection to nothing
set_process(false) # stop listening for packets # set_process(false) # stop listening for packets
try_connect = 20 # try_connect = 20
stream_status = self.StreamState.END # stream_status = self.StreamState.END
reinit_stream() # reinit_stream()
if tgt_peer.get_status() == StreamPeerTCP.STATUS_NONE and xmppclient: # if tgt_peer.get_status() == StreamPeerTCP.STATUS_NONE and xmppclient:
print("connect_to_server:", xmppclient) # print("connect_to_server:", xmppclient)
connect_to_server() # connect_to_server()
xmppclient = false # xmppclient = false
func connect_to_server(): func connect_to_server():
@ -630,24 +799,24 @@ func conv_string_to_PackedByteArray(message:String) -> PackedByteArray:
# tgt_peer.put_data(message) # tgt_peer.put_data(message)
func start_stream() -> void: #func start_stream() -> void:
""" Send the stream header. # """ Send the stream header.
Needs to be done several times over stream negotiation. # Needs to be done several times over stream negotiation.
""" # """
var server_name = account_name.split("@")[-1] # var server_name = account_name.split("@")[-1]
var message:String = "<?xml version='1.0'?>" + \ # var message:String = "<?xml version='1.0'?>" + \
"<stream:stream" + \ # "<stream:stream" + \
" xmlns=\"jabber:client\"" + \ # " xmlns=\"jabber:client\"" + \
" version=\"1.0\"" + \ # " version=\"1.0\"" + \
" xmlns:stream=\"http://etherx.jabber.org/streams\"" + \ # " xmlns:stream=\"http://etherx.jabber.org/streams\"" + \
" from=\"" + account_name + "\" " + \ # " from=\"" + account_name + "\" " + \
" to=\"" + server_name + "\" " + \ # " to=\"" + server_name + "\" " + \
" xml:lang=\"en\"" + \ # " xml:lang=\"en\"" + \
" > " # " > "
# " from=\"" + account_name + "\" " + \ # # " from=\"" + account_name + "\" " + \
# + locale + "'" + # # + locale + "'" +
print(message) # print(message)
send_string(message) # send_string(message)
func remove_stream_header(text :String) -> String: func remove_stream_header(text :String) -> String:
var index = 0 var index = 0
@ -666,130 +835,130 @@ func remove_stream_header(text :String) -> String:
return text return text
func stream_process(response :String = "") -> void: #func stream_process(response :String = "") -> void:
""" Try to authenticate using SASL. We can currently only do plain. # """ Try to authenticate using SASL. We can currently only do plain.
For SCRAM based methods, we need HMAC at the very least. # For SCRAM based methods, we need HMAC at the very least.
""" # """
#
if (!response.length() == 0 and stream_status != self.StreamState.STANZA): # if (!response.length() == 0 and stream_status != self.StreamState.STANZA):
if response.begins_with("<stream:error"): # if response.begins_with("<stream:error"):
var stream_error = XMPPStreamError.new() # var stream_error = XMPPStreamError.new()
stream_error.parse_from_xml(response) # stream_error.parse_from_xml(response)
var error_name = stream_error.error_name_for_enum(stream_error.error_type) # var error_name = stream_error.error_name_for_enum(stream_error.error_type)
var error = tr('A stream error of type "%" occured, or in other words: % \n\nStream errors cannot be recovered from, the connection will be closed.'.format([error_name, stream_error.human_friendly_error_message()], "%")) # var error = tr('A stream error of type "%" occured, or in other words: % \n\nStream errors cannot be recovered from, the connection will be closed.'.format([error_name, stream_error.human_friendly_error_message()], "%"))
error.emit(error) # error.emit(error)
#
elif response.begins_with("<stream:features"): # elif response.begins_with("<stream:features"):
var stream_features = XMPPStreamFeatures.new() # var stream_features = XMPPStreamFeatures.new()
stream_features.parse_from_xml(response) # stream_features.parse_from_xml(response)
#
if stream_features.parsedDictionary.has("starttls"): # if stream_features.parsedDictionary.has("starttls"):
send_msg_debug.emit("Stream: sending request for ssl") # send_msg_debug.emit("Stream: sending request for ssl")
var request_tls = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>" # var request_tls = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
send_string(request_tls) # send_string(request_tls)
stream_status = self.StreamState.TLS # stream_status = self.StreamState.TLS
#
elif stream_features.parsedDictionary.has("mechanisms"): # elif stream_features.parsedDictionary.has("mechanisms"):
print("response:", response) # print("response:", response)
var authentication_methods = stream_features.parsedDictionary["mechanisms"] # var authentication_methods = stream_features.parsedDictionary["mechanisms"]
if (authentication_methods.size() > 0): # if (authentication_methods.size() > 0):
var tmp:String = "" # var tmp:String = ""
var sep:String = "" # var sep:String = ""
for item in authentication_methods: # for item in authentication_methods:
tmp += sep + item # tmp += sep + item
sep = ", " # sep = ", "
send_msg_debug.emit("Stream: authentication methods: " + tmp) # send_msg_debug.emit("Stream: authentication methods: " + tmp)
negotiate_sasl(authentication_methods) # negotiate_sasl(authentication_methods)
stream_status = self.StreamState.AUTHENTICATE # stream_status = self.StreamState.AUTHENTICATE
#
else: # else:
if stream_status == StreamState.TLS: # if stream_status == StreamState.TLS:
if response.begins_with("<proceed"): # if response.begins_with("<proceed"):
send_msg_debug.emit("Stream: gotten go ahead for ssl") # send_msg_debug.emit("Stream: gotten go ahead for ssl")
negotiate_tls() # negotiate_tls()
else: # else:
send_msg_error.emit(tr("Tls negotiation failed.")) # send_msg_error.emit(tr("Tls negotiation failed."))
#
elif stream_status == StreamState.AUTHENTICATE: # elif stream_status == StreamState.AUTHENTICATE:
if response.begins_with("<success"): # if response.begins_with("<success"):
stream_status = self.StreamState.STANZA # stream_status = self.StreamState.STANZA
# start_stream() ## start_stream()
return # return
else: # else:
var parser = XMLParser.new() # var parser = XMLParser.new()
# parser.open_buffer(response.to_utf8()) ## parser.open_buffer(response.to_utf8())
var failure_text = [] # var failure_text = []
while parser.read() == OK: # while parser.read() == OK:
if parser.get_node_type() == XMLParser.NODE_TEXT: # if parser.get_node_type() == XMLParser.NODE_TEXT:
failure_text.append(parser.get_node_data()) # failure_text.append(parser.get_node_data())
print(failure_text) # print(failure_text)
# failure_text = tr("Authentication failed! %".format([PoolStringArray(failure_text).join(" ")], "%")) ## failure_text = tr("Authentication failed! %".format([PoolStringArray(failure_text).join(" ")], "%"))
var msg:String = "" # var msg:String = ""
for item in failure_text: # for item in failure_text:
msg += item # msg += item
send_msg_error.emit(msg) # send_msg_error.emit(msg)
elif stream_status == self.StreamState.START: # elif stream_status == self.StreamState.START:
connect_to_server() # connect_to_server()
start_stream() # start_stream()
else: # else:
print("Mystery stream status: "+str(stream_status)) # print("Mystery stream status: "+str(stream_status))
func negotiate_tls() -> bool: #func negotiate_tls() -> bool:
#var ssl_peer = StreamPeerTLS.new() # #var ssl_peer = StreamPeerTLS.new()
# I am unsure how to validate the ssl certificate for an unknown host? # # I am unsure how to validate the ssl certificate for an unknown host?
#var ssl_succes = FAILED # #var ssl_succes = FAILED
var options:TLSOptions = TLSOptions.client_unsafe() # var options:TLSOptions = TLSOptions.client_unsafe()
print("accept_stream") # print("accept_stream")
#var ssl_succes = ssl_peer.accept_stream(tcp_peer, options) # #var ssl_succes = ssl_peer.accept_stream(tcp_peer, options)
var ssl_succes = ssl_peer.connect_to_stream(tcp_peer, "localhost", options) # var ssl_succes = ssl_peer.connect_to_stream(tcp_peer, "localhost", options)
print("resultat:", ssl_succes) # print("resultat:", ssl_succes)
if ssl_succes == OK: # if ssl_succes == OK:
send_msg_debug.emit("Stream: switched to SSL!") # send_msg_debug.emit("Stream: switched to SSL!")
print("get_status:", ssl_peer.get_status()) # print("get_status:", ssl_peer.get_status())
# Wait connection done # # Wait connection done
while ssl_peer.get_status() == StreamPeerTLS.STATUS_HANDSHAKING: # while ssl_peer.get_status() == StreamPeerTLS.STATUS_HANDSHAKING:
ssl_peer.poll() # ssl_peer.poll()
print("get_status:", ssl_peer.get_status()) # print("get_status:", ssl_peer.get_status())
tgt_peer = ssl_peer # tgt_peer = ssl_peer
start_stream() # start_stream()
print("get_status:", ssl_peer.get_status()) # print("get_status:", ssl_peer.get_status())
print("-----") # print("-----")
#stream_status == StreamState.START # #stream_status == StreamState.START
return true # return true
else: # else:
send_msg_error.emit("SSL failed, error %".format([ssl_succes], "%")) # send_msg_error.emit("SSL failed, error %".format([ssl_succes], "%"))
return false # return false
#
#
#func negotiate_sasl(authentication_methods : Array) -> void:
# if ( authentication_methods.has("PLAIN")):
# send_msg_debug.emit("Stream: sending request for plain")
# var msg:PackedByteArray = PackedByteArray()
# msg.push_back(0)
# var t = account_name.split("@")[0]
# msg += t.to_ascii_buffer()
# #msg += conv_string_to_PackedByteArray(account_name.split("@")[0])
# msg.push_back(0)
# msg += password.to_ascii_buffer()
# var auth_account:String = Marshalls.raw_to_base64(msg)
# var request_sasl:String = "<auth" + \
# " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'" + \
# " mechanism='PLAIN'" + \
# " >" + auth_account + "</auth>"
# send_string(request_sasl)
# else:
# send_msg_error.emit("Impossible to authenticate (unknown protocol)")
# end_stream()
#
func negotiate_sasl(authentication_methods : Array) -> void: #func end_stream() -> void:
if ( authentication_methods.has("PLAIN")): # """ End the stream """
send_msg_debug.emit("Stream: sending request for plain") # send_msg_debug.emit("Stream: Ending stream")
var msg:PackedByteArray = PackedByteArray() # send_string("</stream>")
msg.push_back(0) # if tcp_peer.has_method("disconnect_from_stream"):
var t = account_name.split("@")[0] # tcp_peer.disconnect_from_stream()
msg += t.to_ascii_buffer() # else:
#msg += conv_string_to_PackedByteArray(account_name.split("@")[0]) # tcp_peer.disconnect_from_host()
msg.push_back(0) # set_process(false)
msg += password.to_ascii_buffer() # stream_status = StreamState.END
var auth_account:String = Marshalls.raw_to_base64(msg)
var request_sasl:String = "<auth" + \
" xmlns='urn:ietf:params:xml:ns:xmpp-sasl'" + \
" mechanism='PLAIN'" + \
" >" + auth_account + "</auth>"
send_string(request_sasl)
else:
send_msg_error.emit("Impossible to authenticate (unknown protocol)")
end_stream()
func end_stream() -> void:
""" End the stream """
send_msg_debug.emit("Stream: Ending stream")
send_string("</stream>")
if tcp_peer.has_method("disconnect_from_stream"):
tcp_peer.disconnect_from_stream()
else:
tcp_peer.disconnect_from_host()
set_process(false)
stream_status = StreamState.END