diff --git a/CMakeLists.txt b/CMakeLists.txt index 052c394..fe23ca3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -410,9 +410,6 @@ target_link_libraries(mocktail_auth_runtime_composition PUBLIC mocktail_runtime mocktail_services ) -target_link_libraries(mocktail_auth_runtime_composition PRIVATE - Mocktail::CryptoFoundation -) mocktail_apply_compile_options(mocktail_auth_runtime_composition) add_library(mocktail_linker STATIC diff --git a/include/runtime/auth_runtime_composition.h b/include/runtime/auth_runtime_composition.h index 8824e94..5656206 100644 --- a/include/runtime/auth_runtime_composition.h +++ b/include/runtime/auth_runtime_composition.h @@ -101,8 +101,7 @@ struct AuthRuntimeComposition { }; // A VM requires authentication or explicit guest mode. HTTP 401/403 clears -// only a managed credential; rejected Sober credentials are suppressed -// without changing Sober's file. +// only Mocktail's managed credential. AuthRuntimeComposition ComposeAuthRuntime(const Environment& environment, const RuntimePaths& paths, services::AuthService& auth_service); diff --git a/include/runtime/runtime_paths.h b/include/runtime/runtime_paths.h index 7f7b68c..0dc3c85 100644 --- a/include/runtime/runtime_paths.h +++ b/include/runtime/runtime_paths.h @@ -81,12 +81,6 @@ class RuntimePaths { return active_payload_manifest_; } const std::filesystem::path& cookie_file() const { return cookie_file_; } - const std::filesystem::path& sober_cookie_file() const { - return sober_cookie_file_; - } - const std::filesystem::path& default_sober_rejection_file() const { - return default_sober_rejection_file_; - } bool use_real_sober_paths() const { return use_real_sober_paths_; } std::filesystem::path DefaultAssetPath() const; @@ -119,8 +113,6 @@ class RuntimePaths { std::filesystem::path config_file_; std::filesystem::path active_payload_manifest_; std::filesystem::path cookie_file_; - std::filesystem::path sober_cookie_file_; - std::filesystem::path default_sober_rejection_file_; bool use_real_sober_paths_ = false; }; diff --git a/scripts/auto_update_roblox.sh b/scripts/auto_update_roblox.sh index 869b85d..7ecd4b5 100755 --- a/scripts/auto_update_roblox.sh +++ b/scripts/auto_update_roblox.sh @@ -894,7 +894,6 @@ RunCandidateCanary() { MOCKTAIL_SKIP_UPDATE_CHECK=1 \ MOCKTAIL_ISOLATED_CANARY=1 \ MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP=1 \ - MOCKTAIL_USE_SOBER_COOKIES=0 \ MOCKTAIL_IGNORE_WINDOW_CLOSE=1 \ MOCKTAIL_DISABLE_SUPPORT_BUNDLE=1 \ MOCKTAIL_AUTO_EXIT_AFTER_PRESENT_MS=5000 \ diff --git a/scripts/real_bringup_smoke.sh b/scripts/real_bringup_smoke.sh index beccfc3..6ff77a8 100755 --- a/scripts/real_bringup_smoke.sh +++ b/scripts/real_bringup_smoke.sh @@ -115,9 +115,7 @@ if [[ "${MOCKTAIL_ISOLATED_CANARY:-0}" == 1 ]]; then # rendering, and controlled lifecycle/audio shutdown. unset MOCKTAIL_COOKIE_FILE MOCKTAIL_ROBLOX_COOKIES export MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP=1 - export MOCKTAIL_USE_SOBER_COOKIES=0 else - export MOCKTAIL_COOKIE_FILE="${MOCKTAIL_COOKIE_FILE:-$HOME/.var/app/org.vinegarhq.Sober/data/sober/cookies}" fi export MOCKTAIL_ENGINE_DETACH="${MOCKTAIL_ENGINE_DETACH:-0}" export MOCKTAIL_CALL_REAL_APP_BRIDGE_INIT="${MOCKTAIL_CALL_REAL_APP_BRIDGE_INIT:-1}" diff --git a/src/jnivm/jnivm.cc b/src/jnivm/jnivm.cc index 86de5ec..5e64600 100644 --- a/src/jnivm/jnivm.cc +++ b/src/jnivm/jnivm.cc @@ -1103,14 +1103,6 @@ std::string MocktailConfigRoot() { return HomePath("/.config/mocktail"); } -std::string SoberDataRoot() { - const char* root = std::getenv("MOCKTAIL_SOBER_DATA_ROOT"); - if (root && root[0] != '\0') { - return root; - } - return HomePath("/.var/app/org.vinegarhq.Sober/data/sober"); -} - void EnsureCookieStoreLoadedLocked() { if (g_cookie_store_loaded) { return; @@ -1129,10 +1121,6 @@ void EnsureCookieStoreLoadedLocked() { g_cookie_header = NormalizeCookieHeader(ReadTextFile(MocktailConfigRoot() + "/cookie")); } - if (g_cookie_header.empty()) { - g_cookie_header = - NormalizeCookieHeader(ReadTextFile(SoberDataRoot() + "/cookies")); - } if (TraceEnabled()) { std::cout << " [JNI] cookie store loaded bytes=" << g_cookie_header.size() << '\n'; diff --git a/src/legacy/legacy_runtime.cc b/src/legacy/legacy_runtime.cc index c536989..52a319f 100644 --- a/src/legacy/legacy_runtime.cc +++ b/src/legacy/legacy_runtime.cc @@ -28793,11 +28793,6 @@ std::string MocktailCookiePath() { return MocktailConfigRoot() + "/cookie"; } -std::string SoberCookiePath() { - return GetEnvString("MOCKTAIL_SOBER_COOKIE_FILE", - (SoberDataRoot() + "/cookies").c_str()); -} - bool CookieHasAttribute(const std::string& cookie, const char* attribute) { std::string lower_cookie = cookie; std::string lower_attribute = attribute ? attribute : ""; @@ -29583,9 +29578,8 @@ void ConfigureNativeSettings(JNIEnv* env, jclass settings_class, std::cout << " [engine] no Roblox cookie found; proceeding without login\n" << std::flush; } else { - std::cout << " [engine] WARNING: no Roblox cookie found; checked " - << MocktailCookiePath() << " and " << SoberCookiePath() - << '\n' + std::cout << " [engine] WARNING: no Roblox cookie found at " + << MocktailCookiePath() << '\n' << std::flush; } std::string android_id = diff --git a/src/main.cc b/src/main.cc index 1392472..011d833 100644 --- a/src/main.cc +++ b/src/main.cc @@ -657,10 +657,6 @@ int main(int argc, char* argv[]) { tracker_cookie_owned = false; } else if (mocktail::runtime::RuntimePaths::Exists(paths.cookie_file())) { tracker_cookie_file = paths.cookie_file(); - } else if (mocktail::runtime::RuntimePaths::Exists( - paths.sober_cookie_file())) { - tracker_cookie_file = paths.sober_cookie_file(); - tracker_cookie_owned = false; } const mocktail::services::BrowserTrackerResult browser_tracker_result = browser_tracker.EnsureInitialized(app_storage_file, tracker_cookie_file, diff --git a/src/runtime/auth_runtime_composition.cc b/src/runtime/auth_runtime_composition.cc index 265d05f..5233da3 100644 --- a/src/runtime/auth_runtime_composition.cc +++ b/src/runtime/auth_runtime_composition.cc @@ -35,7 +35,6 @@ #include #include "jnivm/jnivm.h" -#include "mocktail/sha256.h" #include "runtime/environment.h" #include "runtime/runtime_paths.h" #include "services/auth_service.h" @@ -45,8 +44,6 @@ namespace runtime { namespace { constexpr uintmax_t kMaximumCookieFileBytes = 1024 * 1024; -constexpr std::string_view kSoberRejectionMarkerPrefix = "v1:"; -constexpr char kSoberRejectionDomain[] = "mocktail-default-sober-rejection-v1"; enum class CookieLoadStatus { kFound, @@ -59,7 +56,6 @@ enum class CookieSource { kEnvironment, kExplicitFile, kManagedFile, - kSoberFile, }; struct CookieLoadResult { @@ -315,34 +311,6 @@ bool WritePrivateFileAtomically(const std::filesystem::path& path, FsyncDirectoryChain(first_created_parent, existing_ancestor); } -std::string BuildSoberRejectionMarker(std::string_view rejected_value) { - foundation::Sha256 sha256; - sha256.Update(reinterpret_cast(kSoberRejectionDomain), - sizeof(kSoberRejectionDomain)); - sha256.Update(rejected_value); - std::string marker(kSoberRejectionMarkerPrefix); - marker += sha256.FinalHex(); - marker.push_back('\n'); - return marker; -} - -bool IsValidSoberRejectionMarker(std::string_view marker) { - constexpr size_t kSha256HexBytes = 64; - if (marker.size() != - kSoberRejectionMarkerPrefix.size() + kSha256HexBytes + 1 || - marker.compare(0, kSoberRejectionMarkerPrefix.size(), - kSoberRejectionMarkerPrefix) != 0 || - marker.back() != '\n') { - return false; - } - const std::string_view digest = - marker.substr(kSoberRejectionMarkerPrefix.size(), kSha256HexBytes); - return std::all_of(digest.begin(), digest.end(), [](char character) { - return (character >= '0' && character <= '9') || - (character >= 'a' && character <= 'f'); - }); -} - bool PersistRobloxCredential(void* opaque, const char* data, size_t size) { auto* context = static_cast(opaque); if (context == nullptr || context->path.empty() || data == nullptr || @@ -517,90 +485,6 @@ CookieLoadResult ReadCookieSource(const std::filesystem::path& path, return result; } -enum class SoberRejectionStatus { - kNoMatch, - kMatch, - kUnavailable, -}; - -struct SoberRejectionResult { - SoberRejectionStatus status = SoberRejectionStatus::kNoMatch; - std::string error; -}; - -SoberRejectionResult CheckSoberRejection(const RuntimePaths& paths, - std::string_view cookie_contents) { - std::string cookie_value = - services::AuthService::ExtractRoblosecurityValue(cookie_contents); - if (cookie_value.empty()) { - return {}; - } - - struct stat auth_root_status = {}; - if (lstat(paths.auth_root().c_str(), &auth_root_status) != 0) { - ClearSensitiveString(&cookie_value); - if (errno == ENOENT) { - return {}; - } - return {SoberRejectionStatus::kUnavailable, - "saved Sober rejection marker storage is unavailable"}; - } - if (!S_ISDIR(auth_root_status.st_mode) || S_ISLNK(auth_root_status.st_mode) || - auth_root_status.st_uid != geteuid() || - (auth_root_status.st_mode & (S_IRWXG | S_IRWXO)) != 0) { - ClearSensitiveString(&cookie_value); - return {SoberRejectionStatus::kUnavailable, - "saved Sober rejection marker storage is unsafe"}; - } - const std::filesystem::path& marker_path = - paths.default_sober_rejection_file(); - struct stat marker_status = {}; - if (lstat(marker_path.c_str(), &marker_status) != 0) { - ClearSensitiveString(&cookie_value); - if (errno == ENOENT) { - return {}; - } - return {SoberRejectionStatus::kUnavailable, - "saved Sober rejection marker is unavailable"}; - } - CookieLoadResult marker = ReadCookieFile(marker_path, true); - if (marker.status != CookieLoadStatus::kFound || - !IsValidSoberRejectionMarker(marker.value)) { - ClearSensitiveString(&cookie_value); - ClearSensitiveString(&marker.value); - return {SoberRejectionStatus::kUnavailable, - "saved Sober rejection marker is invalid"}; - } - - const std::string expected = BuildSoberRejectionMarker(cookie_value); - ClearSensitiveString(&cookie_value); - const bool matches = marker.value == expected; - ClearSensitiveString(&marker.value); - return { - matches ? SoberRejectionStatus::kMatch : SoberRejectionStatus::kNoMatch, - {}}; -} - -bool PersistSoberRejection(const RuntimePaths& paths, - std::string_view rejected_value, - std::string* error) { - if (rejected_value.empty()) { - if (error != nullptr) { - *error = "rejected Sober credential could not be identified safely"; - } - return false; - } - const std::string marker = BuildSoberRejectionMarker(rejected_value); - if (!WritePrivateFileAtomically(paths.default_sober_rejection_file(), - marker)) { - if (error != nullptr) { - *error = "rejected Sober credential could not be retired safely"; - } - return false; - } - return true; -} - bool ReadDescriptorContents(int descriptor, std::string* contents) { if (contents == nullptr || lseek(descriptor, 0, SEEK_SET) < 0) { return false; @@ -633,8 +517,7 @@ bool ReadDescriptorContents(int descriptor, std::string* contents) { } bool IsAutomaticallyRecoverableSource(CookieSource source) { - return source == CookieSource::kManagedFile || - source == CookieSource::kSoberFile; + return source == CookieSource::kManagedFile; } bool IsCookieFileDelimiter(char character) { @@ -680,7 +563,6 @@ std::vector FindCookieRedactionRanges( bool ClearRejectedCookieFile(const std::filesystem::path& path, std::string_view loaded_contents, - const std::filesystem::path& protected_cookie_path, std::string* error) { const std::filesystem::path parent = path.parent_path().empty() ? std::filesystem::path(".") @@ -741,13 +623,6 @@ bool ClearRejectedCookieFile(const std::filesystem::path& path, return fail("rejected Roblox cookie could not be identified safely"); } - struct stat protected_metadata = {}; - bool protected_exists = false; - if (stat(protected_cookie_path.c_str(), &protected_metadata) == 0) { - protected_exists = true; - } else if (errno != ENOENT) { - return fail("protected Sober cookie identity could not be checked"); - } const auto source_metadata_error = [&](const struct stat& metadata) { if (!S_ISREG(metadata.st_mode) || metadata.st_uid != geteuid() || (metadata.st_mode & (S_IRWXG | S_IRWXO)) != 0 || metadata.st_size < 0 || @@ -756,10 +631,6 @@ bool ClearRejectedCookieFile(const std::filesystem::path& path, "Roblox cookie changed while authentication was " "checked"); } - if (protected_exists && SameFile(protected_metadata, metadata)) { - return std::string( - "managed Roblox cookie aliases the protected Sober file"); - } if (metadata.st_nlink != 1) { return std::string("managed Roblox cookie has unexpected hard links"); } @@ -821,14 +692,6 @@ bool ClearRejectedCookieFile(const std::filesystem::path& path, !SameFile(path_metadata, source_metadata)) { return fail("Roblox cookie changed while authentication was checked"); } - struct stat current_protected_metadata = {}; - if (stat(protected_cookie_path.c_str(), ¤t_protected_metadata) == 0) { - if (SameFile(current_protected_metadata, source_metadata)) { - return fail("managed Roblox cookie aliases the protected Sober file"); - } - } else if (errno != ENOENT) { - return fail("protected Sober cookie identity could not be checked"); - } struct stat prewrite_metadata = {}; if (fstat(source.get(), &prewrite_metadata) != 0 || !SameFileVersion(source_metadata, prewrite_metadata) || @@ -901,26 +764,6 @@ CookieLoadResult LoadSavedCookie(const Environment& environment, } else if (result.status != CookieLoadStatus::kMissing) { return result; } - if (Enabled(environment, "MOCKTAIL_USE_SOBER_COOKIES", true)) { - const CookieSource sober_source = - environment.HasNonEmpty("MOCKTAIL_SOBER_COOKIE_FILE") - ? CookieSource::kExplicitFile - : CookieSource::kSoberFile; - result = ReadCookieSource(paths.sober_cookie_file(), false, sober_source); - if (result.status == CookieLoadStatus::kFound && - sober_source == CookieSource::kSoberFile) { - const SoberRejectionResult rejection = - CheckSoberRejection(paths, result.value); - if (rejection.status == SoberRejectionStatus::kUnavailable) { - ClearSensitiveString(&result.value); - result.status = CookieLoadStatus::kUnavailable; - result.error = rejection.error; - } else if (rejection.status == SoberRejectionStatus::kMatch) { - ClearSensitiveString(&result.value); - result = {}; - } - } - } return result; } @@ -1031,29 +874,11 @@ AuthRuntimeComposition ComposeAuthRuntime( if (session.status == services::AuthSessionStatus::kInvalid && (session.http_status == 401 || session.http_status == 403) && IsAutomaticallyRecoverableSource(cookie.source)) { - std::string rejected_value = - services::AuthService::ExtractRoblosecurityValue(cookie.value); std::string reset_error; - const bool default_sober_fallback = - Enabled(environment, "MOCKTAIL_USE_SOBER_COOKIES", true) && - !environment.HasNonEmpty("MOCKTAIL_SOBER_COOKIE_FILE"); - if ((cookie.source == CookieSource::kSoberFile || - (cookie.source == CookieSource::kManagedFile && - default_sober_fallback)) && - !PersistSoberRejection(paths, rejected_value, &reset_error)) { - ClearSensitiveString(&cookie.value); - ClearSensitiveString(&rejected_value); - credential.Clear(); - composition.status = AuthRuntimeStatus::kUnavailable; - composition.http_status = session.http_status; - composition.error = std::move(reset_error); - return composition; - } if (cookie.source == CookieSource::kManagedFile && !ClearRejectedCookieFile(cookie.source_path, cookie.value, - paths.sober_cookie_file(), &reset_error)) { + &reset_error)) { ClearSensitiveString(&cookie.value); - ClearSensitiveString(&rejected_value); credential.Clear(); composition.status = AuthRuntimeStatus::kUnavailable; composition.http_status = session.http_status; @@ -1061,7 +886,6 @@ AuthRuntimeComposition ComposeAuthRuntime( return composition; } ClearSensitiveString(&cookie.value); - ClearSensitiveString(&rejected_value); credential.Clear(); composition.rejected_credential_retired = true; if (!allow_guest) { diff --git a/src/runtime/runtime_paths.cc b/src/runtime/runtime_paths.cc index 5c9e01c..1289472 100644 --- a/src/runtime/runtime_paths.cc +++ b/src/runtime/runtime_paths.cc @@ -358,13 +358,6 @@ RuntimePaths RuntimePaths::FromEnvironment( paths.active_payload_manifest_ = paths.data_root_ / "current.json"; paths.cookie_file_ = paths.auth_root_ / "roblox.cookie"; - paths.default_sober_rejection_file_ = - paths.auth_root_ / "default-sober-rejection"; - paths.sober_cookie_file_ = - environment.HasNonEmpty("MOCKTAIL_SOBER_COOKIE_FILE") - ? std::filesystem::path( - environment.GetOr("MOCKTAIL_SOBER_COOKIE_FILE", "")) - : paths.sober_data_root_ / "cookies"; paths.use_real_sober_paths_ = LegacyEnabled(environment, "MOCKTAIL_USE_REAL_SOBER_PATHS"); return paths; diff --git a/src/update/readiness_canary.cc b/src/update/readiness_canary.cc index 99c1b31..9ba1de8 100644 --- a/src/update/readiness_canary.cc +++ b/src/update/readiness_canary.cc @@ -352,7 +352,6 @@ CanaryResult RunReadinessCanary(const CanaryOptions& options) { "MOCKTAIL_SKIP_UPDATE_CHECK=1", "MOCKTAIL_ISOLATED_CANARY=1", "MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP=1", - "MOCKTAIL_USE_SOBER_COOKIES=0", "MOCKTAIL_VALIDATE_ROBLOX_COOKIE=0", "MOCKTAIL_IGNORE_WINDOW_CLOSE=1", "MOCKTAIL_DISABLE_SUPPORT_BUNDLE=1", diff --git a/tests/auth_runtime_composition_test.cc b/tests/auth_runtime_composition_test.cc index 5ed3eb6..f9e1664 100644 --- a/tests/auth_runtime_composition_test.cc +++ b/tests/auth_runtime_composition_test.cc @@ -35,7 +35,6 @@ #include "jnivm/jnivm.h" #include "legacy/legacy_runtime.h" -#include "mocktail/sha256.h" #include "runtime/environment.h" #include "runtime/runtime_paths.h" #include "services/auth_service.h" @@ -138,17 +137,6 @@ RuntimePaths PathsFor(const MapEnvironment& environment, return RuntimePaths::FromEnvironment(environment, directory.path()); } -std::filesystem::path SoberRejectionPathFor(const RuntimePaths& paths) { - return paths.default_sober_rejection_file(); -} - -std::string SoberRejectionMarkerFor(std::string_view credential) { - constexpr char kDomain[] = "mocktail-default-sober-rejection-v1"; - std::string fingerprint_input(kDomain, sizeof(kDomain)); - fingerprint_input.append(credential); - return "v1:" + foundation::ComputeSha256Hex(fingerprint_input) + "\n"; -} - std::string ReadJavaString(JNIEnv* env, jstring value) { if (env == nullptr || value == nullptr) { return {}; @@ -219,11 +207,14 @@ TEST(AuthRuntimeCompositionTest, EXPECT_EQ(identity.display_name.find(kCredential), std::string::npos); } -TEST(AuthRuntimeCompositionTest, MissingCookieRequiresExplicitGuestPolicy) { +TEST(AuthRuntimeCompositionTest, SoberCookieIsIgnoredAndGuestPolicyRequired) { TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); + ASSERT_TRUE(WriteFile( + directory.path() / + ".var/app/org.vinegarhq.Sober/data/sober/cookies", + std::string(".ROBLOSECURITY=") + kCredential + "\n")); FakeHttpClient http; services::AuthService auth_service(http); @@ -254,7 +245,6 @@ TEST(AuthRuntimeCompositionTest, TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); FakeHttpClient http; @@ -315,7 +305,6 @@ TEST(AuthRuntimeCompositionTest, TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); auto http = std::make_shared(); @@ -360,7 +349,6 @@ TEST(AuthRuntimeCompositionTest, TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); FakeHttpClient initial_http; @@ -408,7 +396,6 @@ TEST(AuthRuntimeCompositionTest, MapEnvironment restart_environment; restart_environment.Set("HOME", directory.path().string()); - restart_environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); FakeHttpClient restart_http; restart_http.response = { true, @@ -457,7 +444,6 @@ TEST(AuthRuntimeCompositionTest, TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); const std::string remaining_cookies = @@ -498,406 +484,11 @@ TEST(AuthRuntimeCompositionTest, EXPECT_EQ(restart_http.request_count, 0); } -TEST(AuthRuntimeCompositionTest, - Http401ClearsManagedAndSuppressesMatchingDefaultSoberCredential) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string rejected_cookie = - std::string(".ROBLOSECURITY=") + kCredential; - const std::string managed_other = "ManagedCookie=keep\n"; - const std::string sober_other = "SoberCookie=keep\n"; - ASSERT_TRUE( - WriteFile(paths.cookie_file(), rejected_cookie + "\n" + managed_other)); - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), - rejected_cookie + "\n" + sober_other)); - FakeHttpClient http; - http.response = {true, 401, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - ASSERT_TRUE(composition) << composition.error; - EXPECT_EQ(composition.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(http.request_count, 1); - const std::string redacted_prefix(rejected_cookie.size(), ' '); - EXPECT_EQ(ReadFile(paths.cookie_file()), - redacted_prefix + "\n" + managed_other); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), - rejected_cookie + "\n" + sober_other); - const std::filesystem::path rejection_path = SoberRejectionPathFor(paths); - const std::string marker = ReadFile(rejection_path); - EXPECT_EQ(marker.size(), 68U); - EXPECT_EQ(marker.rfind("v1:", 0), 0U); - EXPECT_EQ(marker.find(kCredential), std::string::npos); - struct stat marker_metadata = {}; - ASSERT_EQ(lstat(rejection_path.c_str(), &marker_metadata), 0); - EXPECT_TRUE(S_ISREG(marker_metadata.st_mode)); - EXPECT_EQ(marker_metadata.st_mode & (S_IRWXG | S_IRWXO), 0U); - - FakeHttpClient restart_http; - services::AuthService restart_auth_service(restart_http); - const AuthRuntimeComposition restarted = - ComposeAuthRuntime(environment, paths, restart_auth_service); - ASSERT_TRUE(restarted) << restarted.error; - EXPECT_EQ(restarted.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(restart_http.request_count, 0); -} - -TEST(AuthRuntimeCompositionTest, - Http401SuppressesDefaultSoberCredentialWithoutMutatingItsFile) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string remaining_cookies = - "RBXEventTrackerV2=browserid=654321&browserid_insert_timestamp=1\n" - "OtherCookie=keep\n"; - const std::string rejected_cookie = - std::string(".ROBLOSECURITY=") + kCredential; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), - rejected_cookie + "\n" + remaining_cookies)); - FakeHttpClient http; - http.response = {true, 401, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - ASSERT_TRUE(composition) << composition.error; - EXPECT_EQ(composition.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(composition.http_status, 401); - EXPECT_EQ(http.request_count, 1); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), - rejected_cookie + "\n" + remaining_cookies); - EXPECT_FALSE(std::filesystem::exists(paths.cookie_file())); - const std::filesystem::path rejection_path = SoberRejectionPathFor(paths); - EXPECT_EQ(ReadFile(rejection_path).find(kCredential), std::string::npos); - - const std::string changed_tracker_cookies = - rejected_cookie + - "\nRBXEventTrackerV2=browserid=999999&browserid_insert_timestamp=2\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), changed_tracker_cookies)); - FakeHttpClient restart_http; - services::AuthService restart_auth_service(restart_http); - const AuthRuntimeComposition restarted = - ComposeAuthRuntime(environment, paths, restart_auth_service); - ASSERT_TRUE(restarted) << restarted.error; - EXPECT_EQ(restarted.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(restart_http.request_count, 0); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), changed_tracker_cookies); -} - -TEST(AuthRuntimeCompositionTest, - RelativeNestedAuthRootPersistsDefaultSoberRejection) { - TempDirectory directory; - std::error_code error; - const std::filesystem::path current_directory = - std::filesystem::current_path(error); - ASSERT_FALSE(error); - const std::filesystem::path relative_auth_root = std::filesystem::relative( - directory.path() / "relative/auth/root", current_directory, error); - ASSERT_FALSE(error); - ASSERT_FALSE(relative_auth_root.empty()); - ASSERT_FALSE(relative_auth_root.is_absolute()); - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_AUTH_ROOT", relative_auth_root.string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), cookies)); - FakeHttpClient http; - http.response = {true, 401, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - ASSERT_TRUE(composition) << composition.error; - EXPECT_EQ(composition.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(http.request_count, 1); - EXPECT_EQ(ReadFile(paths.default_sober_rejection_file()), - SoberRejectionMarkerFor(kCredential)); - - FakeHttpClient restart_http; - services::AuthService restart_auth_service(restart_http); - const AuthRuntimeComposition restarted = - ComposeAuthRuntime(environment, paths, restart_auth_service); - ASSERT_TRUE(restarted) << restarted.error; - EXPECT_EQ(restarted.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(restart_http.request_count, 0); -} - -TEST(AuthRuntimeCompositionTest, - ChangedDefaultSoberCredentialIsCheckedAndReplacesOldMarker) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string first_cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\nOther=keep\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), first_cookies)); - FakeHttpClient first_http; - first_http.response = {true, 401, {}, {}}; - services::AuthService first_auth_service(first_http); - ASSERT_TRUE(ComposeAuthRuntime(environment, paths, first_auth_service)); - - const std::filesystem::path rejection_path = SoberRejectionPathFor(paths); - const std::string first_marker = ReadFile(rejection_path); - struct stat first_metadata = {}; - ASSERT_EQ(lstat(rejection_path.c_str(), &first_metadata), 0); - - const std::string changed_value = "_|changed-default-sober-credential"; - const std::string changed_cookies = - ".ROBLOSECURITY=" + changed_value + "\nOther=still-keep\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), changed_cookies)); - FakeHttpClient changed_http; - changed_http.response = {true, 401, {}, {}}; - services::AuthService changed_auth_service(changed_http); - - const AuthRuntimeComposition changed = - ComposeAuthRuntime(environment, paths, changed_auth_service); - - ASSERT_TRUE(changed) << changed.error; - EXPECT_EQ(changed.status, AuthRuntimeStatus::kGuest); - ASSERT_EQ(changed_http.request_count, 1); - ASSERT_EQ(changed_http.last_request.headers.size(), 2U); - EXPECT_EQ(changed_http.last_request.headers[1], - "Cookie: .ROBLOSECURITY=" + changed_value); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), changed_cookies); - const std::string changed_marker = ReadFile(rejection_path); - EXPECT_NE(changed_marker, first_marker); - EXPECT_EQ(changed_marker.find(changed_value), std::string::npos); - struct stat changed_metadata = {}; - ASSERT_EQ(lstat(rejection_path.c_str(), &changed_metadata), 0); - EXPECT_NE(changed_metadata.st_ino, first_metadata.st_ino); - - FakeHttpClient restart_http; - services::AuthService restart_auth_service(restart_http); - const AuthRuntimeComposition restarted = - ComposeAuthRuntime(environment, paths, restart_auth_service); - ASSERT_TRUE(restarted) << restarted.error; - EXPECT_EQ(restarted.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(restart_http.request_count, 0); -} - -TEST(AuthRuntimeCompositionTest, - DefaultSoberRefreshDuringHttp401RecoveryIsNeverModified) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), - std::string(".ROBLOSECURITY=") + kCredential + "\n")); - const std::string refreshed_value = "_|refreshed-during-http"; - const std::string refreshed_cookies = - ".ROBLOSECURITY=" + refreshed_value + "\nOther=keep\n"; - FakeHttpClient http; - http.response = {true, 401, {}, {}}; - http.before_response = [&]() { - EXPECT_TRUE(WriteFile(paths.sober_cookie_file(), refreshed_cookies)); - }; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - ASSERT_TRUE(composition) << composition.error; - EXPECT_EQ(composition.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), refreshed_cookies); - - FakeHttpClient restart_http; - restart_http.response = { - true, - 200, - R"({"id":654,"name":"Refreshed","displayName":"Refreshed User"})", - {}}; - services::AuthService restart_auth_service(restart_http); - const AuthRuntimeComposition restarted = - ComposeAuthRuntime(environment, paths, restart_auth_service); - ASSERT_TRUE(restarted) << restarted.error; - EXPECT_EQ(restarted.status, AuthRuntimeStatus::kAuthenticated); - EXPECT_EQ(restart_http.request_count, 1); - ASSERT_EQ(restart_http.last_request.headers.size(), 2U); - EXPECT_EQ(restart_http.last_request.headers[1], - "Cookie: .ROBLOSECURITY=" + refreshed_value); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), refreshed_cookies); -} - -TEST(AuthRuntimeCompositionTest, - MalformedDefaultSoberRejectionMarkerFailsClosedBeforeHttp) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string sober_cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), sober_cookies)); - ASSERT_TRUE(WriteFile(SoberRejectionPathFor(paths), "not-a-valid-marker\n")); - ASSERT_EQ(chmod(paths.auth_root().c_str(), S_IRWXU), 0); - FakeHttpClient http; - http.response = {true, 200, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kUnavailable); - EXPECT_EQ(composition.error, "saved Sober rejection marker is invalid"); - EXPECT_EQ(http.request_count, 0); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), sober_cookies); -} - -TEST(AuthRuntimeCompositionTest, - UnsafeAuthRootWithoutMarkerFailsClosedBeforeHttp) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string sober_cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), sober_cookies)); - std::error_code error; - std::filesystem::create_directories(paths.auth_root(), error); - ASSERT_FALSE(error); - ASSERT_EQ(chmod(paths.auth_root().c_str(), - S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH), - 0); - FakeHttpClient http; - http.response = {true, 200, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kUnavailable); - EXPECT_EQ(composition.error, - "saved Sober rejection marker storage is unsafe"); - EXPECT_EQ(http.request_count, 0); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), sober_cookies); -} - -TEST(AuthRuntimeCompositionTest, - SymlinkDefaultSoberRejectionMarkerFailsClosedWithoutTouchingTarget) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string sober_cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), sober_cookies)); - const std::filesystem::path protected_target = - directory.path() / "protected-marker-target"; - const std::string protected_contents = "must remain untouched\n"; - ASSERT_TRUE(WriteFile(protected_target, protected_contents)); - std::error_code error; - std::filesystem::create_directories(paths.auth_root(), error); - ASSERT_FALSE(error); - ASSERT_EQ(chmod(paths.auth_root().c_str(), S_IRWXU), 0); - std::filesystem::create_symlink(protected_target, - SoberRejectionPathFor(paths), error); - ASSERT_FALSE(error); - FakeHttpClient http; - http.response = {true, 200, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kUnavailable); - EXPECT_EQ(http.request_count, 0); - EXPECT_EQ(ReadFile(protected_target), protected_contents); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), sober_cookies); -} - -TEST(AuthRuntimeCompositionTest, - FifoDefaultSoberRejectionMarkerFailsClosedWithoutBlocking) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string sober_cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), sober_cookies)); - std::error_code error; - std::filesystem::create_directories(paths.auth_root(), error); - ASSERT_FALSE(error); - ASSERT_EQ(chmod(paths.auth_root().c_str(), S_IRWXU), 0); - ASSERT_EQ(mkfifo(SoberRejectionPathFor(paths).c_str(), S_IRUSR | S_IWUSR), 0); - FakeHttpClient http; - http.response = {true, 200, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kUnavailable); - EXPECT_EQ(http.request_count, 0); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), sober_cookies); -} - -TEST(AuthRuntimeCompositionTest, - RejectionWriterLockHardlinkCannotChangeDefaultSoberFile) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string sober_cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), sober_cookies)); - ASSERT_EQ(chmod(paths.sober_cookie_file().c_str(), S_IRWXU), 0); - std::error_code error; - std::filesystem::create_directories(paths.auth_root(), error); - ASSERT_FALSE(error); - ASSERT_EQ(chmod(paths.auth_root().c_str(), S_IRWXU), 0); - const std::filesystem::path lock_path = - paths.auth_root() / ".default-sober-rejection.mocktail-writer.lock"; - std::filesystem::create_hard_link(paths.sober_cookie_file(), lock_path, - error); - ASSERT_FALSE(error); - FakeHttpClient http; - http.response = {true, 401, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kUnavailable); - EXPECT_EQ(composition.http_status, 401); - EXPECT_EQ(composition.error, - "rejected Sober credential could not be retired safely"); - EXPECT_EQ(http.request_count, 1); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), sober_cookies); - struct stat sober_metadata = {}; - ASSERT_EQ(lstat(paths.sober_cookie_file().c_str(), &sober_metadata), 0); - EXPECT_EQ(sober_metadata.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), S_IRWXU); - EXPECT_FALSE(std::filesystem::exists(paths.default_sober_rejection_file())); -} - TEST(AuthRuntimeCompositionTest, Http401ClearsPrivateReadOnlyManagedCredential) { TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); const std::string remaining_cookies = "OtherCookie=keep\n"; @@ -929,7 +520,6 @@ TEST(AuthRuntimeCompositionTest, TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); const std::string raw_cookie = kCredential; @@ -965,7 +555,6 @@ TEST(AuthRuntimeCompositionTest, Http403ClearsManagedCookieAndStartsGuest) { TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); const std::string cookies = std::string(".ROBLOSECURITY=") + kCredential + @@ -989,97 +578,11 @@ TEST(AuthRuntimeCompositionTest, Http403ClearsManagedCookieAndStartsGuest) { "\nRBXEventTrackerV2=browserid=123456\n"); } -TEST(AuthRuntimeCompositionTest, - DefaultSoberHttp403SuppressesRejectedCredentialAndStartsGuest) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\nOther=keep\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), cookies)); - FakeHttpClient http; - http.response = {true, 403, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - ASSERT_TRUE(composition) << composition.error; - EXPECT_EQ(composition.status, AuthRuntimeStatus::kGuest); - EXPECT_EQ(composition.http_status, 403); - EXPECT_TRUE(composition.rejected_credential_retired); - EXPECT_EQ(http.request_count, 1); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), cookies); - EXPECT_EQ(ReadFile(SoberRejectionPathFor(paths)), - SoberRejectionMarkerFor(kCredential)); -} - -TEST(AuthRuntimeCompositionTest, - DefaultSoberTransportFailureDoesNotCreateRejectionMarker) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), cookies)); - FakeHttpClient http; - http.response = {false, 0, {}, "request contained sensitive details"}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kUnavailable); - EXPECT_EQ(composition.error, "authentication service unavailable"); - EXPECT_EQ(http.request_count, 1); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), cookies); - EXPECT_FALSE(std::filesystem::exists(SoberRejectionPathFor(paths))); -} - -TEST(AuthRuntimeCompositionTest, - DefaultSoberHttp401PersistsRejectionWhenGuestIsDisabled) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), cookies)); - FakeHttpClient http; - http.response = {true, 401, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kInvalidCredentials); - EXPECT_EQ(composition.http_status, 401); - EXPECT_EQ(http.request_count, 1); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), cookies); - EXPECT_EQ(ReadFile(SoberRejectionPathFor(paths)), - SoberRejectionMarkerFor(kCredential)); - - FakeHttpClient restart_http; - services::AuthService restart_auth_service(restart_http); - const AuthRuntimeComposition restarted = - ComposeAuthRuntime(environment, paths, restart_auth_service); - EXPECT_FALSE(restarted); - EXPECT_EQ(restarted.status, AuthRuntimeStatus::kInvalidCredentials); - EXPECT_EQ(restart_http.request_count, 0); -} - TEST(AuthRuntimeCompositionTest, Http401ClearsManagedCredentialButDoesNotStartGuestWhenDisabled) { TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); const RuntimePaths paths = PathsFor(environment, directory); const std::string remaining_cookies = "RBXEventTrackerV2=browserid=123456\n"; const std::string rejected_cookie = @@ -1126,42 +629,11 @@ TEST(AuthRuntimeCompositionTest, EXPECT_EQ(ReadFile(explicit_cookie), cookies); } -TEST(AuthRuntimeCompositionTest, - Http401DoesNotClearExplicitSoberCredentialOverride) { - TempDirectory directory; - const std::filesystem::path explicit_sober_cookie = - directory.path() / "explicit-sober-cookie"; - const std::string cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\n"; - ASSERT_TRUE(WriteFile(explicit_sober_cookie, cookies)); - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_SOBER_COOKIE_FILE", explicit_sober_cookie.string()); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string marker = SoberRejectionMarkerFor(kCredential); - ASSERT_TRUE(WriteFile(SoberRejectionPathFor(paths), marker)); - ASSERT_EQ(chmod(paths.auth_root().c_str(), S_IRWXU), 0); - FakeHttpClient http; - http.response = {true, 401, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kInvalidCredentials); - EXPECT_EQ(composition.http_status, 401); - EXPECT_EQ(ReadFile(explicit_sober_cookie), cookies); - EXPECT_EQ(ReadFile(SoberRejectionPathFor(paths)), marker); -} - TEST(AuthRuntimeCompositionTest, Http401FailsClosedWhileCookieWriterLockIsHeld) { TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); const std::string cookies = @@ -1195,7 +667,6 @@ TEST(AuthRuntimeCompositionTest, TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); ASSERT_TRUE(WriteFile(paths.cookie_file(), @@ -1232,7 +703,6 @@ TEST(AuthRuntimeCompositionTest, TempDirectory directory; MapEnvironment environment; environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); const RuntimePaths paths = PathsFor(environment, directory); ASSERT_TRUE(WriteFile(paths.cookie_file(), @@ -1266,43 +736,6 @@ TEST(AuthRuntimeCompositionTest, EXPECT_EQ(ReadFile(protected_target), protected_contents); } -TEST(AuthRuntimeCompositionTest, - ManagedHardlinkToDefaultSoberCookieFailsClosedWithoutRedaction) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); - environment.Set("MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP", "1"); - const RuntimePaths paths = PathsFor(environment, directory); - const std::string cookies = - std::string(".ROBLOSECURITY=") + kCredential + "\nOther=keep\n"; - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), cookies)); - ASSERT_EQ(chmod(paths.sober_cookie_file().c_str(), S_IRUSR), 0); - std::error_code error; - std::filesystem::create_directories(paths.auth_root(), error); - ASSERT_FALSE(error); - std::filesystem::create_hard_link(paths.sober_cookie_file(), - paths.cookie_file(), error); - ASSERT_FALSE(error); - FakeHttpClient http; - http.response = {true, 401, {}, {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - EXPECT_FALSE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kUnavailable); - EXPECT_EQ(composition.http_status, 401); - EXPECT_EQ(composition.error, - "managed Roblox cookie aliases the protected Sober file"); - EXPECT_EQ(ReadFile(paths.cookie_file()), cookies); - EXPECT_EQ(ReadFile(paths.sober_cookie_file()), cookies); - struct stat sober_metadata = {}; - ASSERT_EQ(lstat(paths.sober_cookie_file().c_str(), &sober_metadata), 0); - EXPECT_EQ(sober_metadata.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), S_IRUSR); -} - TEST(AuthRuntimeCompositionTest, UnavailableAuthFailsClosedAndRedactsErrors) { TempDirectory directory; MapEnvironment environment; @@ -1390,89 +823,6 @@ TEST(AuthRuntimeCompositionTest, RejectsSymlinkCookieSource) { EXPECT_EQ(http.request_count, 0); } -TEST(AuthRuntimeCompositionTest, FallsBackToConfiguredSoberCookieFile) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_CONFIG_ROOT", - (directory.path() / "config").string()); - environment.Set("MOCKTAIL_SOBER_COOKIE_FILE", - (directory.path() / "sober-cookies").string()); - const RuntimePaths paths = PathsFor(environment, directory); - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), - std::string(".ROBLOSECURITY=") + kCredential + "\n")); - FakeHttpClient http; - http.response = { - true, 200, R"({"id":654,"name":"SoberUser","displayName":"Sober"})", {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - ASSERT_TRUE(composition); - EXPECT_EQ(composition.status, AuthRuntimeStatus::kAuthenticated); - EXPECT_EQ(composition.jni_vm->GetRobloxAuthIdentitySnapshot().user_id, 654); - EXPECT_EQ(http.request_count, 1); - - std::ifstream migrated(paths.cookie_file(), std::ios::binary); - ASSERT_TRUE(migrated.good()); - const std::string migrated_value( - (std::istreambuf_iterator(migrated)), - std::istreambuf_iterator()); - EXPECT_EQ(migrated_value, - std::string(".ROBLOSECURITY=") + kCredential + "\n"); - struct stat migrated_status = {}; - ASSERT_EQ(lstat(paths.cookie_file().c_str(), &migrated_status), 0); - EXPECT_EQ(migrated_status.st_mode & (S_IRWXG | S_IRWXO), 0U); - - MapEnvironment restart_environment; - restart_environment.Set("HOME", directory.path().string()); - restart_environment.Set("MOCKTAIL_USE_SOBER_COOKIES", "0"); - FakeHttpClient restart_http; - restart_http.response = { - true, 200, R"({"id":654,"name":"SoberUser","displayName":"Sober"})", {}}; - services::AuthService restart_auth_service(restart_http); - const AuthRuntimeComposition restarted = ComposeAuthRuntime( - restart_environment, PathsFor(restart_environment, directory), - restart_auth_service); - ASSERT_TRUE(restarted); - EXPECT_EQ(restarted.status, AuthRuntimeStatus::kAuthenticated); - ASSERT_EQ(restart_http.request_count, 1); - EXPECT_EQ(restart_http.last_request.headers[1], - std::string("Cookie: .ROBLOSECURITY=") + kCredential); -} - -TEST(AuthRuntimeCompositionTest, - TrackerOnlyLocalCookieFallsBackToSoberCredential) { - TempDirectory directory; - MapEnvironment environment; - environment.Set("HOME", directory.path().string()); - environment.Set("MOCKTAIL_CONFIG_ROOT", - (directory.path() / "config").string()); - environment.Set("MOCKTAIL_SOBER_COOKIE_FILE", - (directory.path() / "sober-cookies").string()); - const RuntimePaths paths = PathsFor(environment, directory); - ASSERT_TRUE(WriteFile( - paths.cookie_file(), - "RBXEventTrackerV2=browserid=123456&browserid_insert_timestamp=1\n")); - ASSERT_TRUE(WriteFile(paths.sober_cookie_file(), - std::string(".ROBLOSECURITY=") + kCredential + "\n")); - FakeHttpClient http; - http.response = { - true, 200, R"({"id":654,"name":"SoberUser","displayName":"Sober"})", {}}; - services::AuthService auth_service(http); - - const AuthRuntimeComposition composition = - ComposeAuthRuntime(environment, paths, auth_service); - - ASSERT_TRUE(composition) << composition.error; - EXPECT_EQ(composition.status, AuthRuntimeStatus::kAuthenticated); - ASSERT_EQ(http.request_count, 1); - ASSERT_GE(http.last_request.headers.size(), 2U); - EXPECT_EQ(http.last_request.headers[1], - std::string("Cookie: .ROBLOSECURITY=") + kCredential); -} - TEST(AuthRuntimeCompositionTest, FileReplacementCannotChangeCredentialOrIdentityDependency) { constexpr char kCredentialA[] = "_|validated-credential-a"; diff --git a/tests/auto_update_orchestration_test.sh b/tests/auto_update_orchestration_test.sh index 5a17c4f..e7f6e44 100755 --- a/tests/auto_update_orchestration_test.sh +++ b/tests/auto_update_orchestration_test.sh @@ -285,7 +285,6 @@ fi if [[ "${MOCKTAIL_ISOLATED_CANARY:-0}" == 1 ]]; then [[ -z "${MOCKTAIL_COOKIE_FILE+x}" && "${MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP:-0}" == 1 && - "${MOCKTAIL_USE_SOBER_COOKIES:-1}" == 0 && "${MOCKTAIL_IGNORE_WINDOW_CLOSE:-0}" == 1 ]] || exit 1 fi [[ "${VK_DRIVER_FILES:-}" == /test/mocktail-vk.json && diff --git a/tests/compatibility_gate_test.sh b/tests/compatibility_gate_test.sh index fe60673..956aa2c 100644 --- a/tests/compatibility_gate_test.sh +++ b/tests/compatibility_gate_test.sh @@ -22,7 +22,6 @@ output="$( PATH="${PATH}" \ HOME="${HOME}" \ MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP=1 \ - MOCKTAIL_USE_SOBER_COOKIES=0 \ MOCKTAIL_CONFIG_ROOT="${temporary_root}/config" \ MOCKTAIL_DATA_ROOT="${temporary_root}/data" \ MOCKTAIL_CACHE_ROOT="${temporary_root}/cache" \ diff --git a/tests/detached_thread_policy_test.sh b/tests/detached_thread_policy_test.sh index 0e5a5e4..5582753 100644 --- a/tests/detached_thread_policy_test.sh +++ b/tests/detached_thread_policy_test.sh @@ -79,7 +79,6 @@ run_with_override() { PATH="${PATH}" \ HOME="${HOME}" \ MOCKTAIL_ALLOW_NO_COOKIE_LUA_APP=1 \ - MOCKTAIL_USE_SOBER_COOKIES=0 \ MOCKTAIL_CONFIG_ROOT="${temporary_root}/config" \ MOCKTAIL_DATA_ROOT="${temporary_root}/data" \ MOCKTAIL_CACHE_ROOT="${temporary_root}/cache" \ diff --git a/tests/runtime_paths_test.cc b/tests/runtime_paths_test.cc index 50fdbf5..ad86ee2 100644 --- a/tests/runtime_paths_test.cc +++ b/tests/runtime_paths_test.cc @@ -142,9 +142,6 @@ TEST(RuntimePathsTest, DerivesXdgDefaults) { EXPECT_EQ(paths.auth_root(), "/home/mocktail/.local/share/mocktail/auth"); EXPECT_EQ(paths.cookie_file(), "/home/mocktail/.local/share/mocktail/auth/roblox.cookie"); - EXPECT_EQ(paths.default_sober_rejection_file(), - "/home/mocktail/.local/share/mocktail/auth/" - "default-sober-rejection"); } TEST(RuntimePathsTest, IgnoresRelativeXdgHomes) { @@ -410,7 +407,6 @@ TEST(RuntimePathsTest, HonorsExplicitAndXdgOverrides) { {"MOCKTAIL_DATA_ROOT", "/data"}, {"MOCKTAIL_STATE_ROOT", "/state"}, {"MOCKTAIL_AUTH_ROOT", "/auth"}, - {"MOCKTAIL_SOBER_COOKIE_FILE", "/cookies/sober"}, }); const RuntimePaths explicit_paths = RuntimePaths::FromEnvironment(explicit_environment, "/workspace"); @@ -419,9 +415,6 @@ TEST(RuntimePathsTest, HonorsExplicitAndXdgOverrides) { EXPECT_EQ(explicit_paths.data_root(), "/data"); EXPECT_EQ(explicit_paths.state_root(), "/state"); EXPECT_EQ(explicit_paths.auth_root(), "/auth"); - EXPECT_EQ(explicit_paths.default_sober_rejection_file(), - "/auth/default-sober-rejection"); - EXPECT_EQ(explicit_paths.sober_cookie_file(), "/cookies/sober"); const MapEnvironment xdg_environment({ {"HOME", "/home/mocktail"},