mirror of
https://github.com/InstanceBrick/nightcap.git
synced 2026-10-17 15:00:47 +02:00
1 parent
0b8cbef447
commit
2a154b6f58
16 files changed
+10
-891
No files matched your search
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <vector>
|
||||
|
||||
#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<const unsigned char*>(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<CookiePersistenceContext*>(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<CookieRedactionRange> 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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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<FakeHttpClient>();
|
||||
@@ -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<char>(migrated)),
|
||||
std::istreambuf_iterator<char>());
|
||||
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";
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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"},
|
||||
|
||||
Reference in new issue
Block a user