7bd8124199
POST /api/auth/register now requires a real date_of_birth (ISO YYYY-MM-DD). The server computes age (auth.calculate_age) and rejects under-18s with 403; a future/nonsensical date is 400. The DOB is stored and surfaced only to that user (/api/auth/me). Still self-attested (a user can enter a false DOB) -- but a concrete, stored, legally-meaningful data point and the seam for a future ID-check pass. Encryption-at-rest for the column and the Tier-2 hook are not done; the limitation is stated plainly in docs/architecture/content_moderation.md 5.2. - auth.py: RegisterRequest.date_of_birth (date); MIN_AGE=18; register() computes + enforces; UserResponse.date_of_birth typed `date | None` (the old `str | None` would have 500'd /me once a DOB was actually stored). - api_client.gd / main_menu.gd: the Over18 checkbox is now a "Date of birth (YYYY-MM-DD)" field with a client-side sanity check. - tests: test_auth_age_gate.py rewritten around the endpoint + age math (adult/minor/exactly-18/future-dob/stored); ~25 over_18 references across 6 backend test files + 6 game smoke tests updated. Backend 74 passed; game smokes green (auth 6/6, menu_full_flow 12/12, e2e 4/4, etc.); fresh-clone boot PASS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jtxAiu5dAW4WxCNdGkrkJ
134 lines
4.9 KiB
Plaintext
134 lines
4.9 KiB
Plaintext
[gd_scene load_steps=2 format=3 uid="uid://main_menu_scene"]
|
|
|
|
[ext_resource type="Script" path="res://scripts/main_menu.gd" id="1_main"]
|
|
|
|
[node name="MainMenu" type="Control"]
|
|
anchors_preset = 15
|
|
anchor_right = 1.0
|
|
anchor_bottom = 1.0
|
|
grow_horizontal = 2
|
|
grow_vertical = 2
|
|
script = ExtResource("1_main")
|
|
|
|
[node name="CenterContainer" type="CenterContainer" parent="."]
|
|
layout_mode = 3
|
|
anchors_preset = 15
|
|
anchor_right = 1.0
|
|
anchor_bottom = 1.0
|
|
grow_horizontal = 2
|
|
grow_vertical = 2
|
|
|
|
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
|
|
layout_mode = 1
|
|
theme_override_constants/separation = 16
|
|
size_flags_horizontal = 4
|
|
|
|
[node name="TitleLabel" type="Label" parent="CenterContainer/VBoxContainer"]
|
|
layout_mode = 1
|
|
text = "AGP Game"
|
|
horizontal_alignment = 1
|
|
theme_override_font_sizes/font_size = 72
|
|
|
|
[node name="AuthButtonsRow" type="HBoxContainer" parent="CenterContainer/VBoxContainer"]
|
|
layout_mode = 1
|
|
theme_override_constants/separation = 16
|
|
alignment = 1
|
|
|
|
[node name="LoginButton" type="Button" parent="CenterContainer/VBoxContainer/AuthButtonsRow"]
|
|
layout_mode = 1
|
|
text = "Login"
|
|
size_flags_horizontal = 3
|
|
|
|
[node name="RegisterButton" type="Button" parent="CenterContainer/VBoxContainer/AuthButtonsRow"]
|
|
layout_mode = 1
|
|
text = "Register"
|
|
size_flags_horizontal = 3
|
|
|
|
[node name="AuthPanel" type="PanelContainer" parent="CenterContainer/VBoxContainer"]
|
|
layout_mode = 1
|
|
visible = false
|
|
|
|
[node name="MarginContainer" type="MarginContainer" parent="CenterContainer/VBoxContainer/AuthPanel"]
|
|
layout_mode = 1
|
|
theme_override_constants/margin_left = 24
|
|
theme_override_constants/margin_top = 24
|
|
theme_override_constants/margin_right = 24
|
|
theme_override_constants/margin_bottom = 24
|
|
|
|
[node name="AuthVBox" type="VBoxContainer" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer"]
|
|
layout_mode = 1
|
|
theme_override_constants/separation = 8
|
|
size_flags_horizontal = 3
|
|
|
|
[node name="AuthModeLabel" type="Label" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
layout_mode = 1
|
|
text = "Login"
|
|
horizontal_alignment = 1
|
|
theme_override_font_sizes/font_size = 24
|
|
|
|
[node name="UsernameEdit" type="LineEdit" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
layout_mode = 1
|
|
placeholder_text = "Username"
|
|
size_flags_horizontal = 3
|
|
|
|
[node name="PasswordEdit" type="LineEdit" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
layout_mode = 1
|
|
placeholder_text = "Password"
|
|
size_flags_horizontal = 3
|
|
echo_password = true
|
|
|
|
[node name="EmailEdit" type="LineEdit" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
layout_mode = 1
|
|
visible = false
|
|
placeholder_text = "Email"
|
|
size_flags_horizontal = 3
|
|
|
|
[node name="DobEdit" type="LineEdit" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
layout_mode = 1
|
|
visible = false
|
|
size_flags_horizontal = 3
|
|
placeholder_text = "Date of birth (YYYY-MM-DD)"
|
|
|
|
[node name="AuthButton" type="Button" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
layout_mode = 1
|
|
text = "Login"
|
|
size_flags_horizontal = 3
|
|
|
|
[node name="AuthStatusLabel" type="Label" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
layout_mode = 1
|
|
text = ""
|
|
horizontal_alignment = 1
|
|
autowrap_mode = 2
|
|
visible = false
|
|
|
|
[node name="WelcomeLabel" type="Label" parent="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox"]
|
|
layout_mode = 1
|
|
visible = false
|
|
text = ""
|
|
horizontal_alignment = 1
|
|
|
|
[node name="PlayButton" type="Button" parent="CenterContainer/VBoxContainer"]
|
|
layout_mode = 1
|
|
text = "Play"
|
|
size_flags_horizontal = 4
|
|
|
|
[node name="CustomizeButton" type="Button" parent="CenterContainer/VBoxContainer"]
|
|
layout_mode = 1
|
|
text = "Customize Avatar"
|
|
size_flags_horizontal = 4
|
|
disabled = true
|
|
|
|
[node name="QuitButton" type="Button" parent="CenterContainer/VBoxContainer"]
|
|
layout_mode = 1
|
|
text = "Quit"
|
|
size_flags_horizontal = 4
|
|
|
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/AuthButtonsRow/LoginButton" to="." method="_on_login_button_pressed"]
|
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/AuthButtonsRow/RegisterButton" to="." method="_on_register_button_pressed"]
|
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/PlayButton" to="." method="_on_play_button_pressed"]
|
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/CustomizeButton" to="." method="_on_customize_button_pressed"]
|
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/QuitButton" to="." method="_on_quit_button_pressed"]
|
|
[connection signal="pressed" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton" to="." method="_on_auth_button_pressed"]
|
|
[connection signal="text_submitted" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/UsernameEdit" to="." method="_on_auth_button_pressed"]
|
|
[connection signal="text_submitted" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/PasswordEdit" to="." method="_on_auth_button_pressed"]
|