impermanence/lib.nix
talyz b4160ba71d
nixos: Rewrite directory creation for saner default permissions
Construct directory items for all parent directories of the user
specified files and directories, assigning better default permissions
and ownership to each and removing this responsibility from the
create-directories script.

This means that all parent directories of root directories will now
have the default permissions and ownership, not inherit them from the
child. User directories are assigned default user ownership. The home
directory itself is handled specially to make sure it is owned by the
user, not readable by anyone else and its parent gets default root
ownership.

To illustrate this with an example, here is a directory specification
and the ownership and permissions that could potentially be assigned
to the parent directories, given none of them yet exist in persistent
storage:

environment.persistence."/persistent" = {
  users.talyz = {
    directories = [
      { directory = ".local/share/secret"; mode = "0500"; }
    ];
  };
};

Before:
/home                            talyz:talyz   0500
/home/talyz                      talyz:talyz   0500
/home/talyz/.local               talyz:talyz   0500
/home/talyz/.local/share         talyz:talyz   0500
/home/talyz/.local/share/secret  talyz:talyz   0500

After:
/home                            root:root     0755
/home/talyz                      talyz:talyz   0700
/home/talyz/.local               talyz:talyz   0755
/home/talyz/.local/share         talyz:talyz   0755
/home/talyz/.local/share/secret  talyz:talyz   0500
2023-04-23 08:16:07 +02:00

91 lines
1.8 KiB
Nix

{ lib }:
let
inherit (lib)
filter
concatMap
concatStringsSep
hasPrefix
head
replaceStrings
optionalString
removePrefix
foldl'
elem
take
length
last
;
inherit (lib.strings)
sanitizeDerivationName
;
# ["/home/user/" "/.screenrc"] -> ["home" "user" ".screenrc"]
splitPath = paths:
(filter
(s: builtins.typeOf s == "string" && s != "")
(concatMap (builtins.split "/") paths)
);
# ["home" "user" ".screenrc"] -> "home/user/.screenrc"
dirListToPath = dirList: (concatStringsSep "/" dirList);
# ["/home/user/" "/.screenrc"] -> "/home/user/.screenrc"
concatPaths = paths:
let
prefix = optionalString (hasPrefix "/" (head paths)) "/";
path = dirListToPath (splitPath paths);
in
prefix + path;
parentsOf = path:
let
prefix = optionalString (hasPrefix "/" path) "/";
split = splitPath [ path ];
parents = take ((length split) - 1) split;
in
foldl'
(state: item:
state ++ [
(concatPaths [
(if state != [ ] then last state else prefix)
item
])
])
[ ]
parents;
sanitizeName = name:
replaceStrings
[ "." ] [ "" ]
(sanitizeDerivationName (removePrefix "/" name));
duplicates = list:
let
result =
foldl'
(state: item:
if elem item state.items then
{
items = state.items ++ [ item ];
duplicates = state.duplicates ++ [ item ];
}
else
state // {
items = state.items ++ [ item ];
})
{ items = [ ]; duplicates = [ ]; }
list;
in
result.duplicates;
in
{
inherit
splitPath
dirListToPath
concatPaths
parentsOf
sanitizeName
duplicates
;
}