mirror of
https://github.com/InstanceBrick/nightcap.git
synced 2026-10-18 03:01:03 +02:00
243 lines
8.4 KiB
Bash
Executable File
243 lines
8.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Copyright 2026 Mocktail Project Authors
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# Validates an authenticated public-place readiness log. Marker matches can
|
|
# contain account, game, ticket, server, or address data, so this script never
|
|
# prints matching lines or caller-provided values.
|
|
|
|
set -euo pipefail
|
|
|
|
if [[ "$#" -ne 3 || "$1" != "validate" ]]; then
|
|
echo "usage: $0 validate EXPECTED_PLACE_ID PRIVATE_NETWORK_LOG" >&2
|
|
exit 2
|
|
fi
|
|
|
|
EXPECTED_PLACE_ID="$2"
|
|
LOG="$3"
|
|
if [[ ! "${EXPECTED_PLACE_ID}" =~ ^[1-9][0-9]{0,18}$ ]] ||
|
|
{ [[ "${#EXPECTED_PLACE_ID}" -eq 19 ]] &&
|
|
[[ "${EXPECTED_PLACE_ID}" > "9223372036854775807" ]]; }; then
|
|
echo "NETWORK readiness requires a positive signed 64-bit expected place" >&2
|
|
exit 2
|
|
fi
|
|
if [[ ! -f "${LOG}" || -L "${LOG}" || ! -r "${LOG}" ]]; then
|
|
echo "NETWORK readiness requires a private regular log" >&2
|
|
exit 2
|
|
fi
|
|
network_log_mode="$(stat -c '%a' -- "${LOG}" 2>/dev/null || true)"
|
|
if [[ "${network_log_mode}" != "600" ]]; then
|
|
echo "NETWORK readiness raw log must have mode 0600" >&2
|
|
exit 1
|
|
fi
|
|
|
|
network_failed=0
|
|
network_previous_line=0
|
|
|
|
NetworkRequireFixed() {
|
|
local label="$1"
|
|
local marker="$2"
|
|
if ! rg --fixed-strings --quiet -- "${marker}" "${LOG}"; then
|
|
echo "NETWORK readiness marker missing: ${label}" >&2
|
|
network_failed=1
|
|
fi
|
|
}
|
|
|
|
NetworkRequireRegex() {
|
|
local label="$1"
|
|
local marker="$2"
|
|
if ! rg --quiet -- "${marker}" "${LOG}"; then
|
|
echo "NETWORK readiness marker missing: ${label}" >&2
|
|
network_failed=1
|
|
fi
|
|
}
|
|
|
|
NetworkOrderedFixed() {
|
|
local label="$1"
|
|
local marker="$2"
|
|
local marker_line
|
|
marker_line="$(
|
|
rg --fixed-strings --line-number -- "${marker}" "${LOG}" \
|
|
| awk -F: -v previous="${network_previous_line}" \
|
|
'$1 > previous && !found { print $1; found = 1 }' \
|
|
|| true
|
|
)"
|
|
if [[ -z "${marker_line}" ]]; then
|
|
echo "NETWORK readiness order violation: ${label}" >&2
|
|
network_failed=1
|
|
return
|
|
fi
|
|
network_previous_line="${marker_line}"
|
|
}
|
|
|
|
NetworkOrderedRegex() {
|
|
local label="$1"
|
|
local marker="$2"
|
|
local marker_line
|
|
marker_line="$(
|
|
rg --line-number -- "${marker}" "${LOG}" \
|
|
| awk -F: -v previous="${network_previous_line}" \
|
|
'$1 > previous && !found { print $1; found = 1 }' \
|
|
|| true
|
|
)"
|
|
if [[ -z "${marker_line}" ]]; then
|
|
echo "NETWORK readiness order violation: ${label}" >&2
|
|
network_failed=1
|
|
return
|
|
fi
|
|
network_previous_line="${marker_line}"
|
|
}
|
|
|
|
NetworkForbidRegex() {
|
|
local label="$1"
|
|
local marker="$2"
|
|
if rg --ignore-case --quiet -- "${marker}" "${LOG}"; then
|
|
echo "NETWORK readiness forbidden marker detected: ${label}" >&2
|
|
network_failed=1
|
|
fi
|
|
}
|
|
|
|
NetworkRequireRegex \
|
|
"supported exact Build-ID profile" \
|
|
'^[[:space:]]+\[compat\] Roblox [^[:space:]]+ Build ID [0-9a-f]{40} \(supported\)$'
|
|
NetworkRequireFixed \
|
|
"legacy binary patches disabled" \
|
|
"[compat] legacy binary patches: disabled"
|
|
NetworkRequireFixed \
|
|
"signal recovery disabled" \
|
|
"[compat] signal-recovery handler disabled"
|
|
NetworkRequireFixed \
|
|
"native allocator retained" \
|
|
"[compat] native allocator retained; host allocator bridges disabled"
|
|
|
|
NetworkForbidRegex \
|
|
"guest or rejected typed authentication" \
|
|
'\[auth\] explicit guest identity selected|Typed Roblox authentication preflight failed|authentication rejected|authentication service unavailable'
|
|
NetworkForbidRegex \
|
|
"legacy crash recovery" \
|
|
'^[[:space:]]*\[patch\]|recovered from (crash|SIG)|startup path cannot continue'
|
|
NetworkForbidRegex \
|
|
"fatal process failure" \
|
|
'\[FATAL\]|Segmentation fault|core dumped'
|
|
NetworkForbidRegex \
|
|
"synthetic game-loaded event" \
|
|
'nativeAppBridgeV2SendAppEventOnGameLoaded'
|
|
NetworkForbidRegex \
|
|
"invalid initial game resume" \
|
|
'nativeAppBridgeV2ResumeGameWithPlatformParams after StartGame'
|
|
NetworkForbidRegex \
|
|
"credential material in log" \
|
|
'\.ROBLOSECURITY|_\|WARNING:-DO-NOT-SHARE-THIS|Authorization:[[:space:]]*Bearer|authenticationTicket'
|
|
NetworkForbidRegex \
|
|
"remote attestation timeout (disconnect 319)" \
|
|
'Disconnect reason received:[[:space:]]*319([^0-9]|$)|Disconnection Notification\.[[:space:]]*Reason:[[:space:]]*319([^0-9]|$)'
|
|
NetworkForbidRegex \
|
|
"remote attestation integrity rejection" \
|
|
'Roblox was not able to verify the integrity of the game|This place (has enabled additional hardware security requirements|requires a trusted operating system)'
|
|
|
|
NetworkOrderedFixed \
|
|
"typed authenticated identity" \
|
|
"[auth] typed Roblox identity resolved for production VM"
|
|
NetworkOrderedRegex \
|
|
"StartGame dispatch" \
|
|
'^[[:space:]]+\[engine\] nativeAppBridgeV2StartGameWithParam$'
|
|
NetworkOrderedFixed "UGCGame stage" "setStage: (stage:UGCGame)"
|
|
network_ugc_game_line="${network_previous_line}"
|
|
NetworkOrderedFixed \
|
|
"typed game lifecycle running" \
|
|
"[game-session] typed lifecycle startup completed: Running"
|
|
NetworkOrderedRegex \
|
|
"public-place join dispatch" \
|
|
"\\[FLog::Output\\] ! Joining game '[^']+' place ${EXPECTED_PLACE_ID} at [^[:space:]]+"
|
|
NetworkOrderedRegex \
|
|
"accepted server connection" \
|
|
'\[DFLog::NetworkClient\] Connection accepted from [^[:space:]]+'
|
|
NetworkOrderedRegex \
|
|
"player replicator created" \
|
|
'\[FLog::Network\] Replicator created for player [^[:space:]]+'
|
|
NetworkOrderedRegex \
|
|
"replication schema initialized" \
|
|
'\[FLog::Network\] Time taken to initialize schema = [0-9]+(\.[0-9]+)? ms'
|
|
NetworkOrderedRegex \
|
|
"real game-loaded callback" \
|
|
"\\[D/rbx\\.jni\\] onGameLoaded\\(\\) SessionReporterState_GameLoaded placeId:${EXPECTED_PLACE_ID}([^0-9]|$)"
|
|
network_game_loaded_line="${network_previous_line}"
|
|
|
|
# Graphics and network startup run concurrently after UGCGame. A first frame
|
|
# may be presented while the server connection is still being accepted, so do
|
|
# not impose a false ordering between the two branches. Both branches must
|
|
# complete before teardown starts.
|
|
network_previous_line="${network_ugc_game_line}"
|
|
NetworkOrderedFixed \
|
|
"first real Vulkan frame" \
|
|
"[window] first Roblox Vulkan frame presented"
|
|
NetworkOrderedRegex \
|
|
"Vulkan queue present" \
|
|
'^[[:space:]]+\[window\] vkQueuePresentKHR #[1-9][0-9]* '
|
|
network_vulkan_present_line="${network_previous_line}"
|
|
|
|
network_previous_line="${network_game_loaded_line}"
|
|
if ((network_vulkan_present_line > network_previous_line)); then
|
|
network_previous_line="${network_vulkan_present_line}"
|
|
fi
|
|
NetworkOrderedFixed "RenderView destroyed" "RenderView destroyed"
|
|
NetworkOrderedFixed \
|
|
"Vulkan pipeline cache saved" \
|
|
"Vulkan: Saved pipeline cache"
|
|
NetworkOrderedFixed \
|
|
"SDL WSI adapter stopped" \
|
|
"[vulkan] SDL WSI adapter shut down"
|
|
NetworkOrderedFixed \
|
|
"controlled network disconnect" \
|
|
"[DFLog::NetworkClient] Client:Disconnect"
|
|
NetworkOrderedFixed \
|
|
"replication disconnect completed" \
|
|
"Time to disconnect replication data:"
|
|
NetworkOrderedFixed "NetworkClient removed" "NetworkClient:Remove"
|
|
NetworkOrderedFixed \
|
|
"MegaReplicator destroyed" \
|
|
"Destroying MegaReplicator."
|
|
NetworkOrderedFixed \
|
|
"UGC controller finalized" \
|
|
"UgcExperienceController: finalized"
|
|
NetworkOrderedFixed "Replicator destroyed" "Replicator destroyed:"
|
|
NetworkOrderedFixed "stage cleared" "setStage: (stage:None)"
|
|
NetworkOrderedFixed \
|
|
"lifecycle stopped" \
|
|
"[main] Roblox lifecycle shutdown: Stopped"
|
|
|
|
early_update_line="$(
|
|
rg --fixed-strings --line-number \
|
|
"nativeAppBridgeV2UpdateSurfaceGameWithPlatformParams" "${LOG}" \
|
|
| awk -F: -v ugc="${network_ugc_game_line:-0}" \
|
|
'$1 < ugc && !found { print $1; found = 1 }' \
|
|
|| true
|
|
)"
|
|
if [[ -n "${early_update_line}" ]]; then
|
|
echo "NETWORK readiness updated the game surface before UGCGame" >&2
|
|
network_failed=1
|
|
fi
|
|
|
|
if [[ -n "${network_game_loaded_line:-}" ]]; then
|
|
terminal_join_failure_line="$(
|
|
rg --ignore-case --line-number -- \
|
|
'ClientJoinFail|Error processing ticket|Lost connection to the game server|Error_ConnectionAttemptFailed|JoinGamePlaceLauncher-FailureStatus|UgcExperienceController:.*failed to parse' \
|
|
"${LOG}" \
|
|
| awk -F: -v loaded="${network_game_loaded_line}" \
|
|
'$1 < loaded && !found { print $1; found = 1 }' \
|
|
|| true
|
|
)"
|
|
if [[ -n "${terminal_join_failure_line}" ]]; then
|
|
echo "NETWORK readiness observed a terminal join failure before game load" >&2
|
|
network_failed=1
|
|
fi
|
|
fi
|
|
|
|
if [[ "${network_failed}" -ne 0 ]]; then
|
|
exit 1
|
|
fi
|
|
|
|
echo "NETWORK readiness passed: authenticated join, replication, Vulkan present, and clean shutdown"
|