fix(launcher): Campaign LA LA3 narrow review fixes
This commit is contained in:
parent
26feba8186
commit
347a1a5d16
9 changed files with 495 additions and 145 deletions
|
|
@ -19,6 +19,8 @@ namespace AcDream.Launcher.Core.Profiles;
|
|||
public sealed class LauncherProfileStore
|
||||
{
|
||||
internal const int CurrentVersion = 1;
|
||||
internal const UnixFileMode OwnerOnlyFileMode =
|
||||
UnixFileMode.UserRead | UnixFileMode.UserWrite;
|
||||
|
||||
private static readonly JsonSerializerOptions SerializerOptions = new()
|
||||
{
|
||||
|
|
@ -115,14 +117,12 @@ public sealed class LauncherProfileStore
|
|||
/// <summary>
|
||||
/// Persists <see cref="Document"/> to <see cref="FilePath"/> via a
|
||||
/// write-then-atomic-rename so a crash mid-write never leaves a
|
||||
/// truncated credentials file. On Linux, the temp file is chmod'd to
|
||||
/// owner read/write (0600) immediately after creation — BEFORE any
|
||||
/// plaintext credential is serialized into it — so there is no window
|
||||
/// where the temp file carries the process umask's (potentially
|
||||
/// world/group-readable) default permissions while holding a
|
||||
/// password; the final path gets the same restriction after the
|
||||
/// rename (Campaign LA's plaintext-credential decision, spec §5,
|
||||
/// decisions log; the temp-file window itself is review finding F4).
|
||||
/// truncated credentials file. On Linux, the temp file is created
|
||||
/// atomically with owner read/write (0600) as its requested creation
|
||||
/// mode — before its path is observable and before any plaintext
|
||||
/// credential is serialized into it. The final path retains that mode
|
||||
/// through the rename (Campaign LA's plaintext-credential decision,
|
||||
/// spec §5, decisions log).
|
||||
/// A failure between temp-file creation and the rename deletes the
|
||||
/// stale temp file rather than leaving it behind.
|
||||
/// </summary>
|
||||
|
|
@ -135,15 +135,18 @@ public sealed class LauncherProfileStore
|
|||
}
|
||||
|
||||
string tempPath = FilePath + ".tmp";
|
||||
DeleteStaleTempFile(tempPath);
|
||||
try
|
||||
{
|
||||
using (FileStream stream = File.Create(tempPath))
|
||||
using (FileStream stream = CreateCredentialTempFile(tempPath))
|
||||
{
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
File.SetUnixFileMode(
|
||||
tempPath,
|
||||
UnixFileMode.UserRead | UnixFileMode.UserWrite);
|
||||
// UnixCreateMode is subject to the process umask. It
|
||||
// guarantees the file is never created with group/other
|
||||
// access; normalize the owner bits while the still-empty
|
||||
// file is open so the persisted contract is exactly 0600.
|
||||
File.SetUnixFileMode(tempPath, OwnerOnlyFileMode);
|
||||
}
|
||||
|
||||
JsonSerializer.Serialize(stream, Document, SerializerOptions);
|
||||
|
|
@ -159,12 +162,39 @@ public sealed class LauncherProfileStore
|
|||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
File.SetUnixFileMode(
|
||||
FilePath,
|
||||
UnixFileMode.UserRead | UnixFileMode.UserWrite);
|
||||
File.SetUnixFileMode(FilePath, OwnerOnlyFileMode);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the exact options used for the plaintext-credential temp
|
||||
/// file. <see cref="FileMode.CreateNew"/> makes creation atomic and
|
||||
/// refuses to follow an existing stale or raced path. On Linux,
|
||||
/// <see cref="FileStreamOptions.UnixCreateMode"/> supplies 0600 to
|
||||
/// the OS create operation itself, eliminating the observable
|
||||
/// create-then-chmod window. Windows leaves UnixCreateMode unset and
|
||||
/// therefore retains its normal user-profile ACL behavior.
|
||||
/// </summary>
|
||||
internal static FileStreamOptions CreateCredentialTempFileOptions()
|
||||
{
|
||||
var options = new FileStreamOptions
|
||||
{
|
||||
Mode = FileMode.CreateNew,
|
||||
Access = FileAccess.Write,
|
||||
Share = FileShare.None,
|
||||
};
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
options.UnixCreateMode = OwnerOnlyFileMode;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
internal static FileStream CreateCredentialTempFile(string tempPath) =>
|
||||
new(tempPath, CreateCredentialTempFileOptions());
|
||||
|
||||
private static void DeleteStaleTempFile(string tempPath)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue