noz-cli/NozCli/Repl/NotesCache.cs
kryptomrx b971d45e78 security: slug validation, path traversal protection, temp file cleanup
- SlugGuard.IsValid() rejects slugs with path traversal (../, //, uppercase)
- SlugGuard.ToSafePath() ensures sync writes stay within target directory
- PushCommand: skip files with invalid slugs before upload
- SyncCommand: validate server-returned slugs before writing to disk
- EditCommand/NewCommand: try/finally guarantees temp file deletion on crash
- NotesCache: set 600 permissions on cache file (metadata only, no token)
- NewCommand: remove dead Sha256 method (HashHelper already covers this)
2026-05-16 23:36:40 +02:00

56 lines
1.8 KiB
C#

using System.Text.Json;
using NozCli.Core.Models;
using NozCli.Core.Serialization;
namespace NozCli.Repl;
public static class NotesCache
{
private static string CachePath => Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
".cache", "noz", "notes.json");
public static NotesCacheFile? TryLoad()
{
try
{
if (!File.Exists(CachePath)) return null;
var json = File.ReadAllText(CachePath);
return JsonSerializer.Deserialize(json, NozJsonContext.Default.NotesCacheFile);
}
catch { return null; }
}
public static async Task SaveAsync(List<NoteInfo> notes)
{
try
{
var dir = Path.GetDirectoryName(CachePath)!;
Directory.CreateDirectory(dir);
var cache = new NotesCacheFile(DateTimeOffset.UtcNow, notes);
var json = JsonSerializer.Serialize(cache, NozJsonContext.Default.NotesCacheFile);
// Atomic write: tmp → rename
var tmp = CachePath + ".tmp";
await File.WriteAllTextAsync(tmp, json);
File.Move(tmp, CachePath, overwrite: true);
if (!OperatingSystem.IsWindows())
File.SetUnixFileMode(CachePath, UnixFileMode.UserRead | UnixFileMode.UserWrite);
}
catch { /* cache write failures are non-fatal */ }
}
public static string TimeAgo(DateTimeOffset dt)
{
var diff = DateTimeOffset.UtcNow - dt;
return diff.TotalSeconds switch
{
< 60 => "gerade eben",
< 3600 => $"vor {(int)diff.TotalMinutes} Min.",
< 86400 => $"vor {(int)diff.TotalHours} Std.",
_ => $"vor {(int)diff.TotalDays} Tagen",
};
}
}