mirror of
https://port.numenaute.org/aleajactaest/bazar_alea.git
synced 2024-11-09 08:49:03 +00:00
update xmpp sasl
This commit is contained in:
parent
72ad3bf8e5
commit
7d3f028768
1 changed files with 379 additions and 210 deletions
|
@ -5,6 +5,7 @@ extends Node
|
|||
#
|
||||
# https://xmpp.org/extensions/xep-0178.html
|
||||
# https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml
|
||||
# https://datatracker.ietf.org/doc/html/rfc6120#section-6.5
|
||||
|
||||
|
||||
# Boucle
|
||||
|
@ -41,10 +42,11 @@ enum XMPPState {
|
|||
STARTED_TLS, # TLS connection is done
|
||||
SELECT_MECHANISM_AUTHENTICATE,
|
||||
AUTHENTICATE_STEP_PLAIN, # Select mechanism authenticate PLAIN
|
||||
AUTHENTICATE_STEP_1, # Launch authenticate
|
||||
AUTHENTICATE_STEP_2, # Launch authenticate
|
||||
AUTHENTICATE_STEP_3, # Launch authenticate
|
||||
AUTHENTICATE_CHECK_RESULT, # Last time check result
|
||||
AUTHENTICATE_STEP_DIGEST_MD5,
|
||||
# AUTHENTICATE_STEP_1, # Launch authenticate
|
||||
# AUTHENTICATE_STEP_2, # Launch authenticate
|
||||
# AUTHENTICATE_STEP_3, # Launch authenticate
|
||||
# AUTHENTICATE_CHECK_RESULT, # Last time check result
|
||||
AUTHENTICATE_FAILURE,
|
||||
AUTHENTICATE_SUCCESS,
|
||||
AUTHENTICATED, # We finished authenticate
|
||||
|
@ -141,22 +143,26 @@ var status:StreamState = StreamState.END
|
|||
var xmpp_state = XMPPState.NONE
|
||||
var authentication_methods = []
|
||||
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 = []
|
||||
#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():
|
||||
if ssl_peer != null:
|
||||
ssl_peer.disconnect_from_stream()
|
||||
else:
|
||||
ssl_peer = StreamPeerTLS.new()
|
||||
if tcp_peer != null:
|
||||
tcp_peer.disconnect_from_host()
|
||||
else:
|
||||
tcp_peer = StreamPeerTCP.new()
|
||||
tgt_peer = tcp_peer
|
||||
start_stream()
|
||||
stream_status = self.StreamState.START
|
||||
#func reinit_stream():
|
||||
# if ssl_peer != null:
|
||||
# ssl_peer.disconnect_from_stream()
|
||||
# else:
|
||||
# ssl_peer = StreamPeerTLS.new()
|
||||
# if tcp_peer != null:
|
||||
# tcp_peer.disconnect_from_host()
|
||||
# else:
|
||||
# tcp_peer = StreamPeerTCP.new()
|
||||
# tgt_peer = tcp_peer
|
||||
## start_stream()
|
||||
# stream_status = self.StreamState.START
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
|
@ -167,7 +173,7 @@ func _init() -> 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:
|
||||
return
|
||||
# Wait MAX_WAIT_MISSING_TLS (s) if server can't negociate with TLS
|
||||
|
@ -327,7 +333,13 @@ func _process(delta) -> void:
|
|||
return
|
||||
elif selected_mechanism_authenticate == "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:
|
||||
# https://datatracker.ietf.org/doc/html/rfc4616
|
||||
if tcp_peer.get_status() != StreamPeerTCP.STATUS_CONNECTED:
|
||||
xmpp_state = XMPPState.NONE
|
||||
count_connecting_time = 0
|
||||
|
@ -365,10 +377,112 @@ func _process(delta) -> void:
|
|||
count_connecting_time = 0
|
||||
xmpp_state = XMPPState.SELECT_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:
|
||||
response = remove_stream_header(response)
|
||||
if response.begins_with("<success"):
|
||||
count_connecting_time = 0
|
||||
return SASLReturn.SUCCESS
|
||||
|
@ -493,13 +607,18 @@ func select_mechanism_authenticate(authentication_methods : Array) -> 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()
|
||||
# [authzid]
|
||||
#msg += server_xmpp_name.to_ascii_buffer()
|
||||
# UTF8NUL
|
||||
msg.push_back(0)
|
||||
# authcid
|
||||
var t = account_name.split("@")[0]
|
||||
msg += t.to_ascii_buffer()
|
||||
#msg += conv_string_to_PackedByteArray(account_name.split("@")[0])
|
||||
# UTF8NUL
|
||||
msg.push_back(0)
|
||||
# passwd
|
||||
msg += password.to_ascii_buffer()
|
||||
var auth_account:String = Marshalls.raw_to_base64(msg)
|
||||
var request_sasl:String = "<auth" + \
|
||||
|
@ -509,6 +628,56 @@ func negotiate_ssl_authenticate_plain() -> void:
|
|||
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:
|
||||
if ( authentication_methods.has("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:
|
||||
var res = tcp_peer.connect_to_host(server_xmpp_name, port_number)
|
||||
if res == OK:
|
||||
count_connecting_time = 0
|
||||
stream_status = self.StreamState.END
|
||||
set_process(true)
|
||||
tgt_peer = tcp_peer
|
||||
#func connect_to_server_xmpp() -> void:
|
||||
# var res = tcp_peer.connect_to_host(server_xmpp_name, port_number)
|
||||
# if res == OK:
|
||||
# count_connecting_time = 0
|
||||
# stream_status = self.StreamState.END
|
||||
# set_process(true)
|
||||
# tgt_peer = tcp_peer
|
||||
|
||||
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)
|
||||
if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED:
|
||||
print("STATUS_CONNECTED:", delta)
|
||||
if (tgt_peer.has_method("poll")):
|
||||
tgt_peer.poll()
|
||||
if tgt_peer.get_available_bytes()>0:
|
||||
var response = tgt_peer.get_string(tgt_peer.get_available_bytes())
|
||||
send_msg_debug.emit("Stream: response: " + response)
|
||||
if stream_status == self.StreamState.STANZA:
|
||||
#collect_stanza(remove_stream_header(response))
|
||||
print("collect_stanza")
|
||||
else:
|
||||
print("stream_process")
|
||||
stream_process(remove_stream_header(response))
|
||||
# print(remove_stream_header(response))
|
||||
elif stream_status == self.StreamState.END:
|
||||
reinit_stream()
|
||||
#start_stream()
|
||||
#stream_status = self.StreamState.START
|
||||
count_connecting_time = 0
|
||||
if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTING:
|
||||
print("STATUS_CONNECTING:", delta)
|
||||
count_connecting_time += delta
|
||||
if (tgt_peer.has_method("poll")):
|
||||
tgt_peer.poll()
|
||||
if count_connecting_time > 60: # (1 -> 1s) if it took more than 1s to connect, error
|
||||
print("**** 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")
|
||||
tgt_peer.disconnect_from_host() #interrupts connection to nothing
|
||||
set_process(false) # stop listening for packets
|
||||
try_connect = 20
|
||||
stream_status = self.StreamState.END
|
||||
reinit_stream()
|
||||
if tgt_peer.get_status() == StreamPeerTCP.STATUS_NONE and xmppclient:
|
||||
print("connect_to_server:", xmppclient)
|
||||
connect_to_server()
|
||||
xmppclient = false
|
||||
#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)
|
||||
# if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED:
|
||||
# print("STATUS_CONNECTED:", delta)
|
||||
# if (tgt_peer.has_method("poll")):
|
||||
# tgt_peer.poll()
|
||||
# if tgt_peer.get_available_bytes()>0:
|
||||
# var response = tgt_peer.get_string(tgt_peer.get_available_bytes())
|
||||
# send_msg_debug.emit("Stream: response: " + response)
|
||||
# if stream_status == self.StreamState.STANZA:
|
||||
# #collect_stanza(remove_stream_header(response))
|
||||
# print("collect_stanza")
|
||||
# else:
|
||||
# print("stream_process")
|
||||
# stream_process(remove_stream_header(response))
|
||||
## print(remove_stream_header(response))
|
||||
# elif stream_status == self.StreamState.END:
|
||||
# reinit_stream()
|
||||
# #start_stream()
|
||||
# #stream_status = self.StreamState.START
|
||||
# count_connecting_time = 0
|
||||
# if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTING:
|
||||
# print("STATUS_CONNECTING:", delta)
|
||||
# count_connecting_time += delta
|
||||
# if (tgt_peer.has_method("poll")):
|
||||
# tgt_peer.poll()
|
||||
# if count_connecting_time > 60: # (1 -> 1s) if it took more than 1s to connect, error
|
||||
# print("**** 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")
|
||||
# tgt_peer.disconnect_from_host() #interrupts connection to nothing
|
||||
# set_process(false) # stop listening for packets
|
||||
# try_connect = 20
|
||||
# stream_status = self.StreamState.END
|
||||
# reinit_stream()
|
||||
# if tgt_peer.get_status() == StreamPeerTCP.STATUS_NONE and xmppclient:
|
||||
# print("connect_to_server:", xmppclient)
|
||||
# connect_to_server()
|
||||
# xmppclient = false
|
||||
|
||||
|
||||
func connect_to_server():
|
||||
|
@ -630,24 +799,24 @@ func conv_string_to_PackedByteArray(message:String) -> PackedByteArray:
|
|||
# tgt_peer.put_data(message)
|
||||
|
||||
|
||||
func start_stream() -> void:
|
||||
""" Send the stream header.
|
||||
Needs to be done several times over stream negotiation.
|
||||
"""
|
||||
var server_name = account_name.split("@")[-1]
|
||||
var message:String = "<?xml version='1.0'?>" + \
|
||||
"<stream:stream" + \
|
||||
" xmlns=\"jabber:client\"" + \
|
||||
" version=\"1.0\"" + \
|
||||
" xmlns:stream=\"http://etherx.jabber.org/streams\"" + \
|
||||
" from=\"" + account_name + "\" " + \
|
||||
" to=\"" + server_name + "\" " + \
|
||||
" xml:lang=\"en\"" + \
|
||||
" > "
|
||||
# " from=\"" + account_name + "\" " + \
|
||||
# + locale + "'" +
|
||||
print(message)
|
||||
send_string(message)
|
||||
#func start_stream() -> void:
|
||||
# """ Send the stream header.
|
||||
# Needs to be done several times over stream negotiation.
|
||||
# """
|
||||
# var server_name = account_name.split("@")[-1]
|
||||
# var message:String = "<?xml version='1.0'?>" + \
|
||||
# "<stream:stream" + \
|
||||
# " xmlns=\"jabber:client\"" + \
|
||||
# " version=\"1.0\"" + \
|
||||
# " xmlns:stream=\"http://etherx.jabber.org/streams\"" + \
|
||||
# " from=\"" + account_name + "\" " + \
|
||||
# " to=\"" + server_name + "\" " + \
|
||||
# " xml:lang=\"en\"" + \
|
||||
# " > "
|
||||
# # " from=\"" + account_name + "\" " + \
|
||||
# # + locale + "'" +
|
||||
# print(message)
|
||||
# send_string(message)
|
||||
|
||||
func remove_stream_header(text :String) -> String:
|
||||
var index = 0
|
||||
|
@ -666,130 +835,130 @@ func remove_stream_header(text :String) -> String:
|
|||
return text
|
||||
|
||||
|
||||
func stream_process(response :String = "") -> void:
|
||||
""" Try to authenticate using SASL. We can currently only do plain.
|
||||
For SCRAM based methods, we need HMAC at the very least.
|
||||
"""
|
||||
|
||||
if (!response.length() == 0 and stream_status != self.StreamState.STANZA):
|
||||
if response.begins_with("<stream:error"):
|
||||
var stream_error = XMPPStreamError.new()
|
||||
stream_error.parse_from_xml(response)
|
||||
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()], "%"))
|
||||
error.emit(error)
|
||||
|
||||
elif response.begins_with("<stream:features"):
|
||||
var stream_features = XMPPStreamFeatures.new()
|
||||
stream_features.parse_from_xml(response)
|
||||
|
||||
if stream_features.parsedDictionary.has("starttls"):
|
||||
send_msg_debug.emit("Stream: sending request for ssl")
|
||||
var request_tls = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
|
||||
send_string(request_tls)
|
||||
stream_status = self.StreamState.TLS
|
||||
|
||||
elif stream_features.parsedDictionary.has("mechanisms"):
|
||||
print("response:", response)
|
||||
var authentication_methods = stream_features.parsedDictionary["mechanisms"]
|
||||
if (authentication_methods.size() > 0):
|
||||
var tmp:String = ""
|
||||
var sep:String = ""
|
||||
for item in authentication_methods:
|
||||
tmp += sep + item
|
||||
sep = ", "
|
||||
send_msg_debug.emit("Stream: authentication methods: " + tmp)
|
||||
negotiate_sasl(authentication_methods)
|
||||
stream_status = self.StreamState.AUTHENTICATE
|
||||
|
||||
else:
|
||||
if stream_status == StreamState.TLS:
|
||||
if response.begins_with("<proceed"):
|
||||
send_msg_debug.emit("Stream: gotten go ahead for ssl")
|
||||
negotiate_tls()
|
||||
else:
|
||||
send_msg_error.emit(tr("Tls negotiation failed."))
|
||||
|
||||
elif stream_status == StreamState.AUTHENTICATE:
|
||||
if response.begins_with("<success"):
|
||||
stream_status = self.StreamState.STANZA
|
||||
# start_stream()
|
||||
return
|
||||
else:
|
||||
var parser = XMLParser.new()
|
||||
# parser.open_buffer(response.to_utf8())
|
||||
var failure_text = []
|
||||
while parser.read() == OK:
|
||||
if parser.get_node_type() == XMLParser.NODE_TEXT:
|
||||
failure_text.append(parser.get_node_data())
|
||||
print(failure_text)
|
||||
# failure_text = tr("Authentication failed! %".format([PoolStringArray(failure_text).join(" ")], "%"))
|
||||
var msg:String = ""
|
||||
for item in failure_text:
|
||||
msg += item
|
||||
send_msg_error.emit(msg)
|
||||
elif stream_status == self.StreamState.START:
|
||||
connect_to_server()
|
||||
start_stream()
|
||||
else:
|
||||
print("Mystery stream status: "+str(stream_status))
|
||||
#func stream_process(response :String = "") -> void:
|
||||
# """ Try to authenticate using SASL. We can currently only do plain.
|
||||
# For SCRAM based methods, we need HMAC at the very least.
|
||||
# """
|
||||
#
|
||||
# if (!response.length() == 0 and stream_status != self.StreamState.STANZA):
|
||||
# if response.begins_with("<stream:error"):
|
||||
# var stream_error = XMPPStreamError.new()
|
||||
# stream_error.parse_from_xml(response)
|
||||
# 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()], "%"))
|
||||
# error.emit(error)
|
||||
#
|
||||
# elif response.begins_with("<stream:features"):
|
||||
# var stream_features = XMPPStreamFeatures.new()
|
||||
# stream_features.parse_from_xml(response)
|
||||
#
|
||||
# if stream_features.parsedDictionary.has("starttls"):
|
||||
# send_msg_debug.emit("Stream: sending request for ssl")
|
||||
# var request_tls = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
|
||||
# send_string(request_tls)
|
||||
# stream_status = self.StreamState.TLS
|
||||
#
|
||||
# elif stream_features.parsedDictionary.has("mechanisms"):
|
||||
# print("response:", response)
|
||||
# var authentication_methods = stream_features.parsedDictionary["mechanisms"]
|
||||
# if (authentication_methods.size() > 0):
|
||||
# var tmp:String = ""
|
||||
# var sep:String = ""
|
||||
# for item in authentication_methods:
|
||||
# tmp += sep + item
|
||||
# sep = ", "
|
||||
# send_msg_debug.emit("Stream: authentication methods: " + tmp)
|
||||
# negotiate_sasl(authentication_methods)
|
||||
# stream_status = self.StreamState.AUTHENTICATE
|
||||
#
|
||||
# else:
|
||||
# if stream_status == StreamState.TLS:
|
||||
# if response.begins_with("<proceed"):
|
||||
# send_msg_debug.emit("Stream: gotten go ahead for ssl")
|
||||
# negotiate_tls()
|
||||
# else:
|
||||
# send_msg_error.emit(tr("Tls negotiation failed."))
|
||||
#
|
||||
# elif stream_status == StreamState.AUTHENTICATE:
|
||||
# if response.begins_with("<success"):
|
||||
# stream_status = self.StreamState.STANZA
|
||||
## start_stream()
|
||||
# return
|
||||
# else:
|
||||
# var parser = XMLParser.new()
|
||||
## parser.open_buffer(response.to_utf8())
|
||||
# var failure_text = []
|
||||
# while parser.read() == OK:
|
||||
# if parser.get_node_type() == XMLParser.NODE_TEXT:
|
||||
# failure_text.append(parser.get_node_data())
|
||||
# print(failure_text)
|
||||
## failure_text = tr("Authentication failed! %".format([PoolStringArray(failure_text).join(" ")], "%"))
|
||||
# var msg:String = ""
|
||||
# for item in failure_text:
|
||||
# msg += item
|
||||
# send_msg_error.emit(msg)
|
||||
# elif stream_status == self.StreamState.START:
|
||||
# connect_to_server()
|
||||
# start_stream()
|
||||
# else:
|
||||
# print("Mystery stream status: "+str(stream_status))
|
||||
|
||||
|
||||
func negotiate_tls() -> bool:
|
||||
#var ssl_peer = StreamPeerTLS.new()
|
||||
# I am unsure how to validate the ssl certificate for an unknown host?
|
||||
#var ssl_succes = FAILED
|
||||
var options:TLSOptions = TLSOptions.client_unsafe()
|
||||
print("accept_stream")
|
||||
#var ssl_succes = ssl_peer.accept_stream(tcp_peer, options)
|
||||
var ssl_succes = ssl_peer.connect_to_stream(tcp_peer, "localhost", options)
|
||||
print("resultat:", ssl_succes)
|
||||
if ssl_succes == OK:
|
||||
send_msg_debug.emit("Stream: switched to SSL!")
|
||||
print("get_status:", ssl_peer.get_status())
|
||||
# Wait connection done
|
||||
while ssl_peer.get_status() == StreamPeerTLS.STATUS_HANDSHAKING:
|
||||
ssl_peer.poll()
|
||||
print("get_status:", ssl_peer.get_status())
|
||||
tgt_peer = ssl_peer
|
||||
start_stream()
|
||||
print("get_status:", ssl_peer.get_status())
|
||||
print("-----")
|
||||
#stream_status == StreamState.START
|
||||
return true
|
||||
else:
|
||||
send_msg_error.emit("SSL failed, error %".format([ssl_succes], "%"))
|
||||
return false
|
||||
#func negotiate_tls() -> bool:
|
||||
# #var ssl_peer = StreamPeerTLS.new()
|
||||
# # I am unsure how to validate the ssl certificate for an unknown host?
|
||||
# #var ssl_succes = FAILED
|
||||
# var options:TLSOptions = TLSOptions.client_unsafe()
|
||||
# print("accept_stream")
|
||||
# #var ssl_succes = ssl_peer.accept_stream(tcp_peer, options)
|
||||
# var ssl_succes = ssl_peer.connect_to_stream(tcp_peer, "localhost", options)
|
||||
# print("resultat:", ssl_succes)
|
||||
# if ssl_succes == OK:
|
||||
# send_msg_debug.emit("Stream: switched to SSL!")
|
||||
# print("get_status:", ssl_peer.get_status())
|
||||
# # Wait connection done
|
||||
# while ssl_peer.get_status() == StreamPeerTLS.STATUS_HANDSHAKING:
|
||||
# ssl_peer.poll()
|
||||
# print("get_status:", ssl_peer.get_status())
|
||||
# tgt_peer = ssl_peer
|
||||
# start_stream()
|
||||
# print("get_status:", ssl_peer.get_status())
|
||||
# print("-----")
|
||||
# #stream_status == StreamState.START
|
||||
# return true
|
||||
# else:
|
||||
# send_msg_error.emit("SSL failed, error %".format([ssl_succes], "%"))
|
||||
# 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:
|
||||
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 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
|
||||
#
|
||||
#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
|
||||
|
|
Loading…
Reference in a new issue