Add provider-neutral Google authentication
This commit is contained in:
@@ -6,6 +6,8 @@ signal preferences_saved
|
||||
signal password_changed
|
||||
signal account_deleted
|
||||
signal archive_saved(path: String)
|
||||
signal external_link_started(provider: String)
|
||||
signal external_linked(provider: String)
|
||||
|
||||
const EndpointConfig := preload("res://scripts/autoload/api_endpoint_config.gd")
|
||||
const AUTH_URL := "https://us3q.ranaze.com/api/Auth"
|
||||
@@ -15,11 +17,18 @@ var account: Dictionary = {}
|
||||
var preferences: Dictionary = _default_preferences()
|
||||
var auth_request: HTTPRequest
|
||||
var profile_request: HTTPRequest
|
||||
var external_request: HTTPRequest
|
||||
var external_poll_timer: Timer
|
||||
var auth_operation := ""
|
||||
var profile_operation := ""
|
||||
var auth_token := ""
|
||||
var profile_token := ""
|
||||
var preferences_pending := false
|
||||
var external_operation := ""
|
||||
var external_provider := ""
|
||||
var external_provider_name := ""
|
||||
var external_transaction_id := ""
|
||||
var external_poll_deadline_msec := 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -31,6 +40,14 @@ func _ready() -> void:
|
||||
profile_request.timeout = 30.0
|
||||
profile_request.request_completed.connect(_on_profile_completed)
|
||||
add_child(profile_request)
|
||||
external_request = HTTPRequest.new()
|
||||
external_request.timeout = 25.0
|
||||
external_request.request_completed.connect(_on_external_completed)
|
||||
add_child(external_request)
|
||||
external_poll_timer = Timer.new()
|
||||
external_poll_timer.wait_time = 2.0
|
||||
external_poll_timer.timeout.connect(_poll_external_link)
|
||||
add_child(external_poll_timer)
|
||||
AuthState.auth_changed.connect(_on_auth_changed)
|
||||
|
||||
|
||||
@@ -83,6 +100,32 @@ func delete_account(password: String, confirmation: String) -> void:
|
||||
})
|
||||
|
||||
|
||||
func connect_provider(provider: String, provider_name: String) -> void:
|
||||
if not AuthState.can_send_authenticated_request():
|
||||
request_failed.emit("Sign in again before connecting an account.")
|
||||
return
|
||||
if external_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
request_failed.emit("Another connection request is still in progress.")
|
||||
return
|
||||
external_provider = provider
|
||||
external_provider_name = provider_name
|
||||
var storage_key := _external_storage_key()
|
||||
if OS.has_feature("web"):
|
||||
var popup_result: Variant = JavaScriptBridge.eval(
|
||||
"window.localStorage.removeItem(%s); var bridge = new URL('/external-redirect.html?key=' + encodeURIComponent(%s) + '&provider=' + encodeURIComponent(%s), window.location.origin).href; window.ranazeProfileExternalWindow = window.open(bridge, 'ranaze_profile_external', 'popup=yes,width=560,height=720,resizable=yes,scrollbars=yes'); window.ranazeProfileExternalWindow !== null;" % [JSON.stringify(storage_key), JSON.stringify(storage_key), JSON.stringify(provider_name)], true)
|
||||
if not bool(popup_result):
|
||||
request_failed.emit("Allow popups for this site, then try again.")
|
||||
_reset_external_link()
|
||||
return
|
||||
external_operation = "start"
|
||||
var headers := PackedStringArray(["Authorization: Bearer %s" % AuthState.access_token, "Content-Type: application/json"])
|
||||
var error := external_request.request("%s/external/%s/start" % [_auth_base(), provider], headers,
|
||||
HTTPClient.METHOD_POST, JSON.stringify({"purpose": "link"}))
|
||||
if error != OK:
|
||||
request_failed.emit("The account provider could not be reached.")
|
||||
_reset_external_link()
|
||||
|
||||
|
||||
func _request_auth(operation: String, method: HTTPClient.Method, path: String, payload: Variant = null) -> void:
|
||||
if auth_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
request_failed.emit("Another account request is still in progress.")
|
||||
@@ -162,6 +205,82 @@ func _on_profile_completed(result: int, response_code: int, _headers: PackedStri
|
||||
_save_archive(JSON.stringify(archive, " "))
|
||||
|
||||
|
||||
func _on_external_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
var operation := external_operation
|
||||
external_operation = ""
|
||||
if response_code == 401:
|
||||
AuthState.handle_unauthorized(AuthState.access_token)
|
||||
_reset_external_link()
|
||||
return
|
||||
if result != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300:
|
||||
request_failed.emit(_error_message(body, "The external account request failed."))
|
||||
_reset_external_link()
|
||||
return
|
||||
var parsed: Variant = JSON.parse_string(body.get_string_from_utf8())
|
||||
if typeof(parsed) != TYPE_DICTIONARY:
|
||||
request_failed.emit("The external account service returned invalid data.")
|
||||
_reset_external_link()
|
||||
return
|
||||
var data: Dictionary = parsed
|
||||
if operation == "start":
|
||||
external_transaction_id = str(data.get("transactionId", ""))
|
||||
var auth_url := str(data.get("authUrl", ""))
|
||||
if external_transaction_id.is_empty() or auth_url.is_empty():
|
||||
request_failed.emit("The provider returned an invalid response.")
|
||||
_reset_external_link()
|
||||
return
|
||||
if OS.has_feature("web"):
|
||||
JavaScriptBridge.eval("var url=%s; window.localStorage.setItem(%s,url); if(window.ranazeProfileExternalWindow&&!window.ranazeProfileExternalWindow.closed){window.ranazeProfileExternalWindow.location.replace(url);window.ranazeProfileExternalWindow.focus();}" % [JSON.stringify(auth_url), JSON.stringify(_external_storage_key())], true)
|
||||
else:
|
||||
OS.shell_open(auth_url)
|
||||
external_poll_deadline_msec = Time.get_ticks_msec() + 300000
|
||||
external_poll_timer.start()
|
||||
external_link_started.emit(external_provider)
|
||||
elif operation == "status":
|
||||
match str(data.get("status", "pending")):
|
||||
"linked":
|
||||
var linked_provider := external_provider
|
||||
_reset_external_link()
|
||||
external_linked.emit(linked_provider)
|
||||
refresh()
|
||||
"failed":
|
||||
request_failed.emit(str(data.get("message", "The provider could not connect this account.")))
|
||||
_reset_external_link()
|
||||
|
||||
|
||||
func _poll_external_link() -> void:
|
||||
if external_transaction_id.is_empty() or external_request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
return
|
||||
if Time.get_ticks_msec() >= external_poll_deadline_msec:
|
||||
request_failed.emit("The account connection timed out.")
|
||||
_reset_external_link()
|
||||
return
|
||||
external_operation = "status"
|
||||
var error := external_request.request("%s/external/%s/status/%s" % [_auth_base(), external_provider, external_transaction_id])
|
||||
if error != OK:
|
||||
external_operation = ""
|
||||
|
||||
|
||||
func _reset_external_link() -> void:
|
||||
if external_poll_timer != null:
|
||||
external_poll_timer.stop()
|
||||
if OS.has_feature("web") and not external_provider.is_empty():
|
||||
JavaScriptBridge.eval("window.localStorage.removeItem(%s);if(window.ranazeProfileExternalWindow&&!window.ranazeProfileExternalWindow.closed){window.ranazeProfileExternalWindow.close();}window.ranazeProfileExternalWindow=null;" % JSON.stringify(_external_storage_key()), true)
|
||||
external_operation = ""
|
||||
external_provider = ""
|
||||
external_provider_name = ""
|
||||
external_transaction_id = ""
|
||||
external_poll_deadline_msec = 0
|
||||
|
||||
|
||||
func _external_storage_key() -> String:
|
||||
return "ranaze_profile_external_auth_url_%s" % external_provider
|
||||
|
||||
|
||||
func _auth_base() -> String:
|
||||
return EndpointConfig.resolve(str(ProjectSettings.get_setting("step3/auth_api_base_url", AUTH_URL)), "/api/Auth").rstrip("/")
|
||||
|
||||
|
||||
func _save_archive(content: String) -> void:
|
||||
var filename := "ranaze-account-export-%s.json" % Time.get_date_string_from_system()
|
||||
if OS.has_feature("web"):
|
||||
|
||||
Reference in New Issue
Block a user