vaultfs 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,6 +39,9 @@ public class DiskService {
39
39
 
40
40
  if (existingStartBlockId >= 0) {
41
41
  metadata.startBlockId = existingStartBlockId;
42
+ } else if (existingStartBlockId == -2) {
43
+ // Already tracked but disk was full — don't retry allocation
44
+ metadata.startBlockId = -1;
42
45
  } else if (metadata.startBlockId == -1) {
43
46
  metadata.startBlockId = diskSimulator.allocateFile(metadata.sizeBytes);
44
47
  }
@@ -762,10 +762,13 @@ public class FileSystem {
762
762
  } else if (entry.isFile()) {
763
763
  String filePath = diskService.normalizePath(entry.getAbsolutePath());
764
764
  Integer existingBlockId = fileBlockIndex.get(filePath);
765
+ // If file is already tracked (even with -1 = disk full), skip re-allocation
766
+ int blockHint = existingBlockId != null ? existingBlockId : -1;
767
+ boolean alreadyTracked = fileBlockIndex.containsKey(filePath);
765
768
  models.FileMetadata metadata = diskService.metadataFromDiskFile(
766
769
  entry,
767
770
  diskSimulator,
768
- existingBlockId != null ? existingBlockId : -1
771
+ alreadyTracked ? Math.max(blockHint, 0) == blockHint ? blockHint : -2 : -1
769
772
  );
770
773
  diskFiles.add(metadata);
771
774
  diskFilePaths.add(filePath);
@@ -858,7 +861,9 @@ public class FileSystem {
858
861
  }
859
862
 
860
863
  /** Allows plain names only so commands operate within current directory scope.
861
- * Rejects path separators, traversal patterns (..), null bytes, and empty/blank names. */
864
+ * Rejects path separators, traversal patterns (..), null bytes, and empty/blank names.
865
+ * Note: any name containing ".." is rejected, including "foo..bar", as a
866
+ * defense-in-depth measure against path traversal after separator stripping. */
862
867
  private boolean isSimpleName(String name) {
863
868
  if (name == null || name.trim().isEmpty()) {
864
869
  return false;
@@ -869,8 +874,6 @@ public class FileSystem {
869
874
  if (".".equals(name) || "..".equals(name)) {
870
875
  return false;
871
876
  }
872
- // Reject names that contain ".." as a substring (e.g. "foo..bar" is fine,
873
- // but this catches edge cases with path separators stripped earlier)
874
877
  if (name.contains("..")) {
875
878
  return false;
876
879
  }
@@ -955,7 +958,6 @@ public class FileSystem {
955
958
  if (AuthManager.isLoggedIn() && syncPending.compareAndSet(false, true)) {
956
959
  syncExecutor.submit(() -> {
957
960
  try {
958
- syncPending.set(false);
959
961
  String stateContent = new String(
960
962
  java.nio.file.Files.readAllBytes(
961
963
  java.nio.file.Paths.get(
@@ -969,8 +971,9 @@ public class FileSystem {
969
971
  stateContent
970
972
  );
971
973
  } catch (Exception e) {
972
- syncPending.set(false);
973
974
  Logger.warn("[sync] Cloud sync failed: " + e.getClass().getSimpleName());
975
+ } finally {
976
+ syncPending.set(false);
974
977
  }
975
978
  });
976
979
  }
@@ -99,7 +99,13 @@ public class FirestoreSync {
99
99
  if (attempt == maxRetries) {
100
100
  Logger.warn("[sync] Push failed after " + maxRetries + " attempts");
101
101
  } else {
102
- Thread.sleep((long) Math.pow(2, attempt) * 1000); // Exponential backoff
102
+ try {
103
+ Thread.sleep((long) Math.pow(2, attempt) * 1000); // Exponential backoff
104
+ } catch (InterruptedException ie) {
105
+ Thread.currentThread().interrupt();
106
+ Logger.warn("[sync] Push interrupted");
107
+ break;
108
+ }
103
109
  }
104
110
  }
105
111
  }
@@ -136,7 +142,9 @@ public class FirestoreSync {
136
142
  return null;
137
143
  }
138
144
 
139
- // Use char array for private key so we can zero it after use
145
+ // Best-effort zeroing: char array can be wiped, but intermediate String
146
+ // instances (strippedKey, jwt) remain in the JVM string pool until GC.
147
+ // For stronger guarantees, consider an HSM or vault-based signer.
140
148
  char[] privateKeyChars = privateKey.toCharArray();
141
149
  privateKey = null; // Release string reference
142
150
 
@@ -11,17 +11,38 @@ public class EnvParser {
11
11
  private static final Map<String, String> envMap = new HashMap<>();
12
12
 
13
13
  static {
14
- loadEnvFile(System.getProperty("user.dir") + "/.env");
14
+ // Try user.dir first (development), then VAULTFS_HOME / -Dvaultfs.home (global install)
15
+ String userDir = System.getProperty("user.dir");
16
+ String envPath = userDir + "/.env";
17
+ if (!new java.io.File(envPath).exists()) {
18
+ String home = System.getProperty("vaultfs.home");
19
+ if (home == null || home.isEmpty()) {
20
+ home = System.getenv("VAULTFS_HOME");
21
+ }
22
+ if (home != null && !home.isEmpty()) {
23
+ envPath = home + "/.env";
24
+ }
25
+ }
26
+ loadEnvFile(envPath);
15
27
  }
16
28
 
17
29
  private static void loadEnvFile(String path) {
18
- // Validate the .env path is within the project directory
30
+ // Validate the .env path is within an allowed base directory
19
31
  try {
20
32
  java.io.File envFile = new java.io.File(path);
21
33
  String canonicalEnv = envFile.getCanonicalPath();
22
34
  String canonicalBase = new java.io.File(System.getProperty("user.dir")).getCanonicalPath();
23
- if (!canonicalEnv.startsWith(canonicalBase)) {
24
- System.err.println("[EnvParser] Warning: .env path outside project directory, skipping");
35
+ boolean allowed = canonicalEnv.startsWith(canonicalBase);
36
+ if (!allowed) {
37
+ String home = System.getProperty("vaultfs.home");
38
+ if (home == null || home.isEmpty()) home = System.getenv("VAULTFS_HOME");
39
+ if (home != null && !home.isEmpty()) {
40
+ String canonicalHome = new java.io.File(home).getCanonicalPath();
41
+ allowed = canonicalEnv.startsWith(canonicalHome);
42
+ }
43
+ }
44
+ if (!allowed) {
45
+ System.err.println("[EnvParser] Warning: .env path outside allowed directories, skipping");
25
46
  return;
26
47
  }
27
48
  } catch (IOException e) {
package/version.txt CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.3