mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-15 00:32:03 +00:00
fix(multiplayer): enforce ranked tier enum
This commit is contained in:
@@ -29,7 +29,7 @@ func apply(payload: Dictionary) -> bool:
|
|||||||
var next_volatility := float(payload["volatility"])
|
var next_volatility := float(payload["volatility"])
|
||||||
var next_games := int(payload["ranked_games"])
|
var next_games := int(payload["ranked_games"])
|
||||||
var next_tier := String(payload["tier"])
|
var next_tier := String(payload["tier"])
|
||||||
if not is_finite(next_rating) or not is_finite(next_rd) or not is_finite(next_volatility) or not _valid_nonnegative_integer(payload["ranked_games"]) or next_rating < 0.0 or next_rd < 0.0 or next_volatility < 0.0 or next_games < 0 or next_tier.is_empty():
|
if not is_finite(next_rating) or not is_finite(next_rd) or not is_finite(next_volatility) or not _valid_nonnegative_integer(payload["ranked_games"]) or next_rating < 0.0 or next_rd < 0.0 or next_volatility < 0.0 or next_games < 0 or not _valid_tier(next_tier):
|
||||||
return _reject("Profile response contains invalid values")
|
return _reject("Profile response contains invalid values")
|
||||||
rating = next_rating
|
rating = next_rating
|
||||||
rd = next_rd
|
rd = next_rd
|
||||||
@@ -77,6 +77,10 @@ static func _valid_nonnegative_integer(value: Variant) -> bool:
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
static func _valid_tier(value: String) -> bool:
|
||||||
|
return value in ["PROVISIONAL", "BRONZE", "SILVER", "GOLD", "PLATINUM", "DIAMOND"]
|
||||||
|
|
||||||
|
|
||||||
func set_error(reason: String) -> void:
|
func set_error(reason: String) -> void:
|
||||||
available = false
|
available = false
|
||||||
error_message = reason
|
error_message = reason
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ func test_ranked_profile_is_backend_display_data_and_rejects_unsafe_values() ->
|
|||||||
assert_true(not profile.apply({"rating": -1.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "GOLD", "provisional": false}), "negative rating is rejected")
|
assert_true(not profile.apply({"rating": -1.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "GOLD", "provisional": false}), "negative rating is rejected")
|
||||||
assert_true(not profile.available, "unsafe response is not displayed")
|
assert_true(not profile.available, "unsafe response is not displayed")
|
||||||
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "", "provisional": false}), "empty tier is rejected")
|
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "", "provisional": false}), "empty tier is rejected")
|
||||||
|
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "MASTER", "provisional": false}), "unknown tier is rejected")
|
||||||
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "GOLD", "provisional": "false"}), "string boolean is rejected")
|
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3, "tier": "GOLD", "provisional": "false"}), "string boolean is rejected")
|
||||||
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3.5, "tier": "GOLD", "provisional": false}), "fractional ranked games is rejected")
|
assert_true(not profile.apply({"rating": 1500.0, "rd": 200.0, "volatility": 0.06, "ranked_games": 3.5, "tier": "GOLD", "provisional": false}), "fractional ranked games is rejected")
|
||||||
|
|
||||||
|
|||||||
@@ -1587,6 +1587,8 @@ Ticket timestamp normalization now preserves an invalid sentinel for malformed o
|
|||||||
|
|
||||||
Ranked profile projection now rejects fractional `ranked_games` values instead of silently truncating them, matching the OpenAPI integer contract.
|
Ranked profile projection now rejects fractional `ranked_games` values instead of silently truncating them, matching the OpenAPI integer contract.
|
||||||
|
|
||||||
|
Ranked profile projection now enforces the OpenAPI tier enum, rejecting unknown tier labels before they reach the HUD.
|
||||||
|
|
||||||
Signed MatchNet claims now also require exact JSON string/integer types for every identity, protocol, expiry, slot, team, and generation field; string-number coercion is rejected before canonical signature verification.
|
Signed MatchNet claims now also require exact JSON string/integer types for every identity, protocol, expiry, slot, team, and generation field; string-number coercion is rejected before canonical signature verification.
|
||||||
|
|
||||||
Presentation progress: a shared `Game/themes/cosmic_clash_theme.tres` now gives the menu, lobby, matchmaking, and settings surfaces consistent button, input, option, and label styling. The custom-font portion of `TODO.md` remains open until a distributable font asset is selected.
|
Presentation progress: a shared `Game/themes/cosmic_clash_theme.tres` now gives the menu, lobby, matchmaking, and settings surfaces consistent button, input, option, and label styling. The custom-font portion of `TODO.md` remains open until a distributable font asset is selected.
|
||||||
|
|||||||
Reference in New Issue
Block a user