added firebase and rudimentary leaderboard support
This commit is contained in:
693
addons/godot-firebase/auth/auth.gd
Normal file
693
addons/godot-firebase/auth/auth.gd
Normal file
@@ -0,0 +1,693 @@
|
||||
## @meta-authors TODO
|
||||
## @meta-version 2.5
|
||||
## The authentication API for Firebase.
|
||||
## Documentation TODO.
|
||||
@tool
|
||||
class_name FirebaseAuth
|
||||
extends HTTPRequest
|
||||
|
||||
const _API_VERSION : String = "v1"
|
||||
const _INAPP_PLUGIN : String = "GodotSvc"
|
||||
|
||||
# Emitted for each Auth request issued.
|
||||
# `result_code` -> Either `1` if auth succeeded or `error_code` if unsuccessful auth request
|
||||
# `result_content` -> Either `auth_result` if auth succeeded or `error_message` if unsuccessful auth request
|
||||
signal auth_request(result_code, result_content)
|
||||
|
||||
signal signup_succeeded(auth_result)
|
||||
signal login_succeeded(auth_result)
|
||||
signal login_failed(code, message)
|
||||
signal signup_failed(code, message)
|
||||
signal userdata_received(userdata)
|
||||
signal token_exchanged(successful)
|
||||
signal token_refresh_succeeded(auth_result)
|
||||
signal logged_out()
|
||||
|
||||
const RESPONSE_SIGNUP : String = "identitytoolkit#SignupNewUserResponse"
|
||||
const RESPONSE_SIGNIN : String = "identitytoolkit#VerifyPasswordResponse"
|
||||
const RESPONSE_ASSERTION : String = "identitytoolkit#VerifyAssertionResponse"
|
||||
const RESPONSE_USERDATA : String = "identitytoolkit#GetAccountInfoResponse"
|
||||
const RESPONSE_CUSTOM_TOKEN : String = "identitytoolkit#VerifyCustomTokenResponse"
|
||||
|
||||
var _base_url : String = ""
|
||||
var _refresh_request_base_url = ""
|
||||
var _signup_request_url : String = "accounts:signUp?key=%s"
|
||||
var _signin_with_oauth_request_url : String = "accounts:signInWithIdp?key=%s"
|
||||
var _signin_request_url : String = "accounts:signInWithPassword?key=%s"
|
||||
var _signin_custom_token_url : String = "accounts:signInWithCustomToken?key=%s"
|
||||
var _userdata_request_url : String = "accounts:lookup?key=%s"
|
||||
var _oobcode_request_url : String = "accounts:sendOobCode?key=%s"
|
||||
var _delete_account_request_url : String = "accounts:delete?key=%s"
|
||||
var _update_account_request_url : String = "accounts:update?key=%s"
|
||||
|
||||
var _refresh_request_url : String = "/v1/token?key=%s"
|
||||
var _google_auth_request_url : String = "https://accounts.google.com/o/oauth2/v2/auth?"
|
||||
|
||||
var _config : Dictionary = {}
|
||||
var auth : Dictionary = {}
|
||||
var _needs_refresh : bool = false
|
||||
var is_busy : bool = false
|
||||
var has_child : bool = false
|
||||
var is_oauth_login: bool = false
|
||||
|
||||
|
||||
var tcp_server : TCPServer = TCPServer.new()
|
||||
var tcp_timer : Timer = Timer.new()
|
||||
var tcp_timeout : float = 0.5
|
||||
|
||||
var _headers : PackedStringArray = [
|
||||
"Content-Type: application/json",
|
||||
"Accept: application/json",
|
||||
]
|
||||
|
||||
var requesting : int = -1
|
||||
|
||||
enum Requests {
|
||||
NONE = -1,
|
||||
EXCHANGE_TOKEN,
|
||||
LOGIN_WITH_OAUTH
|
||||
}
|
||||
|
||||
var auth_request_type : int = -1
|
||||
|
||||
enum Auth_Type {
|
||||
NONE = -1,
|
||||
LOGIN_EP,
|
||||
LOGIN_ANON,
|
||||
LOGIN_CT,
|
||||
LOGIN_OAUTH,
|
||||
SIGNUP_EP
|
||||
}
|
||||
|
||||
var _login_request_body : Dictionary = {
|
||||
"email":"",
|
||||
"password":"",
|
||||
"returnSecureToken": true,
|
||||
}
|
||||
|
||||
var _oauth_login_request_body : Dictionary = {
|
||||
"postBody":"",
|
||||
"requestUri":"",
|
||||
"returnIdpCredential":false,
|
||||
"returnSecureToken":true
|
||||
}
|
||||
|
||||
var _anonymous_login_request_body : Dictionary = {
|
||||
"returnSecureToken":true
|
||||
}
|
||||
|
||||
var _refresh_request_body : Dictionary = {
|
||||
"grant_type":"refresh_token",
|
||||
"refresh_token":"",
|
||||
}
|
||||
|
||||
var _custom_token_body : Dictionary = {
|
||||
"token":"",
|
||||
"returnSecureToken":true
|
||||
}
|
||||
|
||||
var _password_reset_body : Dictionary = {
|
||||
"requestType":"password_reset",
|
||||
"email":"",
|
||||
}
|
||||
|
||||
|
||||
var _change_email_body : Dictionary = {
|
||||
"idToken":"",
|
||||
"email":"",
|
||||
"returnSecureToken": true,
|
||||
}
|
||||
|
||||
|
||||
var _change_password_body : Dictionary = {
|
||||
"idToken":"",
|
||||
"password":"",
|
||||
"returnSecureToken": true,
|
||||
}
|
||||
|
||||
|
||||
var _account_verification_body : Dictionary = {
|
||||
"requestType":"verify_email",
|
||||
"idToken":"",
|
||||
}
|
||||
|
||||
|
||||
var _update_profile_body : Dictionary = {
|
||||
"idToken":"",
|
||||
"displayName":"",
|
||||
"photoUrl":"",
|
||||
"deleteAttribute":"",
|
||||
"returnSecureToken":true
|
||||
}
|
||||
|
||||
var link_account_body : Dictionary = {
|
||||
"idToken":"",
|
||||
"email":"",
|
||||
"password":"",
|
||||
"returnSecureToken":true
|
||||
}
|
||||
|
||||
var _local_port : int = 8060
|
||||
var _local_uri : String = "http://localhost:%s/"%_local_port
|
||||
var _local_provider : AuthProvider = AuthProvider.new()
|
||||
|
||||
func _ready() -> void:
|
||||
tcp_timer.wait_time = tcp_timeout
|
||||
tcp_timer.timeout.connect(_tcp_stream_timer)
|
||||
|
||||
Utilities.fix_http_request(self)
|
||||
if Utilities.is_web():
|
||||
_local_uri += "tmp_js_export.html"
|
||||
|
||||
|
||||
# Sets the configuration needed for the plugin to talk to Firebase
|
||||
# These settings come from the Firebase.gd script automatically
|
||||
func _set_config(config_json : Dictionary) -> void:
|
||||
_config = config_json
|
||||
_signup_request_url %= _config.apiKey
|
||||
_signin_request_url %= _config.apiKey
|
||||
_signin_custom_token_url %= _config.apiKey
|
||||
_signin_with_oauth_request_url %= _config.apiKey
|
||||
_userdata_request_url %= _config.apiKey
|
||||
_refresh_request_url %= _config.apiKey
|
||||
_oobcode_request_url %= _config.apiKey
|
||||
_delete_account_request_url %= _config.apiKey
|
||||
_update_account_request_url %= _config.apiKey
|
||||
|
||||
request_completed.connect(_on_FirebaseAuth_request_completed)
|
||||
_check_emulating()
|
||||
|
||||
|
||||
func _check_emulating() -> void :
|
||||
## Check emulating
|
||||
if not Firebase.emulating:
|
||||
_base_url = "https://identitytoolkit.googleapis.com/{version}/".format({ version = _API_VERSION })
|
||||
_refresh_request_base_url = "https://securetoken.googleapis.com"
|
||||
else:
|
||||
var port : String = _config.emulators.ports.authentication
|
||||
if port == "":
|
||||
Firebase._printerr("You are in 'emulated' mode, but the port for Authentication has not been configured.")
|
||||
else:
|
||||
_base_url = "http://localhost:{port}/identitytoolkit.googleapis.com/{version}/".format({ version = _API_VERSION ,port = port })
|
||||
_refresh_request_base_url = "http://localhost:{port}/securetoken.googleapis.com".format({port = port})
|
||||
|
||||
|
||||
# Function is used to check if the auth script is ready to process a request. Returns true if it is not currently processing
|
||||
# If false it will print an error
|
||||
func _is_ready() -> bool:
|
||||
if is_busy:
|
||||
Firebase._printerr("Firebase Auth is currently busy and cannot process this request")
|
||||
return false
|
||||
else:
|
||||
return true
|
||||
|
||||
# Function cleans the URI and replaces spaces with %20
|
||||
# As of right now we only replace spaces
|
||||
# We may need to decide to use the uri_encode() String function
|
||||
func _clean_url(_url):
|
||||
_url = _url.replace(' ','%20')
|
||||
return _url
|
||||
|
||||
# Synchronous call to check if any user is already logged in.
|
||||
func is_logged_in() -> bool:
|
||||
return auth != null and auth.has("idtoken")
|
||||
|
||||
|
||||
# Called with Firebase.Auth.signup_with_email_and_password(email, password)
|
||||
# You must pass in the email and password to this function for it to work correctly
|
||||
func signup_with_email_and_password(email : String, password : String) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
_login_request_body.email = email
|
||||
_login_request_body.password = password
|
||||
auth_request_type = Auth_Type.SIGNUP_EP
|
||||
var err = request(_base_url + _signup_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_login_request_body))
|
||||
_login_request_body.email = ""
|
||||
_login_request_body.password = ""
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error signing up with password and email: %s" % err)
|
||||
|
||||
|
||||
# Called with Firebase.Auth.anonymous_login()
|
||||
# A successful request is indicated by a 200 OK HTTP status code.
|
||||
# The response contains the Firebase ID token and refresh token associated with the anonymous user.
|
||||
# The 'mail' field will be empty since no email is linked to an anonymous user
|
||||
func login_anonymous() -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
auth_request_type = Auth_Type.LOGIN_ANON
|
||||
var err = request(_base_url + _signup_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_anonymous_login_request_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error logging in as anonymous: %s" % err)
|
||||
|
||||
# Called with Firebase.Auth.login_with_email_and_password(email, password)
|
||||
# You must pass in the email and password to this function for it to work correctly
|
||||
# If the login fails it will return an error code through the function _on_FirebaseAuth_request_completed
|
||||
func login_with_email_and_password(email : String, password : String) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
_login_request_body.email = email
|
||||
_login_request_body.password = password
|
||||
auth_request_type = Auth_Type.LOGIN_EP
|
||||
var err = request(_base_url + _signin_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_login_request_body))
|
||||
_login_request_body.email = ""
|
||||
_login_request_body.password = ""
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error logging in with password and email: %s" % err)
|
||||
|
||||
# Login with a custom valid token
|
||||
# The token needs to be generated using an external service/function
|
||||
func login_with_custom_token(token : String) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
_custom_token_body.token = token
|
||||
auth_request_type = Auth_Type.LOGIN_CT
|
||||
var err = request(_base_url + _signin_custom_token_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_custom_token_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error logging in with custom token: %s" % err)
|
||||
|
||||
# Open a web page in browser redirecting to Google oAuth2 page for the current project
|
||||
# Once given user's authorization, a token will be generated.
|
||||
# NOTE** the generated token will be automatically captured and a login request will be made if the token is correct
|
||||
func get_auth_localhost(provider: AuthProvider = get_GoogleProvider(), port : int = _local_port):
|
||||
get_auth_with_redirect(provider)
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
if has_child == false:
|
||||
add_child(tcp_timer)
|
||||
has_child = true
|
||||
tcp_timer.start()
|
||||
tcp_server.listen(port, "*")
|
||||
|
||||
|
||||
func get_auth_with_redirect(provider: AuthProvider) -> void:
|
||||
var url_endpoint: String = provider.redirect_uri
|
||||
for key in provider.params.keys():
|
||||
url_endpoint+=key+"="+provider.params[key]+"&"
|
||||
url_endpoint += provider.params.redirect_type+"="+_local_uri
|
||||
url_endpoint = _clean_url(url_endpoint)
|
||||
if Utilities.is_web() and OS.has_feature("JavaScript"):
|
||||
JavaScriptBridge.eval('window.location.replace("' + url_endpoint + '")')
|
||||
elif Engine.has_singleton(_INAPP_PLUGIN) and OS.get_name() == "iOS":
|
||||
#in app for ios if the iOS plugin exists
|
||||
set_local_provider(provider)
|
||||
Engine.get_singleton(_INAPP_PLUGIN).popup(url_endpoint)
|
||||
else:
|
||||
set_local_provider(provider)
|
||||
OS.shell_open(url_endpoint)
|
||||
|
||||
|
||||
# Login with Google oAuth2.
|
||||
# A token is automatically obtained using an authorization code using @get_google_auth()
|
||||
# @provider_id and @request_uri can be changed
|
||||
func login_with_oauth(_token: String, provider: AuthProvider) -> void:
|
||||
if _token:
|
||||
is_oauth_login = true
|
||||
var token : String = _token.uri_decode()
|
||||
var is_successful: bool = true
|
||||
if provider.should_exchange:
|
||||
exchange_token(token, _local_uri, provider.access_token_uri, provider.get_client_id(), provider.get_client_secret())
|
||||
is_successful = await self.token_exchanged
|
||||
token = auth.accesstoken
|
||||
if is_successful and _is_ready():
|
||||
is_busy = true
|
||||
_oauth_login_request_body.postBody = "access_token="+token+"&providerId="+provider.provider_id
|
||||
_oauth_login_request_body.requestUri = _local_uri
|
||||
requesting = Requests.LOGIN_WITH_OAUTH
|
||||
auth_request_type = Auth_Type.LOGIN_OAUTH
|
||||
var err = request(_base_url + _signin_with_oauth_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_oauth_login_request_body))
|
||||
_oauth_login_request_body.postBody = ""
|
||||
_oauth_login_request_body.requestUri = ""
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error logging in with oauth: %s" % err)
|
||||
|
||||
# Exchange the authorization oAuth2 code obtained from browser with a proper access id_token
|
||||
func exchange_token(code : String, redirect_uri : String, request_url: String, _client_id: String, _client_secret: String) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
var exchange_token_body : Dictionary = {
|
||||
code = code,
|
||||
redirect_uri = redirect_uri,
|
||||
client_id = _client_id,
|
||||
client_secret = _client_secret,
|
||||
grant_type = "authorization_code",
|
||||
}
|
||||
requesting = Requests.EXCHANGE_TOKEN
|
||||
var err = request(request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(exchange_token_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error exchanging tokens: %s" % err)
|
||||
|
||||
# Open a web page in browser redirecting to Google oAuth2 page for the current project
|
||||
# Once given user's authorization, a token will be generated.
|
||||
# NOTE** with this method, the authorization process will be copy-pasted
|
||||
func get_google_auth_manual(provider: AuthProvider = _local_provider) -> void:
|
||||
provider.params.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
|
||||
get_auth_with_redirect(provider)
|
||||
|
||||
# A timer used to listen through TCP checked the redirect uri of the request
|
||||
func _tcp_stream_timer() -> void:
|
||||
var peer : StreamPeer = tcp_server.take_connection()
|
||||
if peer != null:
|
||||
var raw_result : String = peer.get_utf8_string(441)
|
||||
if raw_result != "" and raw_result.begins_with("GET"):
|
||||
tcp_timer.stop()
|
||||
remove_child(tcp_timer)
|
||||
has_child = false
|
||||
var token : String = ""
|
||||
for value in raw_result.split(" ")[1].lstrip("/?").split("&"):
|
||||
var splitted: PackedStringArray = value.split("=")
|
||||
if _local_provider.params.response_type in splitted[0]:
|
||||
token = splitted[1]
|
||||
break
|
||||
|
||||
if token == "":
|
||||
login_failed.emit()
|
||||
peer.disconnect_from_host()
|
||||
tcp_server.stop()
|
||||
return
|
||||
|
||||
var data : PackedByteArray = '<p style="text-align:center">🔥 You can close this window now. 🔥</p>'.to_ascii_buffer()
|
||||
peer.put_data(("HTTP/1.1 200 OK\n").to_ascii_buffer())
|
||||
peer.put_data(("Server: Godot Firebase SDK\n").to_ascii_buffer())
|
||||
peer.put_data(("Content-Length: %d\n" % data.size()).to_ascii_buffer())
|
||||
peer.put_data("Connection: close\n".to_ascii_buffer())
|
||||
peer.put_data(("Content-Type: text/html; charset=UTF-8\n\n").to_ascii_buffer())
|
||||
peer.put_data(data)
|
||||
login_with_oauth(token, _local_provider)
|
||||
await self.login_succeeded
|
||||
peer.disconnect_from_host()
|
||||
tcp_server.stop()
|
||||
|
||||
|
||||
# Function used to logout of the system, this will also remove_at the local encrypted auth file if there is one
|
||||
func logout() -> void:
|
||||
auth = {}
|
||||
remove_auth()
|
||||
logged_out.emit()
|
||||
|
||||
# Checks to see if we need a hard login
|
||||
func needs_login() -> bool:
|
||||
var encrypted_file = FileAccess.open_encrypted_with_pass("user://user.auth", FileAccess.READ, _config.apiKey)
|
||||
var err = encrypted_file == null
|
||||
return err
|
||||
|
||||
# Function is called when requesting a manual token refresh
|
||||
func manual_token_refresh(auth_data):
|
||||
auth = auth_data
|
||||
var refresh_token = null
|
||||
auth = get_clean_keys(auth)
|
||||
if auth.has("refreshtoken"):
|
||||
refresh_token = auth.refreshtoken
|
||||
elif auth.has("refresh_token"):
|
||||
refresh_token = auth.refresh_token
|
||||
_needs_refresh = true
|
||||
_refresh_request_body.refresh_token = refresh_token
|
||||
var err = request(_refresh_request_base_url + _refresh_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_refresh_request_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error manually refreshing token: %s" % err)
|
||||
|
||||
|
||||
# This function is called whenever there is an authentication request to Firebase
|
||||
# On an error, this function with emit the signal 'login_failed' and print the error to the console
|
||||
func _on_FirebaseAuth_request_completed(result : int, response_code : int, headers : PackedStringArray, body : PackedByteArray) -> void:
|
||||
var json = Utilities.get_json_data(body.get_string_from_utf8())
|
||||
is_busy = false
|
||||
var res
|
||||
if response_code == 0:
|
||||
# Mocked error results to trigger the correct signal.
|
||||
# Can occur if there is no internet connection, or the service is down,
|
||||
# in which case there is no json_body (and thus parsing would fail).
|
||||
res = {"error": {
|
||||
"code": "Connection error",
|
||||
"message": "Error connecting to auth service"}}
|
||||
else:
|
||||
if json == null:
|
||||
Firebase._printerr("Error while parsing auth body json")
|
||||
auth_request.emit(ERR_PARSE_ERROR, "Error while parsing auth body json")
|
||||
return
|
||||
|
||||
res = json
|
||||
if response_code == HTTPClient.RESPONSE_OK:
|
||||
if not res.has("kind"):
|
||||
auth = get_clean_keys(res)
|
||||
match requesting:
|
||||
Requests.EXCHANGE_TOKEN:
|
||||
token_exchanged.emit(true)
|
||||
begin_refresh_countdown()
|
||||
# Refresh token countdown
|
||||
auth_request.emit(1, auth)
|
||||
|
||||
if _needs_refresh:
|
||||
_needs_refresh = false
|
||||
if not is_oauth_login: login_succeeded.emit(auth)
|
||||
else:
|
||||
match res.kind:
|
||||
RESPONSE_SIGNUP:
|
||||
auth = get_clean_keys(res)
|
||||
signup_succeeded.emit(auth)
|
||||
begin_refresh_countdown()
|
||||
RESPONSE_SIGNIN, RESPONSE_ASSERTION, RESPONSE_CUSTOM_TOKEN:
|
||||
auth = get_clean_keys(res)
|
||||
login_succeeded.emit(auth)
|
||||
begin_refresh_countdown()
|
||||
RESPONSE_USERDATA:
|
||||
var userdata = FirebaseUserData.new(res.users[0])
|
||||
userdata_received.emit(userdata)
|
||||
auth_request.emit(1, auth)
|
||||
else:
|
||||
# error message would be INVALID_EMAIL, EMAIL_NOT_FOUND, INVALID_PASSWORD, USER_DISABLED or WEAK_PASSWORD
|
||||
if requesting == Requests.EXCHANGE_TOKEN:
|
||||
token_exchanged.emit(false)
|
||||
login_failed.emit(res.error, res.error_description)
|
||||
auth_request.emit(res.error, res.error_description)
|
||||
else:
|
||||
var sig = signup_failed if auth_request_type == Auth_Type.SIGNUP_EP else login_failed
|
||||
sig.emit(res.error.code, res.error.message)
|
||||
auth_request.emit(res.error.code, res.error.message)
|
||||
requesting = Requests.NONE
|
||||
auth_request_type = Auth_Type.NONE
|
||||
is_oauth_login = false
|
||||
|
||||
|
||||
|
||||
# Function used to save the auth data provided by Firebase into an encrypted file
|
||||
# Note this does not work in HTML5 or UWP
|
||||
func save_auth(auth : Dictionary) -> bool:
|
||||
var encrypted_file = FileAccess.open_encrypted_with_pass("user://user.auth", FileAccess.WRITE, _config.apiKey)
|
||||
var err = encrypted_file == null
|
||||
if err:
|
||||
Firebase._printerr("Error Opening File. Error Code: " + str(FileAccess.get_open_error()))
|
||||
else:
|
||||
encrypted_file.store_line(JSON.stringify(auth))
|
||||
return not err
|
||||
|
||||
|
||||
# Function used to load the auth data file that has been stored locally
|
||||
# Note this does not work in HTML5 or UWP
|
||||
func load_auth() -> bool:
|
||||
var encrypted_file = FileAccess.open_encrypted_with_pass("user://user.auth", FileAccess.READ, _config.apiKey)
|
||||
var err = encrypted_file == null
|
||||
if err:
|
||||
Firebase._printerr("Error Opening Firebase Auth File. Error Code: " + str(FileAccess.get_open_error()))
|
||||
auth_request.emit(err, "Error Opening Firebase Auth File.")
|
||||
else:
|
||||
var json = JSON.new()
|
||||
var json_parse_result = json.parse(encrypted_file.get_line())
|
||||
if json_parse_result == OK:
|
||||
var encrypted_file_data = json.data
|
||||
manual_token_refresh(encrypted_file_data)
|
||||
return not err
|
||||
|
||||
# Function used to remove_at the local encrypted auth file
|
||||
func remove_auth() -> void:
|
||||
if (FileAccess.file_exists("user://user.auth")):
|
||||
DirAccess.remove_absolute("user://user.auth")
|
||||
else:
|
||||
Firebase._printerr("No encrypted auth file exists")
|
||||
|
||||
|
||||
# Function to check if there is an encrypted auth data file
|
||||
# If there is, the game will load it and refresh the token
|
||||
func check_auth_file() -> bool:
|
||||
if (FileAccess.file_exists("user://user.auth")):
|
||||
# Will ensure "auth_request" emitted
|
||||
return load_auth()
|
||||
else:
|
||||
Firebase._printerr("Encrypted Firebase Auth file does not exist")
|
||||
auth_request.emit(ERR_DOES_NOT_EXIST, "Encrypted Firebase Auth file does not exist")
|
||||
return false
|
||||
|
||||
|
||||
# Function used to change the email account for the currently logged in user
|
||||
func change_user_email(email : String) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
_change_email_body.email = email
|
||||
_change_email_body.idToken = auth.idtoken
|
||||
var err = request(_base_url + _update_account_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_change_email_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error changing user email: %s" % err)
|
||||
|
||||
|
||||
# Function used to change the password for the currently logged in user
|
||||
func change_user_password(password : String) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
_change_password_body.password = password
|
||||
_change_password_body.idToken = auth.idtoken
|
||||
var err = request(_base_url + _update_account_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_change_password_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error changing user password: %s" % err)
|
||||
|
||||
|
||||
# User Profile handlers
|
||||
func update_account(idToken : String, displayName : String, photoUrl : String, deleteAttribute : PackedStringArray, returnSecureToken : bool) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
_update_profile_body.idToken = idToken
|
||||
_update_profile_body.displayName = displayName
|
||||
_update_profile_body.photoUrl = photoUrl
|
||||
_update_profile_body.deleteAttribute = deleteAttribute
|
||||
_update_profile_body.returnSecureToken = returnSecureToken
|
||||
var err = request(_base_url + _update_account_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_update_profile_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error updating account: %s" % err)
|
||||
|
||||
# Link account with Email and Password
|
||||
func link_account(email : String, password : String) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
link_account_body.idToken = auth.idtoken
|
||||
link_account_body.email = email
|
||||
link_account_body.password = password
|
||||
var err = request(_base_url + _update_account_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(link_account_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error updating account: %s" % err)
|
||||
|
||||
|
||||
# Function to send a account verification email
|
||||
func send_account_verification_email() -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
_account_verification_body.idToken = auth.idtoken
|
||||
var err = request(_base_url + _oobcode_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_account_verification_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error sending account verification email: %s" % err)
|
||||
|
||||
|
||||
# Function used to reset the password for a user who has forgotten in.
|
||||
# This will send the users account an email with a password reset link
|
||||
func send_password_reset_email(email : String) -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
_password_reset_body.email = email
|
||||
var err = request(_base_url + _oobcode_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_password_reset_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error sending password reset email: %s" % err)
|
||||
|
||||
|
||||
# Function called to get all
|
||||
func get_user_data() -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
if not is_logged_in():
|
||||
print_debug("Not logged in")
|
||||
is_busy = false
|
||||
return
|
||||
|
||||
var err = request(_base_url + _userdata_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify({"idToken":auth.idtoken}))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error getting user data: %s" % err)
|
||||
|
||||
|
||||
# Function used to delete the account of the currently authenticated user
|
||||
func delete_user_account() -> void:
|
||||
if _is_ready():
|
||||
is_busy = true
|
||||
var err = request(_base_url + _delete_account_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify({"idToken":auth.idtoken}))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error deleting user: %s" % err)
|
||||
else:
|
||||
remove_auth()
|
||||
|
||||
|
||||
# Function is called when a new token is issued to a user. The function will yield until the token has expired, and then request a new one.
|
||||
func begin_refresh_countdown() -> void:
|
||||
var refresh_token = null
|
||||
var expires_in = 1000
|
||||
auth = get_clean_keys(auth)
|
||||
if auth.has("refreshtoken"):
|
||||
refresh_token = auth.refreshtoken
|
||||
expires_in = auth.expiresin
|
||||
elif auth.has("refresh_token"):
|
||||
refresh_token = auth.refresh_token
|
||||
expires_in = auth.expires_in
|
||||
if auth.has("userid"):
|
||||
auth["localid"] = auth.userid
|
||||
_needs_refresh = true
|
||||
token_refresh_succeeded.emit(auth)
|
||||
await get_tree().create_timer(float(expires_in)).timeout
|
||||
_refresh_request_body.refresh_token = refresh_token
|
||||
var err = request(_refresh_request_base_url + _refresh_request_url, _headers, HTTPClient.METHOD_POST, JSON.stringify(_refresh_request_body))
|
||||
if err != OK:
|
||||
is_busy = false
|
||||
Firebase._printerr("Error refreshing via countdown: %s" % err)
|
||||
|
||||
|
||||
func get_token_from_url(provider: AuthProvider):
|
||||
var token_type: String = provider.params.response_type if provider.params.response_type == "code" else "access_token"
|
||||
if OS.has_feature('web'):
|
||||
var token = JavaScriptBridge.eval("""
|
||||
var url_string = window.location.href.replaceAll('?#', '?');
|
||||
var url = new URL(url_string);
|
||||
url.searchParams.get('"""+token_type+"""');
|
||||
""")
|
||||
JavaScriptBridge.eval("""window.history.pushState({}, null, location.href.split('?')[0]);""")
|
||||
return token
|
||||
return null
|
||||
|
||||
|
||||
func set_redirect_uri(redirect_uri : String) -> void:
|
||||
self._local_uri = redirect_uri
|
||||
|
||||
func set_local_provider(provider : AuthProvider) -> void:
|
||||
self._local_provider = provider
|
||||
|
||||
# This function is used to make all keys lowercase
|
||||
# This is only used to cut down checked processing errors from Firebase
|
||||
# This is due to Google have inconsistencies in the API that we are trying to fix
|
||||
func get_clean_keys(auth_result : Dictionary) -> Dictionary:
|
||||
var cleaned = {}
|
||||
for key in auth_result.keys():
|
||||
cleaned[key.replace("_", "").to_lower()] = auth_result[key]
|
||||
return cleaned
|
||||
|
||||
# --------------------
|
||||
# PROVIDERS
|
||||
# --------------------
|
||||
|
||||
func get_GoogleProvider() -> GoogleProvider:
|
||||
return GoogleProvider.new(_config.clientId, _config.clientSecret)
|
||||
|
||||
func get_FacebookProvider() -> FacebookProvider:
|
||||
return FacebookProvider.new(_config.auth_providers.facebook_id, _config.auth_providers.facebook_secret)
|
||||
|
||||
func get_GitHubProvider() -> GitHubProvider:
|
||||
return GitHubProvider.new(_config.auth_providers.github_id, _config.auth_providers.github_secret)
|
||||
|
||||
func get_TwitterProvider() -> TwitterProvider:
|
||||
return TwitterProvider.new(_config.auth_providers.twitter_id, _config.auth_providers.twitter_secret)
|
||||
Reference in New Issue
Block a user