From 1931ae143acfa04aa448b1939ac9b6dceb0f6638 Mon Sep 17 00:00:00 2001 From: Jose Falanga Date: Mon, 17 Aug 2026 02:08:53 -0300 Subject: [PATCH] Fix cookie persistence: save dict as JSON, verify via HTTP on restart --- core/itch_client.gd | 54 ++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/core/itch_client.gd b/core/itch_client.gd index 44479cd..61a0815 100644 --- a/core/itch_client.gd +++ b/core/itch_client.gd @@ -385,23 +385,41 @@ func _login_with_password(username: String, password: String) -> void: return profile = res.get("profile", {}) is_logged_in = true - # Persist the cookie so we can re-authenticate on restart without the - # password. Butlerd stores tokens in its own DB, but we need the cookie - # to verify the session on subsequent startups. - var cookie: String = res.get("cookie", "") - if cookie != "": - emit_signal.call_deferred("login_cookies_saved", username, cookie) + # Persist the cookie so we can re-authenticate on restart. Butlerd + # stores tokens in its own DB, but we re-send the cookie on subsequent + # startups so butlerd can refresh the session if needed. + var cookie_dict: Dictionary = res.get("cookie", {}) + if not cookie_dict.is_empty(): + var cookie_json := JSON.stringify(cookie_dict) + emit_signal.call_deferred("login_cookies_saved", username, cookie_json) emit_signal.call_deferred("logged_in", LOGIN_STATUS.OK, profile) -## Re-authenticates using a previously saved cookie. The cookie is verified -## against itch.io's API directly (bypassing butlerd) because butlerd does -## not expose a "login with cookie" method. -func login_with_cookie(cookie: String) -> void: - await thread_group.exec(_login_with_cookie.bind(cookie)) +## Re-authenticates using a previously saved cookie. The cookie is a JSON +## dict of name-value pairs from Profile.LoginWithPassword. We send it to +## itch.io's API directly to verify the session — butlerd doesn't expose a +## "login with cookie" method, but it stores the credentials internally so +## subsequent butlerd calls will work once we've verified the session. +func login_with_cookie(cookie_json: String) -> void: + await thread_group.exec(_login_with_cookie.bind(cookie_json)) -func _login_with_cookie(cookie: String) -> void: +func _login_with_cookie(cookie_json: String) -> void: + var cookie_dict: Dictionary = {} + var json := JSON.new() + if json.parse(cookie_json) == OK and typeof(json.data) == TYPE_DICTIONARY: + cookie_dict = json.data + if cookie_dict.is_empty(): + is_logged_in = false + emit_signal.call_deferred("logged_in", LOGIN_STATUS.INVALID_KEY, {}) + return + + # Build Cookie header from the dict: "name1=value1; name2=value2" + var pairs: PackedStringArray = [] + for key in cookie_dict: + pairs.append(str(key) + "=" + str(cookie_dict[key])) + var cookie_header := "; ".join(pairs) + var http := HTTPClient.new() var err := http.connect_to_host("api.itch.io", 443, TLSOptions.client()) if err != OK: @@ -424,7 +442,7 @@ func _login_with_cookie(cookie: String) -> void: return var headers := PackedStringArray([ - "Authorization: Bearer " + cookie, + "Cookie: " + cookie_header, "User-Agent: opencode-itch-plugin/1.0", ]) http.request(HTTPClient.METHOD_GET, "/profile", headers) @@ -454,19 +472,19 @@ func _login_with_cookie(cookie: String) -> void: http.close() var response_code := http.get_response_code() - var json_text := body.get_string_from_utf8() - if response_code != 200 or json_text.is_empty(): + var response_text := body.get_string_from_utf8() + if response_code != 200 or response_text.is_empty(): is_logged_in = false emit_signal.call_deferred("logged_in", LOGIN_STATUS.INVALID_KEY, {}) return - var json := JSON.new() - if json.parse(json_text) != OK: + var resp_json := JSON.new() + if resp_json.parse(response_text) != OK: is_logged_in = false emit_signal.call_deferred("logged_in", LOGIN_STATUS.INVALID_KEY, {}) return - var data: Dictionary = json.data + var data: Dictionary = resp_json.data profile = data.get("user", data) is_logged_in = true emit_signal.call_deferred("logged_in", LOGIN_STATUS.OK, profile)