Keep the profile private and write it all at once
Settings, bookmarks (server passwords) and identities (private keys) were written in place with the default permissions, readable by every user on the machine, and a crash mid-write left a truncated file that the next start silently replaced with defaults. Every profile file is now written to a private temporary file, synced and moved over the old one in one step. The profile folder itself is made accessible to its owner only, which also covers files written before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
package com.ts3client.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class ProfileFilesTest {
|
||||
|
||||
@TempDir
|
||||
Path dir;
|
||||
|
||||
@Test
|
||||
void replacesTheFileReadableByTheUserOnly() throws Exception {
|
||||
File file = dir.resolve("settings.properties").toFile();
|
||||
Files.writeString(file.toPath(), "old");
|
||||
|
||||
ProfileFiles.write(file, out -> out.write("new".getBytes()));
|
||||
|
||||
assertEquals("new", Files.readString(file.toPath()));
|
||||
assertEquals("rw-------", PosixFilePermissions.toString(Files.getPosixFilePermissions(file.toPath())));
|
||||
try (var left = Files.list(dir)) {
|
||||
assertEquals(1, left.count(), "no temporary file left behind");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void aFailedWriteLeavesTheOldFileAlone() throws Exception {
|
||||
File file = dir.resolve("bookmarks.properties").toFile();
|
||||
Files.writeString(file.toPath(), "old");
|
||||
|
||||
assertThrows(IOException.class, () -> ProfileFiles.write(file, out -> {
|
||||
out.write("half".getBytes());
|
||||
throw new IOException("crashed");
|
||||
}));
|
||||
|
||||
assertEquals("old", Files.readString(file.toPath()));
|
||||
try (var left = Files.list(dir)) {
|
||||
assertEquals(1, left.count(), "no temporary file left behind");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user