This commit is contained in:
parent
8e0773688e
commit
df0ff3f095
|
@ -61,7 +61,7 @@ in {
|
|||
commands =
|
||||
concatStringsSep "\n"
|
||||
(map
|
||||
(x: "cp -s \"${pkgs.writeText x.file (toXml x.name x.content)}\" \"/var/lib/jellyfin/config/${x.file}\"")
|
||||
(x: "test ! -e \"/var/lib/jellyfin/config/${x.file}\" && cp -s \"${pkgs.writeText x.file (toXml x.name x.content)}\" \"/var/lib/jellyfin/config/${x.file}\"")
|
||||
[
|
||||
{
|
||||
name = "NetworkConfiguration";
|
||||
|
@ -92,8 +92,6 @@ in {
|
|||
sq = "${pkgs.sqlite}/bin/sqlite3 \"${path}/${dbname}\" --";
|
||||
path = "/var/lib/jellyfin/data";
|
||||
|
||||
# ${sq} "INSERT INTO Users (Id, AudioLanguagePreference, AuthenticationProviderId, DisplayCollectionsView, DisplayMissingEpisodes, EnableAutoLogin, EnableLocalPassword, EnableNextEpisodeAutoPlay, EnableUserPreferenceAccess, HidePlayedInLatest, InternalId, LoginAttemptsBeforeLockout, MaxActiveSessions, MaxParentalAgeRating, Password, HashedPasswordFile, PasswordResetProviderId, PlayDefaultAudioTrack, RememberAudioSelections, RememberSubtitleSelections, RemoteClientBitrateLimit, SubtitleLanguagePreference, SubtitleMode, SyncPlayAccess, Username, CastReceiverId) \
|
||||
# VALUES(${user.})"
|
||||
genUser = index: user: let
|
||||
values =
|
||||
builtins.mapAttrs
|
||||
|
@ -103,21 +101,23 @@ in {
|
|||
if value
|
||||
then "1"
|
||||
else "0"
|
||||
else if (isNull value)
|
||||
then "NULL"
|
||||
else value)
|
||||
(cfg.Users
|
||||
(user
|
||||
// {
|
||||
Id =
|
||||
if (builtins.hasAttr "Id" cfg.Users)
|
||||
then cfg.Users.Id
|
||||
if !(isNull user.Id)
|
||||
then user.Id
|
||||
else "$(${pkgs.libuuid}/bin/uuidgen | ${pkgs.coreutils}/bin/tr '[:lower:]' '[:upper:]')";
|
||||
InternalId =
|
||||
if (builtins.hasAttr "InternalId" cfg.Users)
|
||||
then cfg.Users.InternalId
|
||||
else "$(($maxIndex+${index + 1}))";
|
||||
if !(isNull user.InternalId)
|
||||
then user.InternalId
|
||||
else "$(($maxIndex+${toString (index + 1)}))";
|
||||
Password =
|
||||
if (hasAttr "HashedPasswordFile" cfg.Users)
|
||||
then "$(${pkgs.coreutils}/bin/cat \"${cfg.Users.HashedPasswordFile}\")"
|
||||
else "$(${self.packages.${pkgs.system}.genhash}/bin/genhash -k \"${cfg.Users.Password}\" -i 210000 -l 128 -u)";
|
||||
if !(isNull user.HashedPasswordFile)
|
||||
then "$(${pkgs.coreutils}/bin/cat \"${user.HashedPasswordFile}\")"
|
||||
else "$(${self.packages.${pkgs.system}.genhash}/bin/genhash -k \"${user.Password}\" -i 210000 -l 128 -u)";
|
||||
});
|
||||
in
|
||||
/*
|
||||
|
@ -130,9 +130,9 @@ in {
|
|||
(
|
||||
builtins.filter (x: x != "HashedPasswordFile")
|
||||
(lib.attrsets.mapAttrsToList (name: value: "${name}")
|
||||
options.services.declarative-jellyfin.Users.options)
|
||||
((import ./options/users.nix {inherit lib;}).options.services.declarative-jellyfin.Users.type.getSubOptions []))
|
||||
)}) \\
|
||||
VALUES(${builtins.attrValues values})"
|
||||
VALUES(${concatStringsSep "," (map toString (builtins.attrValues values))})"
|
||||
fi
|
||||
'';
|
||||
in
|
||||
|
@ -144,6 +144,7 @@ in {
|
|||
# Make sure there is a database
|
||||
if [ ! -e "${path}/${dbname}" ]; then
|
||||
cp ${defaultDB} "${path}/${dbname}"
|
||||
chmod 770 "${path}/${dbname}"
|
||||
fi
|
||||
|
||||
maxIndex=$(${sq} 'SELECT InternalId FROM Users ORDER BY InternalId DESC LIMIT 1')
|
||||
|
@ -151,6 +152,23 @@ in {
|
|||
maxIndex="1"
|
||||
fi
|
||||
|
||||
${
|
||||
concatStringsSep "\n"
|
||||
(
|
||||
map ({
|
||||
fst,
|
||||
snd,
|
||||
}:
|
||||
genUser snd fst)
|
||||
(
|
||||
lib.lists.zipLists cfg.Users
|
||||
(
|
||||
builtins.genList (x: x)
|
||||
(builtins.length cfg.Users)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
''
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,15 +4,17 @@ with lib; {
|
|||
# Based on: https://github.com/jellyfin/jellyfin/blob/master/MediaBrowser.Model/Configuration/UserConfiguration.cs
|
||||
Users = mkOption {
|
||||
description = "User configuration";
|
||||
default = [];
|
||||
type = lib.types.listOf (lib.types.submodule ({config, ...}: {
|
||||
options = {
|
||||
Id = mkOption {
|
||||
type = types.str; # TODO: Limit the id to the pattern: "18B51E25-33FD-46B6-BBF8-DB4DD77D0679"
|
||||
type = types.nullOr types.str; # TODO: Limit the id to the pattern: "18B51E25-33FD-46B6-BBF8-DB4DD77D0679"
|
||||
description = "The ID of the user";
|
||||
example = "18B51E25-33FD-46B6-BBF8-DB4DD77D0679";
|
||||
default = null;
|
||||
};
|
||||
AudioLanguagePreference = mkOption {
|
||||
type = with types; either null str;
|
||||
type = with types; nullOr str;
|
||||
description = "The audio language preference. Defaults to 'Any Language'";
|
||||
default = null;
|
||||
example = "eng";
|
||||
|
@ -63,10 +65,11 @@ with lib; {
|
|||
example = false;
|
||||
};
|
||||
InternalId = mkOption {
|
||||
type = types.int;
|
||||
type = with types; nullOr int;
|
||||
# NOTE: index is 1-indexed! NOT 0-indexed.
|
||||
description = "The index of the user in the database. Be careful setting this option. 1 indexed.";
|
||||
example = 69;
|
||||
default = null;
|
||||
};
|
||||
LoginAttemptsBeforeLockout = mkOption {
|
||||
type = types.int;
|
||||
|
@ -81,15 +84,16 @@ with lib; {
|
|||
example = 5;
|
||||
};
|
||||
MaxParentalAgeRating = mkOption {
|
||||
type = with types; either null int;
|
||||
type = with types; nullOr int;
|
||||
# idk no docs man
|
||||
default = null;
|
||||
};
|
||||
Password = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
HashedPasswordFile = mkOption {
|
||||
type = types.path;
|
||||
type = with types; either path str;
|
||||
description = ''
|
||||
A path to a pbkdf2-sha512 hash
|
||||
in this format [PHC string](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md).
|
||||
|
@ -106,6 +110,7 @@ with lib; {
|
|||
|
||||
```
|
||||
'';
|
||||
default = "";
|
||||
example = ''
|
||||
# the format is: $<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]
|
||||
$PBKDF2-SHA512$iterations=210000$D12C02D1DD15949D867BCA9971BE9987$67E75CDCD14E7F6FDDF96BAACBE9E84E5197FB9FE454FB039F5CD773D7DF558B57DC81DB42B6F7CF0E6B8207A771E5C0EE0DBFD91CE5BAF804FE53F70E61CD2E
|
||||
|
@ -135,7 +140,7 @@ with lib; {
|
|||
default = 0;
|
||||
};
|
||||
SubtitleLanguagePreference = mkOption {
|
||||
type = with types; either null str;
|
||||
type = with types; nullOr str;
|
||||
description = "The subtitle language preference. Defaults to 'Any Language'";
|
||||
default = null;
|
||||
example = "eng";
|
||||
|
|
|
@ -16,8 +16,9 @@ in {
|
|||
|
||||
virtualisation.memorySize = 1024;
|
||||
|
||||
environment.systemPackages = [
|
||||
pkgs.sqlite
|
||||
environment.systemPackages = with pkgs; [
|
||||
sqlite
|
||||
file
|
||||
];
|
||||
|
||||
services.declarative-jellyfin = {
|
||||
|
@ -40,9 +41,9 @@ in {
|
|||
machine.start()
|
||||
machine.wait_for_unit("multi-user.target");
|
||||
machine.succeed("file /var/lib/jellyfin/data/jellyfin.db")
|
||||
users = machine.succeed("sqlite3 /var/lib/jellyfin/data/jellyfin.db -- \"SELECT * FROM Users WHERE Username = 'admin'\"")
|
||||
users = machine.succeed("sqlite3 /var/lib/jellyfin/data/jellyfin.db -- \"SELECT * FROM Users\"")
|
||||
print(users)
|
||||
if users == "":
|
||||
if machine.succeed("sqlite3 /var/lib/jellyfin/data/jellyfin.db -- \"SELECT * FROM Users WHERE Username = 'admin'\"") == "":
|
||||
assert False, "User not in db"
|
||||
'';
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue