Add legal consent and reliable external redirects
This commit is contained in:
@@ -22,6 +22,11 @@ var expires_at := ""
|
||||
var expiration_unix := 0.0
|
||||
var refresh_in_progress := false
|
||||
var warning_active := false
|
||||
var requires_legal_acceptance := false
|
||||
var terms_version := ""
|
||||
var privacy_version := ""
|
||||
var terms_url := ""
|
||||
var privacy_url := ""
|
||||
var auth_base_url := DEFAULT_AUTH_BASE_URL
|
||||
var expiry_timer: Timer
|
||||
var refresh_request: HTTPRequest
|
||||
@@ -42,7 +47,7 @@ func _ready() -> void:
|
||||
refresh_request.request_completed.connect(_on_refresh_completed)
|
||||
add_child(refresh_request)
|
||||
|
||||
func set_session(new_username: String, token: String, new_refresh_token: String = "", new_role: String = "", token_expiration: String = "") -> void:
|
||||
func set_session(new_username: String, token: String, new_refresh_token: String = "", new_role: String = "", token_expiration: String = "", legal: Dictionary = {}) -> void:
|
||||
session_revision += 1
|
||||
is_logged_in = not token.is_empty()
|
||||
username = new_username
|
||||
@@ -54,6 +59,7 @@ func set_session(new_username: String, token: String, new_refresh_token: String
|
||||
refresh_in_progress = false
|
||||
refresh_revision = -1
|
||||
warning_active = false
|
||||
set_legal_state(legal, false)
|
||||
if is_logged_in and expiration_unix > 0.0:
|
||||
expiry_timer.start()
|
||||
else:
|
||||
@@ -63,6 +69,16 @@ func set_session(new_username: String, token: String, new_refresh_token: String
|
||||
_evaluate_expiry.call_deferred()
|
||||
|
||||
|
||||
func set_legal_state(legal: Dictionary, notify := true) -> void:
|
||||
requires_legal_acceptance = bool(legal.get("requiresLegalAcceptance", false))
|
||||
terms_version = str(legal.get("termsVersion", terms_version))
|
||||
privacy_version = str(legal.get("privacyVersion", privacy_version))
|
||||
terms_url = str(legal.get("termsUrl", terms_url))
|
||||
privacy_url = str(legal.get("privacyUrl", privacy_url))
|
||||
if notify:
|
||||
auth_changed.emit()
|
||||
|
||||
|
||||
func clear_session() -> void:
|
||||
_clear_session_fields()
|
||||
auth_changed.emit()
|
||||
@@ -175,6 +191,9 @@ func _on_refresh_completed(result: int, response_code: int, _headers: PackedStri
|
||||
expires_at = new_expiration
|
||||
expiration_unix = new_expiration_unix
|
||||
warning_active = false
|
||||
var legal_value: Variant = parsed.get("legal", {})
|
||||
if typeof(legal_value) == TYPE_DICTIONARY:
|
||||
set_legal_state(legal_value, false)
|
||||
session_revision += 1
|
||||
expiry_timer.start()
|
||||
auth_changed.emit()
|
||||
@@ -197,6 +216,11 @@ func _clear_session_fields() -> void:
|
||||
refresh_in_progress = false
|
||||
refresh_revision = -1
|
||||
warning_active = false
|
||||
requires_legal_acceptance = false
|
||||
terms_version = ""
|
||||
privacy_version = ""
|
||||
terms_url = ""
|
||||
privacy_url = ""
|
||||
|
||||
|
||||
func _parse_expiration(value: String, token: String = "") -> float:
|
||||
|
||||
@@ -5,7 +5,7 @@ const DEFAULT_URL := "https://s3q.ranaze.com/api/donations"
|
||||
const REQUEST_TIMEOUT_SECONDS := 30.0
|
||||
const POLL_INTERVAL_SECONDS := 3.0
|
||||
const POLL_LIMIT := 200
|
||||
const CHECKOUT_STORAGE_KEY := "medmindDonationCheckoutUrl"
|
||||
const CHECKOUT_STORAGE_KEY := "ranaze_donation_checkout_url"
|
||||
|
||||
signal checkout_started(donation_id: String, checkout_url: String)
|
||||
signal donation_status_changed(status: String, donation: Dictionary)
|
||||
@@ -140,14 +140,14 @@ func _on_status_completed(result: int, response_code: int, _headers: PackedStrin
|
||||
func _prepare_browser_window() -> void:
|
||||
if OS.has_feature("web"):
|
||||
JavaScriptBridge.eval(
|
||||
"window.localStorage.removeItem('%s'); window.medmindDonationWindow = window.open('about:blank', 'medmind_donation_checkout'); if (window.medmindDonationWindow) { var medmindWaitingWindow = window.medmindDonationWindow; medmindWaitingWindow.document.title = 'RanaZe secure checkout'; medmindWaitingWindow.document.body.innerHTML = '<main id=\"medmind-checkout\" style=\"font:16px system-ui;padding:48px;color:#172033\"><strong>Opening secure checkout...</strong><p>This window will continue to Stripe.</p></main>'; medmindWaitingWindow.setInterval(function () { var checkoutUrl = medmindWaitingWindow.localStorage.getItem('%s'); if (checkoutUrl) { var checkout = medmindWaitingWindow.document.getElementById('medmind-checkout'); checkout.innerHTML = '<strong>Secure checkout is ready.</strong><p><a id=\"medmind-checkout-link\" style=\"color:#2563eb;font-weight:600\">Continue to Stripe</a></p>'; medmindWaitingWindow.document.getElementById('medmind-checkout-link').href = checkoutUrl; medmindWaitingWindow.localStorage.removeItem('%s'); medmindWaitingWindow.location.replace(checkoutUrl); } }, 150); }" % [CHECKOUT_STORAGE_KEY, CHECKOUT_STORAGE_KEY, CHECKOUT_STORAGE_KEY],
|
||||
"window.localStorage.removeItem('%s'); var ranazeDonationBridge = new URL('/external-redirect.html?key=%s&provider=Stripe', window.location.origin).href; window.medmindDonationWindow = window.open(ranazeDonationBridge, 'medmind_donation_checkout');" % [CHECKOUT_STORAGE_KEY, CHECKOUT_STORAGE_KEY],
|
||||
true)
|
||||
|
||||
|
||||
func _open_checkout_url(url: String) -> void:
|
||||
if OS.has_feature("web"):
|
||||
JavaScriptBridge.eval(
|
||||
"var medmindCheckoutUrl = %s; window.localStorage.setItem('%s', medmindCheckoutUrl); if (window.medmindDonationWindow && !window.medmindDonationWindow.closed) { window.medmindDonationWindow.focus(); } else { var medmindCheckoutWindow = window.open(medmindCheckoutUrl, 'medmind_donation_checkout'); if (medmindCheckoutWindow) { window.medmindDonationWindow = medmindCheckoutWindow; medmindCheckoutWindow.focus(); } else { window.location.assign(medmindCheckoutUrl); } }" % [JSON.stringify(url), CHECKOUT_STORAGE_KEY],
|
||||
"var ranazeDonationUrl = %s; window.localStorage.setItem('%s', ranazeDonationUrl); if (window.medmindDonationWindow && !window.medmindDonationWindow.closed) { try { window.medmindDonationWindow.location.replace(ranazeDonationUrl); } catch (_) {} window.medmindDonationWindow.focus(); } else { var ranazeDonationPopup = window.open(ranazeDonationUrl, 'medmind_donation_checkout'); if (ranazeDonationPopup) { window.medmindDonationWindow = ranazeDonationPopup; ranazeDonationPopup.focus(); } else { window.location.assign(ranazeDonationUrl); } }" % [JSON.stringify(url), CHECKOUT_STORAGE_KEY],
|
||||
true)
|
||||
else:
|
||||
OS.shell_open(url)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
extends Node
|
||||
|
||||
signal acceptance_succeeded
|
||||
signal acceptance_failed(message: String)
|
||||
|
||||
const EndpointConfig := preload("res://scripts/autoload/api_endpoint_config.gd")
|
||||
const DEFAULT_AUTH_BASE_URL := "https://pauth.ranaze.com/api/Auth"
|
||||
const DOCUMENT_PATH := "res://legal/legal_documents.json"
|
||||
|
||||
var documents: Dictionary = {}
|
||||
var auth_base_url := DEFAULT_AUTH_BASE_URL
|
||||
var request: HTTPRequest
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
auth_base_url = EndpointConfig.resolve(DEFAULT_AUTH_BASE_URL, "/api/Auth")
|
||||
_load_documents()
|
||||
request = HTTPRequest.new()
|
||||
request.timeout = 20.0
|
||||
request.request_completed.connect(_on_accept_completed)
|
||||
add_child(request)
|
||||
|
||||
|
||||
func get_document(kind: String) -> Dictionary:
|
||||
var value: Variant = documents.get(kind, {})
|
||||
return value if typeof(value) == TYPE_DICTIONARY else {}
|
||||
|
||||
|
||||
func public_url(kind: String) -> String:
|
||||
if kind == "terms" and not AuthState.terms_url.is_empty():
|
||||
return AuthState.terms_url
|
||||
if kind == "privacy" and not AuthState.privacy_url.is_empty():
|
||||
return AuthState.privacy_url
|
||||
return "https://doctor.ranaze.com/%s.html" % kind
|
||||
|
||||
|
||||
func accept_current() -> void:
|
||||
if request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED:
|
||||
return
|
||||
if not AuthState.can_send_authenticated_request():
|
||||
acceptance_failed.emit("Your session expired. Sign in again.")
|
||||
return
|
||||
var headers := PackedStringArray([
|
||||
"Content-Type: application/json",
|
||||
"Authorization: Bearer %s" % AuthState.access_token
|
||||
])
|
||||
var error := request.request(
|
||||
"%s/legal/accept" % auth_base_url.rstrip("/"),
|
||||
headers,
|
||||
HTTPClient.METHOD_POST,
|
||||
JSON.stringify({"accept": true}))
|
||||
if error != OK:
|
||||
acceptance_failed.emit("Unable to contact the authentication service. Try again.")
|
||||
|
||||
|
||||
func _load_documents() -> void:
|
||||
var file := FileAccess.open(DOCUMENT_PATH, FileAccess.READ)
|
||||
if file == null:
|
||||
push_error("Unable to load legal documents")
|
||||
return
|
||||
var parsed: Variant = JSON.parse_string(file.get_as_text())
|
||||
if typeof(parsed) == TYPE_DICTIONARY:
|
||||
documents = parsed
|
||||
|
||||
|
||||
func _on_accept_completed(result: int, code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
if result != HTTPRequest.RESULT_SUCCESS or code < 200 or code >= 300:
|
||||
acceptance_failed.emit("Unable to save your agreement. Check your connection and try again.")
|
||||
return
|
||||
var parsed: Variant = JSON.parse_string(body.get_string_from_utf8())
|
||||
if typeof(parsed) != TYPE_DICTIONARY:
|
||||
acceptance_failed.emit("The authentication service returned an invalid response.")
|
||||
return
|
||||
AuthState.set_legal_state(parsed)
|
||||
acceptance_succeeded.emit()
|
||||
@@ -0,0 +1 @@
|
||||
uid://dp43xyka8queb
|
||||
Reference in New Issue
Block a user