main
1{
2 lib,
3 config,
4 ...
5}: let
6 # Identity fields other than `displayName`, whose default differs between the
7 # shared registry (the registry key) and the entity (the injected value).
8 identityFields = {
9 options = {
10 email = lib.mkOption {
11 type = lib.types.nullOr lib.types.str;
12 default = null;
13 description = "Email address for the user";
14 };
15 avatar = lib.mkOption {
16 type = lib.types.nullOr lib.types.path;
17 default = null;
18 description = "Avatar for the user";
19 };
20 sshKeys = lib.mkOption {
21 type = lib.types.listOf lib.types.str;
22 default = [];
23 };
24 gpgKeys = lib.mkOption {
25 type = lib.types.listOf (lib.types.either lib.types.path lib.types.str);
26 default = [];
27 description = "OpenPGP public keys (paths or armored key text) for this user";
28 };
29 };
30 };
31
32 identityType = lib.types.submodule {
33 imports = [identityFields];
34 options.displayName = lib.mkOption {
35 type = lib.types.str;
36 description = "Display name for the user";
37 };
38 };
39
40 sharedIdentity = lib.mkOptionType {
41 name = "den-shared-user-identity";
42 check = v: builtins.isAttrs v;
43 merge = loc: defs: let
44 shared =
45 if builtins.length loc < 2
46 then {}
47 else let
48 username = lib.elemAt loc (builtins.length loc - 2);
49 in
50 (config.den.users.${username} or {}).identity or {displayName = username;};
51 in
52 identityType.merge loc ([
53 {
54 file = "<den.users>";
55 value = lib.mkDefault shared;
56 }
57 ]
58 ++ defs);
59 };
60in {
61 # Shared user schema across every host
62 options.den.users = lib.mkOption {
63 type = lib.types.attrsOf (
64 lib.types.submodule {
65 freeformType = lib.types.attrsOf lib.types.anything;
66 options = {
67 admin = lib.mkEnableOption "Whether to add user to admin user";
68 identity = lib.mkOption {
69 type = lib.types.submodule (
70 {name, ...}: let
71 userName = name;
72 in {
73 imports = [identityFields];
74 options.displayName = lib.mkOption {
75 type = lib.types.str;
76 default = userName;
77 description = "Display name for the user";
78 };
79 }
80 );
81 default = {};
82 };
83 system = lib.mkOption {
84 type = lib.types.submodule {
85 options = {
86 hashedPasswordAged = lib.mkOption {
87 type = lib.types.path;
88 description = "Age encryped hashed password file for user";
89 };
90 settings = lib.mkOption {
91 type = lib.types.anything;
92 };
93 };
94 };
95 default = {};
96 };
97 };
98 }
99 );
100 default = {};
101 description = ''
102 Shared user definitions, keyed by user name.
103
104 Merged into the user schema of every host that declares `users.<name>`
105 in its `den.hosts` entry; host-specific values override shared ones.
106 '';
107 };
108
109 config.den.schema.user.options.identity = lib.mkOption {
110 type = sharedIdentity;
111 default = {};
112 description = ''
113 User identity fields, merged with the shared `den.users.<name>.identity`
114 registry entry as a lowest-priority definition.
115 '';
116 };
117}