Refactoring

This commit is contained in:
Jakob Lechner 2025-04-09 21:45:49 +02:00
parent 209526d7c0
commit 8e8041e423
51 changed files with 1414 additions and 1368 deletions

View file

@ -8,9 +8,9 @@ let
)
)
);
onlyUniqueItemsInList = (x: lib.lists.length x == lib.lists.length (lib.lists.unique x));
protocols = (x: lib.lists.unique (lib.flatten (map builtins.attrNames (lib.attrValues x))));
mkRange = (x: lib.lists.range (builtins.elemAt x 0) (builtins.elemAt x 1));
onlyUniqueItemsInList = x: lib.lists.length x == lib.lists.length (lib.lists.unique x);
protocols = x: lib.lists.unique (lib.flatten (map builtins.attrNames (lib.attrValues x)));
mkRange = x: lib.lists.range (builtins.elemAt x 0) (builtins.elemAt x 1);
validateList = allowed: builtins.all (x: builtins.elem x allowed);
in
{

View file

@ -8,9 +8,9 @@ let
)
)
);
onlyUniqueItemsInList = (x: lib.lists.length x == lib.lists.length (lib.lists.unique x));
protocols = (x: lib.lists.unique (lib.flatten (map builtins.attrNames (lib.attrValues x))));
mkRange = (x: lib.lists.range (builtins.elemAt x 0) (builtins.elemAt x 1));
onlyUniqueItemsInList = x: lib.lists.length x == lib.lists.length (lib.lists.unique x);
protocols = x: lib.lists.unique (lib.flatten (map builtins.attrNames (lib.attrValues x)));
mkRange = x: lib.lists.range (builtins.elemAt x 0) (builtins.elemAt x 1);
validateList = allowed: builtins.all (x: builtins.elem x allowed);
in
{

View file

@ -5,24 +5,34 @@
flake-utils.url = "github:numtide/flake-utils";
gomod2nix.inputs.flake-utils.follows = "flake-utils";
gomod2nix.inputs.nixpkgs.follows = "nixpkgs";
gomod2nix.url = "github:nix-community/gomod2nix";
gomod2nix = {
url = "github:nix-community/gomod2nix";
inputs.flake-utils.follows = "flake-utils";
inputs.nixpkgs.follows = "nixpkgs";
};
home-manager.inputs.nixpkgs.follows = "nixpkgs";
home-manager.url = "github:nix-community/home-manager/release-24.11";
home-manager = {
url = "github:nix-community/home-manager/release-24.11";
inputs.nixpkgs.follows = "nixpkgs";
};
impermanence.url = "github:nix-community/impermanence";
krops.inputs.flake-utils.follows = "flake-utils";
krops.inputs.nixpkgs.follows = "nixpkgs";
krops.url = "github:Mic92/krops";
krops = {
url = "github:Mic92/krops";
inputs.flake-utils.follows = "flake-utils";
inputs.nixpkgs.follows = "nixpkgs";
};
lanzaboote.url = "github:nix-community/lanzaboote/v0.4.1";
lanzaboote.inputs.nixpkgs.follows = "nixpkgs";
lanzaboote = {
url = "github:nix-community/lanzaboote/v0.4.1";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs";
nix-pre-commit-hooks.url = "github:cachix/git-hooks.nix/master";
nix-pre-commit-hooks = {
url = "github:cachix/git-hooks.nix/master";
inputs.nixpkgs.follows = "nixpkgs";
};
nixos-hardware.url = "github:nixos/nixos-hardware/master";
@ -32,12 +42,16 @@
nur.url = "github:nix-community/NUR";
poetry2nix.inputs.flake-utils.follows = "flake-utils";
poetry2nix.inputs.nixpkgs.follows = "nixpkgs";
poetry2nix.url = "github:nix-community/poetry2nix";
poetry2nix = {
url = "github:nix-community/poetry2nix";
inputs.flake-utils.follows = "flake-utils";
inputs.nixpkgs.follows = "nixpkgs";
};
sops-nix.inputs.nixpkgs.follows = "nixpkgs";
sops-nix.url = "github:Mic92/sops-nix";
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{ self
@ -74,14 +88,14 @@
};
};
devShells.default = pkgs.mkShell {
buildInputs = (with pkgs; [
buildInputs = with pkgs; [
black
just
nixpkgs-fmt
shellcheck
sops
ssh-to-age
]);
];
shellHook = ''
${self.checks.${system}.pre-commit-check.shellHook}
@ -159,8 +173,8 @@
{
_module.args = {
inputs = inputs;
custom-utils = import ./custom-utils { lib = nixpkgs.lib; };
inherit inputs;
custom-utils = import ./custom-utils { inherit (nixpkgs) lib; };
};
}

View file

@ -7,11 +7,11 @@
./services
];
networking.hostName = "aluminium";
services.openssh.enable = true;
security.sudo.wheelNeedsPassword = false;
networking = {
hostName = "aluminium";
useDHCP = false;
vlans = {
lechner = {
@ -78,6 +78,15 @@
iifname "voice" udp dport 5059 accept
ip saddr 217.10.68.150 udp dport 5060 accept
'';
nftables.tables.pppoe = {
family = "ip";
content = ''
chain clamp {
type filter hook forward priority mangle;
oifname "ppp0" tcp flags syn tcp option maxseg size set rt mtu comment "clamp MSS to Path MTU"
}
'';
};
};
@ -116,16 +125,6 @@
};
};
networking.nftables.tables.pppoe = {
family = "ip";
content = ''
chain clamp {
type filter hook forward priority mangle;
oifname "ppp0" tcp flags syn tcp option maxseg size set rt mtu comment "clamp MSS to Path MTU"
}
'';
};
zramSwap = {
enable = true;
algorithm = "zstd";

View file

@ -14,21 +14,6 @@ let
voicemail-sounds = pkgs.callPackage ./voicemail-sounds { };
in
{
systemd.services.asterisk-voicemail-sounds = {
wantedBy = [ "asterisk.service" ];
after = [ "asterisk.service" ];
script = ''
ln -sfn \
${voicemail-sounds}/unavail.wav \
/var/spool/asterisk/voicemail/lechner/876/unavail.wav
'';
restartTriggers = [ voicemail-sounds ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
};
services.asterisk = {
enable = true;
confFiles = {
@ -169,12 +154,12 @@ in
useTheseDefaultConfFiles = [ ];
};
sops.secrets = (lib.listToAttrs (map
sops.secrets = lib.listToAttrs (map
(name: lib.nameValuePair "asterisk-${name}" {
sopsFile = ../../secrets.yaml;
owner = config.users.users.asterisk.name;
})
secretConfigFiles));
secretConfigFiles);
environment.etc = lib.mapAttrs'
(name: _: lib.nameValuePair
"asterisk/${name}.conf"
@ -194,84 +179,99 @@ in
};
};
systemd.services."asterisk-reload-endpoint@" = {
description = "Check if asterisk endpoint is identified and reload it when it is not.";
serviceConfig = {
Type = "oneshot";
systemd.services = {
"asterisk-reload-endpoint@" = {
description = "Check if asterisk endpoint is identified and reload it when it is not.";
serviceConfig = {
Type = "oneshot";
};
environment = {
ENDPOINT = "%I";
};
script = ''
export PATH=${pkgs.lib.makeBinPath [pkgs.asterisk pkgs.gnused pkgs.gnugrep]}
if ! asterisk -r -x "pjsip show endpoint $ENDPOINT" | sed -n '/^===/,/^\s*ParameterName/{//!p}' | grep -q 'Identify:'; then
asterisk -r -x "module reload res_pjsip_endpoint_identifier_ip.so"
fi
'';
};
environment = {
ENDPOINT = "%I";
asterisk-voicemail-sounds = {
wantedBy = [ "asterisk.service" ];
after = [ "asterisk.service" ];
script = ''
ln -sfn \
${voicemail-sounds}/unavail.wav \
/var/spool/asterisk/voicemail/lechner/876/unavail.wav
'';
restartTriggers = [ voicemail-sounds ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
};
script = ''
export PATH=${pkgs.lib.makeBinPath [pkgs.asterisk pkgs.gnused pkgs.gnugrep]}
if ! asterisk -r -x "pjsip show endpoint $ENDPOINT" | sed -n '/^===/,/^\s*ParameterName/{//!p}' | grep -q 'Identify:'; then
asterisk -r -x "module reload res_pjsip_endpoint_identifier_ip.so"
fi
'';
};
"asterisk-voicemail-call@" = {
description = "Check if voicemail exists and place a call to the voicemail application.";
serviceConfig = {
Type = "oneshot";
};
scriptArgs = "%I";
script = ''
export PATH=${pkgs.lib.makeBinPath [pkgs.asterisk pkgs.coreutils pkgs.findutils]}
number="$(echo "$1" | cut -d ':' -f 1)"
user="$(echo "$1" | cut -d ':' -f 2)"
channel="PJSIP/$(echo "$1" | cut -d ':' -f 3)"
systemd.timers.asterisk-reload-endpoint = {
description = "Check if asterisk endpoint is identified and reload it when it is not.";
after = [ "asterisk.service" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = "*-*-* *:*:00";
Unit = "asterisk-reload-endpoint@sipgate.service";
if ! find "/var/spool/asterisk/voicemail/$user/$number/INBOX/" -mindepth 1 -maxdepth 1 | read; then
exit
fi
callfile="$(mktemp -p /tmp XXXXXXXXXX.call)"
chmod 644 "$callfile"
cat > "$callfile" << EOF
Channel: $channel
WaitTime: 15
Application: VoiceMailMain
Data: $number@$user
CallerID: Voicemail
EOF
mv "$callfile" /var/spool/asterisk/outgoing/
'';
};
};
systemd.services."asterisk-voicemail-call@" = {
description = "Check if voicemail exists and place a call to the voicemail application.";
serviceConfig = {
Type = "oneshot";
systemd.timers = {
asterisk-reload-endpoint = {
description = "Check if asterisk endpoint is identified and reload it when it is not.";
after = [ "asterisk.service" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = "*-*-* *:*:00";
Unit = "asterisk-reload-endpoint@sipgate.service";
};
};
scriptArgs = "%I";
script = ''
export PATH=${pkgs.lib.makeBinPath [pkgs.asterisk pkgs.coreutils pkgs.findutils]}
number="$(echo "$1" | cut -d ':' -f 1)"
user="$(echo "$1" | cut -d ':' -f 2)"
channel="PJSIP/$(echo "$1" | cut -d ':' -f 3)"
if ! find "/var/spool/asterisk/voicemail/$user/$number/INBOX/" -mindepth 1 -maxdepth 1 | read; then
exit
fi
callfile="$(mktemp -p /tmp XXXXXXXXXX.call)"
chmod 644 "$callfile"
cat > "$callfile" << EOF
Channel: $channel
WaitTime: 15
Application: VoiceMailMain
Data: $number@$user
CallerID: Voicemail
EOF
mv "$callfile" /var/spool/asterisk/outgoing/
'';
};
systemd.timers.asterisk-voicemail-call-10 = {
description = "Check if voicemail exists and place a call to the voicemail application.";
after = [ "asterisk.service" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = "*-*-* 07..22:00,20,40:00";
Unit = "asterisk-voicemail-call@876:lechner:10.service";
asterisk-voicemail-call-10 = {
description = "Check if voicemail exists and place a call to the voicemail application.";
after = [ "asterisk.service" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = "*-*-* 07..22:00,20,40:00";
Unit = "asterisk-voicemail-call@876:lechner:10.service";
};
};
asterisk-voicemail-call-11 = {
description = "Check if voicemail exists and place a call to the voicemail application.";
after = [ "asterisk.service" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = "*-*-* 07..22:00,10,30:50";
Unit = "asterisk-voicemail-call@876:lechner:11.service";
};
};
};
systemd.timers.asterisk-voicemail-call-11 = {
description = "Check if voicemail exists and place a call to the voicemail application.";
after = [ "asterisk.service" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = "*-*-* 07..22:00,10,30:50";
Unit = "asterisk-voicemail-call@876:lechner:11.service";
};
};
#voicemailCallScript
}

View file

@ -78,8 +78,8 @@ in
unit_system = "metric";
time_zone = "Europe/Berlin";
temperature_unit = "C";
longitude = config.location.longitude;
latitude = config.location.latitude;
inherit (config.location) longitude;
inherit (config.location) latitude;
};
default_config = { };
"automation nix" = [

View file

@ -8,8 +8,6 @@
./services
];
services.fstrim.enable = true;
networking = {
hostName = "copper";
extraHosts = lib.concatStringsSep "\n" (
@ -32,24 +30,28 @@
priority = 1;
};
services.snapper.configs = {
home = {
SUBVOLUME = "/home";
ALLOW_USERS = [ "jalr" ];
TIMELINE_CREATE = true;
TIMELINE_CLEANUP = true;
TIMELINE_LIMIT_HOURLY = 12;
TIMELINE_LIMIT_DAILY = 7;
TIMELINE_LIMIT_WEEKLY = 4;
TIMELINE_LIMIT_MONTHLY = 3;
TIMELINE_LIMIT_YEARLY = 0;
BACKGROUND_COMPARISON = "yes";
NUMBER_CLEANUP = "no";
NUMBER_MIN_AGE = "1800";
NUMBER_LIMIT = "100";
NUMBER_LIMIT_IMPORTANT = "10";
EMPTY_PRE_POST_CLEANUP = "yes";
EMPTY_PRE_POST_MIN_AGE = "1800";
services = {
fstrim.enable = true;
flatpak.enable = true;
snapper.configs = {
home = {
SUBVOLUME = "/home";
ALLOW_USERS = [ "jalr" ];
TIMELINE_CREATE = true;
TIMELINE_CLEANUP = true;
TIMELINE_LIMIT_HOURLY = 12;
TIMELINE_LIMIT_DAILY = 7;
TIMELINE_LIMIT_WEEKLY = 4;
TIMELINE_LIMIT_MONTHLY = 3;
TIMELINE_LIMIT_YEARLY = 0;
BACKGROUND_COMPARISON = "yes";
NUMBER_CLEANUP = "no";
NUMBER_MIN_AGE = "1800";
NUMBER_LIMIT = "100";
NUMBER_LIMIT_IMPORTANT = "10";
EMPTY_PRE_POST_CLEANUP = "yes";
EMPTY_PRE_POST_MIN_AGE = "1800";
};
};
};
@ -68,7 +70,5 @@
};
system.stateVersion = "24.05";
services.flatpak.enable = true;
}

View file

@ -1,4 +1,4 @@
{ ... }@inputs:
inputs:
let
hardware = inputs.nixos-hardware.nixosModules;
in

View file

@ -28,7 +28,7 @@ let
luksDev = "-part3";
biosBoot = "-part4";
};
efiSystemPartitions = (map (diskName: diskName + partitionScheme.efiBoot) (lib.attrValues disks));
efiSystemPartitions = map (diskName: diskName + partitionScheme.efiBoot) (lib.attrValues disks);
in
with lib; {
imports = [
@ -154,19 +154,19 @@ with lib; {
};
supportedFilesystems = [ "zfs" ];
zfs = {
devNodes = devNodes;
inherit devNodes;
forceImportRoot = false;
};
loader = {
efi = {
canTouchEfiVariables = (if removableEfi then false else true);
efiSysMountPoint = ("/boot/efis/" + (head (lib.attrValues disks))
+ partitionScheme.efiBoot);
canTouchEfiVariables = if removableEfi then false else true;
efiSysMountPoint = "/boot/efis/" + (head (lib.attrValues disks))
+ partitionScheme.efiBoot;
};
generationsDir.copyKernels = true;
grub = {
enable = true;
devices = (map (diskName: devNodes + diskName) (attrValues disks));
devices = map (diskName: devNodes + diskName) (attrValues disks);
efiInstallAsRemovable = removableEfi;
copyKernels = true;
efiSupport = true;
@ -176,11 +176,11 @@ with lib; {
terminal_input --append serial
terminal_output --append serial
'';
extraInstallCommands = (toString (map
extraInstallCommands = toString (map
(diskName: ''
${pkgs.coreutils-full}/bin/cp -r ${config.boot.loader.efi.efiSysMountPoint}/EFI /boot/efis/${diskName}${partitionScheme.efiBoot}
'')
(tail (attrValues disks))));
(tail (attrValues disks)));
};
};
kernelParams = [

View file

@ -6,11 +6,13 @@ in
services.avahi = {
enable = true;
allowInterfaces = [ interfaces.lan ];
publish.domain = true;
publish.enable = true;
publish.userServices = true;
publish.workstation = true;
openFirewall = false;
publish = {
domain = true;
enable = true;
userServices = true;
workstation = true;
};
};
networking.firewall.interfaces."${interfaces.lan}".allowedUDPPorts = [

View file

@ -8,23 +8,29 @@ in
sopsFile = ../secrets.yaml;
};
services.calibre-server = {
enable = true;
port = ports.calibre-server.tcp;
host = "127.0.0.1";
};
services.calibre-web = {
enable = true;
user = config.services.calibre-server.user;
group = config.services.calibre-server.group;
listen = {
ip = "127.0.0.1";
port = ports.calibre-web.tcp;
services = {
calibre-server = {
enable = true;
port = ports.calibre-server.tcp;
host = "127.0.0.1";
};
calibre-web = {
enable = true;
inherit (config.services.calibre-server) user;
inherit (config.services.calibre-server) group;
listen = {
ip = "127.0.0.1";
port = ports.calibre-web.tcp;
};
options = {
enableBookUploading = true;
reverseProxyAuth = {
enable = true;
header = "X-Remote-User";
};
};
};
options.enableBookUploading = true;
options.reverseProxyAuth.enable = true;
options.reverseProxyAuth.header = "X-Remote-User";
};
systemd.services.calibre-web = {

View file

@ -5,256 +5,264 @@ let
domain = "hass.jalr.de";
in
{
sops.secrets.home-assistant = {
sopsFile = ../secrets.yaml;
owner = "root";
group = "hass";
mode = "0640";
};
sops.secrets."mqtt-users/home-assistant" = {
sopsFile = ../secrets.yaml;
};
sops.secrets."mqtt-users/valetudo" = {
sopsFile = ../secrets.yaml;
};
services.home-assistant = {
enable = true;
lovelaceConfig = {
title = "Home";
views = [
{
path = "default_view";
title = "Home";
cards = [
{
title = "Eingang";
type = "entities";
entities = [
{
entity = "light.eingang_deckenleuchte_deckenleuchte";
name = "Deckenleuchte";
}
];
}
{
name = "Esstisch";
type = "entities";
entities = [
{
entity = "light.yeelight_meteorite_ambient_light";
name = "Ambient light";
}
{
entity = "light.yeelight_meteorite_ceiling_light";
name = "Ceiling light";
}
{
entity = "light.yeelight_meteorite_night_light";
name = "Night light";
}
];
}
];
}
];
sops.secrets = {
home-assistant = {
sopsFile = ../secrets.yaml;
owner = "root";
group = "hass";
mode = "0640";
};
extraComponents = [
# See https://www.home-assistant.io/integrations
"bthome"
"caldav"
"esphome"
"local_todo"
"openweathermap"
"wyoming"
"xiaomi_ble"
"vlc_telnet"
];
customComponents = with pkgs.home-assistant-custom-components; [
adaptive_lighting
];
customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
valetudo-map-card
];
lovelaceConfigWritable = false;
configWritable = false;
config = {
http = {
server_host = [ "127.0.0.1" ];
server_port = ports.home-assistant.tcp;
use_x_forwarded_for = true;
trusted_proxies = [ "127.0.0.1" ];
};
homeassistant = {
unit_system = "metric";
time_zone = "Europe/Berlin";
temperature_unit = "C";
longitude = config.location.longitude;
latitude = config.location.latitude;
external_url = "https://${domain}/";
internal_url = "https://${domain}/";
};
default_config = { };
adaptive_lighting = {
lights = [
"light.yeelight_meteorite_ceiling_light"
"light.eingang_deckenleuchte_deckenleuchte"
"light.led_panel_schreibtisch_panel"
"light.kueche_leiste_led_light"
"light.badspiegel_background_light"
"light.badspiegel_front_light"
"mqtt-users/home-assistant" = {
sopsFile = ../secrets.yaml;
};
"mqtt-users/valetudo" = {
sopsFile = ../secrets.yaml;
};
};
networking.firewall.interfaces = {
"${interfaces.lan}".allowedTCPPorts = [ ports.mqtt.tcp ];
iot.allowedTCPPorts = [ ports.mqtt.tcp ];
};
services = {
home-assistant = {
enable = true;
lovelaceConfig = {
title = "Home";
views = [
{
path = "default_view";
title = "Home";
cards = [
{
title = "Eingang";
type = "entities";
entities = [
{
entity = "light.eingang_deckenleuchte_deckenleuchte";
name = "Deckenleuchte";
}
];
}
{
name = "Esstisch";
type = "entities";
entities = [
{
entity = "light.yeelight_meteorite_ambient_light";
name = "Ambient light";
}
{
entity = "light.yeelight_meteorite_ceiling_light";
name = "Ceiling light";
}
{
entity = "light.yeelight_meteorite_night_light";
name = "Night light";
}
];
}
];
}
];
};
"automation nix" = [
{
alias = "Waschmaschine fertig Benachrichtigung";
trigger = {
platform = "state";
entity_id = "sensor.waschmaschine_aktueller_vorgang";
to = "Knitterschutz/Ende";
};
action = [
{
service = "notify.mobile_app_shift6mq";
data = {
message = "Die Waschmaschine hat das Programm beendet.";
title = "Wäsche fertig";
};
}
extraComponents = [
# See https://www.home-assistant.io/integrations
"bthome"
"caldav"
"esphome"
"local_todo"
"openweathermap"
"wyoming"
"xiaomi_ble"
"vlc_telnet"
];
customComponents = with pkgs.home-assistant-custom-components; [
adaptive_lighting
];
customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
valetudo-map-card
];
lovelaceConfigWritable = false;
configWritable = false;
config = {
http = {
server_host = [ "127.0.0.1" ];
server_port = ports.home-assistant.tcp;
use_x_forwarded_for = true;
trusted_proxies = [ "127.0.0.1" ];
};
homeassistant = {
unit_system = "metric";
time_zone = "Europe/Berlin";
temperature_unit = "C";
inherit (config.location) longitude;
inherit (config.location) latitude;
external_url = "https://${domain}/";
internal_url = "https://${domain}/";
};
default_config = { };
adaptive_lighting = {
lights = [
"light.yeelight_meteorite_ceiling_light"
"light.eingang_deckenleuchte_deckenleuchte"
"light.led_panel_schreibtisch_panel"
"light.kueche_leiste_led_light"
"light.badspiegel_background_light"
"light.badspiegel_front_light"
];
}
];
"automation ui" = "!include automations.yaml";
"scene nix" = [
];
"scene ui" = "!include scenes.yaml";
bluetooth = { };
device_tracker = [
{
platform = "bluetooth_le_tracker";
}
];
"script nix" = [
{
lights_off_except = {
icon = "mdi:home-lightbulb";
fields.exclude_lights.description = "Excluded lights as list";
sequence = [
};
"automation nix" = [
{
alias = "Waschmaschine fertig Benachrichtigung";
trigger = {
platform = "state";
entity_id = "sensor.waschmaschine_aktueller_vorgang";
to = "Knitterschutz/Ende";
};
action = [
{
service = "logbook.log";
data_template = {
entity_id = "script.turn_off_lights";
name = "Exclude log";
message = "Turning of all lights except: {{ exclude_lights }}";
service = "notify.mobile_app_shift6mq";
data = {
message = "Die Waschmaschine hat das Programm beendet.";
title = "Wäsche fertig";
};
}
{
service = "light.turn_off";
data_template.entity_id = ''
{{ states.light | rejectattr('entity_id', 'in', exclude_lights) | rejectattr('state', 'in', 'off') | join(',', attribute='entity_id') }}
'';
}
];
}
];
"automation ui" = "!include automations.yaml";
"scene nix" = [
];
"scene ui" = "!include scenes.yaml";
bluetooth = { };
device_tracker = [
{
platform = "bluetooth_le_tracker";
}
];
"script nix" = [
{
lights_off_except = {
icon = "mdi:home-lightbulb";
fields.exclude_lights.description = "Excluded lights as list";
sequence = [
{
service = "logbook.log";
data_template = {
entity_id = "script.turn_off_lights";
name = "Exclude log";
message = "Turning of all lights except: {{ exclude_lights }}";
};
}
{
service = "light.turn_off";
data_template.entity_id = ''
{{ states.light | rejectattr('entity_id', 'in', exclude_lights) | rejectattr('state', 'in', 'off') | join(',', attribute='entity_id') }}
'';
}
];
};
}
];
"script ui" = "!include scripts.yaml";
calendar = [
{
platform = "caldav";
username = "jalr@jalr.de";
password = "!secret radicale";
url = "https://cal.jalr.de/radicale";
}
];
mqtt = { };
media_player = [
{
platform = "mpd";
name = "mpd@iron";
host = "127.0.0.1";
}
];
};
};
mosquitto = {
enable = true;
persistence = true;
listeners = [
{
port = ports.mqtt.tcp;
users = {
valetudo = {
passwordFile = config.sops.secrets."mqtt-users/valetudo".path;
acl = [
"readwrite homeassistant/+/donald/#"
"readwrite valetudo/donald/#"
];
};
home-assistant = {
passwordFile = config.sops.secrets."mqtt-users/home-assistant".path;
acl = [ "readwrite #" ];
};
};
}
];
"script ui" = "!include scripts.yaml";
calendar = [
{
platform = "caldav";
username = "jalr@jalr.de";
password = "!secret radicale";
url = "https://cal.jalr.de/radicale";
}
];
mqtt = { };
media_player = [
{
platform = "mpd";
name = "mpd@iron";
host = "127.0.0.1";
}
];
};
};
services.mosquitto = {
enable = true;
persistence = true;
listeners = [
{
port = ports.mqtt.tcp;
users = {
valetudo = {
passwordFile = config.sops.secrets."mqtt-users/valetudo".path;
acl = [
"readwrite homeassistant/+/donald/#"
"readwrite valetudo/donald/#"
];
};
home-assistant = {
passwordFile = config.sops.secrets."mqtt-users/home-assistant".path;
acl = [ "readwrite #" ];
};
};
}
systemd.services = {
home-assistant.serviceConfig.ExecStartPre = [
(
pkgs.writeShellScript "home-assistant-secrets" ''
ln -sf "${config.sops.secrets.home-assistant.path}" "${config.services.home-assistant.configDir}/secrets.yaml"
''
)
];
};
systemd.services.hass-vlc = {
script = ''
exec ${pkgs.vlc}/bin/cvlc \
--no-video \
-I telnet \
--telnet-password=vlc \
--sout='#transcode{acodec=s16le,channels=2,samplerate=48000}:std{access=file,mux=raw,dst=/run/snapserver/hass.fifo}' \
--aout=none
'';
wants = [ "snapserver.service" ];
after = [ "snapserver.service" ];
serviceConfig = {
BindPaths = [ "/run/snapserver/hass.fifo" ];
BindReadOnlyPaths = [ "/nix/store" "/etc/ssl/certs" "/etc/static/ssl/certs" ];
CapabilityBoundingSet = "";
DynamicUser = "true";
Group = "snapserver";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = lib.mkForce true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "noaccess";
ProtectSystem = "strict";
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RootDirectory = "/run/hass-vlc";
RuntimeDirectory = "hass-vlc";
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@privileged" ];
hass-vlc = {
script = ''
exec ${pkgs.vlc}/bin/cvlc \
--no-video \
-I telnet \
--telnet-password=vlc \
--sout='#transcode{acodec=s16le,channels=2,samplerate=48000}:std{access=file,mux=raw,dst=/run/snapserver/hass.fifo}' \
--aout=none
'';
wants = [ "snapserver.service" ];
after = [ "snapserver.service" ];
serviceConfig = {
BindPaths = [ "/run/snapserver/hass.fifo" ];
BindReadOnlyPaths = [ "/nix/store" "/etc/ssl/certs" "/etc/static/ssl/certs" ];
CapabilityBoundingSet = "";
DynamicUser = "true";
Group = "snapserver";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = lib.mkForce true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "noaccess";
ProtectSystem = "strict";
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RootDirectory = "/run/hass-vlc";
RuntimeDirectory = "hass-vlc";
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@privileged" ];
};
wantedBy = [ "multi-user.target" ];
};
wantedBy = [ "multi-user.target" ];
};
networking.firewall.interfaces."${interfaces.lan}".allowedTCPPorts = [ ports.mqtt.tcp ];
networking.firewall.interfaces.iot.allowedTCPPorts = [ ports.mqtt.tcp ];
systemd.services.home-assistant.serviceConfig.ExecStartPre = [
(
pkgs.writeShellScript "home-assistant-secrets" ''
ln -sf "${config.sops.secrets.home-assistant.path}" "${config.services.home-assistant.configDir}/secrets.yaml"
''
)
];
systemd.tmpfiles.rules = [
"f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
"f ${config.services.home-assistant.configDir}/scenes.yaml 0755 hass hass"

View file

@ -13,27 +13,27 @@ let
};
in
{
sops.secrets = (
lib.listToAttrs (map
(name: lib.nameValuePair "wireguard_key_${name}" {
sopsFile = ../secrets.yaml;
})
[
"hetzner-ha"
]
)
sops.secrets = lib.listToAttrs (map
(name: lib.nameValuePair "wireguard_key_${name}" {
sopsFile = ../secrets.yaml;
})
[
"hetzner-ha"
]
);
networking.iproute2.enable = true;
networking.iproute2.rttablesExtraConfig = ''
${toString rtTable.id} ${rtTable.name}
'';
networking.wireguard.interfaces = {
hetzner-ha = {
networking = {
iproute2 = {
enable = true;
rttablesExtraConfig = ''
${toString rtTable.id} ${rtTable.name}
'';
};
firewall.allowedUDPPorts = [ listenPort ];
wireguard.interfaces.hetzner-ha = {
ips = [ "${externalIp}/32" ];
privateKeyFile = config.sops.secrets.wireguard_key_hetzner-ha.path;
listenPort = listenPort;
inherit listenPort;
table = rtTable.name;
postSetup = ''
${pkgs.iproute2}/bin/ip rule add from ${externalIp} to 192.168.0.0/16 table main priority 10
@ -44,7 +44,7 @@ in
${pkgs.iproute2}/bin/ip rule del from ${externalIp} table ${rtTable.name} priority 20
'';
peers = [{
publicKey = publicKey;
inherit publicKey;
endpoint = "${remoteHost}:${toString remotePort}";
persistentKeepalive = 25;
allowedIPs = [
@ -53,6 +53,4 @@ in
}];
};
};
networking.firewall.allowedUDPPorts = [ listenPort ];
}

View file

@ -14,19 +14,21 @@ in
enableACME = true;
forceSSL = true;
basicAuthFile = config.sops.secrets.radicale-htpasswd.path;
locations."/radicale/" = {
proxyPass = "http://127.0.0.1:${toString ports.radicale.tcp}/";
recommendedProxySettings = true;
#basicAuthFile = "";
extraConfig = ''
proxy_set_header X-Script-Name /radicale;
proxy_set_header X-Remote-User $remote_user;
'';
# proxy_pass_request_headers = on;
# underscores_in_headers = on;
locations = {
"/radicale/" = {
proxyPass = "http://127.0.0.1:${toString ports.radicale.tcp}/";
recommendedProxySettings = true;
#basicAuthFile = "";
extraConfig = ''
proxy_set_header X-Script-Name /radicale;
proxy_set_header X-Remote-User $remote_user;
'';
# proxy_pass_request_headers = on;
# underscores_in_headers = on;
};
"/.well-known/caldav".return = "301 $scheme://$host:$server_port/radicale";
"/.well-known/carddav".return = "301 $scheme://$host:$server_port/radicale";
};
locations."/.well-known/caldav".return = "301 $scheme://$host:$server_port/radicale";
locations."/.well-known/carddav".return = "301 $scheme://$host:$server_port/radicale";
};
};

View file

@ -3,9 +3,9 @@ let
ports = import ../ports.nix args;
domain = "rmfakecloud.jalr.de";
cfg = config.services.rmfakecloud;
mkEnvironment = (settings: lib.strings.concatLines (
mkEnvironment = settings: lib.strings.concatLines (
lib.attrsets.mapAttrsToList (name: value: "export ${name}='${value}'") settings
));
);
managementScript = pkgs.writeShellScriptBin "rmfakecloud" ''
[[ $(id -u) == "rmfakecloud" ]] || exec sudo -u rmfakecloud -- "$0" "$@"
set -a

View file

@ -24,54 +24,44 @@
services.blueman.enable = true;
systemd.services.bluetooth-auto-pair = {
wantedBy = [
"bluetooth.service"
];
after = [
"bluetooth.service"
];
bindsTo = [
"bluetooth.service"
];
serviceConfig = {
Type = "simple";
ExecStart = pkgs.writeShellScript "exec-start" ''
${pkgs.bluez}/bin/bluetoothctl <<EOF
discoverable on
pairable on
EOF
systemd.services = {
bluetooth-auto-pair = {
wantedBy = [ "bluetooth.service" ];
after = [ "bluetooth.service" ];
bindsTo = [ "bluetooth.service" ];
serviceConfig = {
Type = "simple";
ExecStart = pkgs.writeShellScript "exec-start" ''
${pkgs.bluez}/bin/bluetoothctl <<EOF
discoverable on
pairable on
EOF
${pkgs.coreutils}/bin/yes | ${pkgs.bluez-tools}/bin/bt-agent -c NoInputNoOutput
'';
ExecStop = pkgs.writeShellScript "exec-stop" ''
kill -s SIGINT $MAINPID
'';
Restart = "on-failure";
${pkgs.coreutils}/bin/yes | ${pkgs.bluez-tools}/bin/bt-agent -c NoInputNoOutput
'';
ExecStop = pkgs.writeShellScript "exec-stop" ''
kill -s SIGINT $MAINPID
'';
Restart = "on-failure";
};
};
};
systemd.services.bluealsa-aplay = {
wantedBy = [
"multi-user.target"
];
serviceConfig = {
DynamicUser = true;
Type = "simple";
ExecStart = "${pkgs.bluez-alsa}/bin/bluealsa-aplay --profile-a2dp --pcm=default:CARD=bluetooth 00:00:00:00:00:00";
Restart = "on-failure";
SupplementaryGroups = [ "audio" ];
bluealsa-aplay = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
DynamicUser = true;
Type = "simple";
ExecStart = "${pkgs.bluez-alsa}/bin/bluealsa-aplay --profile-a2dp --pcm=default:CARD=bluetooth 00:00:00:00:00:00";
Restart = "on-failure";
SupplementaryGroups = [ "audio" ];
};
};
};
systemd.services.bluealsa-a2dp = {
wantedBy = [
"multi-user.target"
];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.bluez-alsa}/bin/bluealsa -p a2dp-sink";
Restart = "on-failure";
bluealsa-a2dp = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.bluez-alsa}/bin/bluealsa -p a2dp-sink";
Restart = "on-failure";
};
};
};
}

View file

@ -30,50 +30,52 @@ in
jalr.libvirt.enable = true;
systemd.services.libvirt-guests.serviceConfig.ExecStop = [
""
"${shutdownAndroidVm} ${vmName}"
"${pkgs.libvirt}/libexec/libvirt-guests.sh stop"
];
systemd.services = {
libvirt-guests.serviceConfig.ExecStop = [
""
"${shutdownAndroidVm} ${vmName}"
"${pkgs.libvirt}/libexec/libvirt-guests.sh stop"
];
systemd.services."whatsapp@" = {
description = "Start Android VM, wait for WhatsApp and shut down VM.";
serviceConfig = {
Type = "oneshot";
};
environment.VM = "%i";
script = ''
export PATH=${pkgs.lib.makeBinPath [pkgs.libvirt pkgs.gnused pkgs.android-tools pkgs.coreutils]}
"whatsapp@" = {
description = "Start Android VM, wait for WhatsApp and shut down VM.";
serviceConfig = {
Type = "oneshot";
};
environment.VM = "%i";
script = ''
export PATH=${pkgs.lib.makeBinPath [pkgs.libvirt pkgs.gnused pkgs.android-tools pkgs.coreutils]}
domstate="$(virsh domstate "$VM")"
domstate="$(virsh domstate "$VM")"
if [ "$domstate" != "running" ]; then
virsh start "$VM"
fi
echo "Wait until IP of Android VM is known"
while :; do
host="$(virsh -q domifaddr --domain "$VM" | sed -n -r 's#.*ipv4\s*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/[0-9]+$#\1#p')"
if [ "$host" ]; then
break
if [ "$domstate" != "running" ]; then
virsh start "$VM"
fi
sleep 1
done
port=5555
adb connect "$host:$port"
echo "Wait until IP of Android VM is known"
while :; do
host="$(virsh -q domifaddr --domain "$VM" | sed -n -r 's#.*ipv4\s*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/[0-9]+$#\1#p')"
if [ "$host" ]; then
break
fi
sleep 1
done
echo "Waiting for WhatsApp"
while ! adb -s "$host:$port" shell -- pgrep com.whatsapp > /dev/null; do
sleep 1
done
port=5555
adb connect "$host:$port"
echo "Sleeping..."
sleep 5m
echo "Waiting for WhatsApp"
while ! adb -s "$host:$port" shell -- pgrep com.whatsapp > /dev/null; do
sleep 1
done
echo "Shutting down Android"
adb -s "$host:$port" shell -- reboot -p
'';
echo "Sleeping..."
sleep 5m
echo "Shutting down Android"
adb -s "$host:$port" shell -- reboot -p
'';
};
};
systemd.timers."whatsapp-${vmName}" = {
description = "Start Android VM to run WhatsApp";

View file

@ -2,7 +2,7 @@
{
boot.initrd.postDeviceCommands =
let
device = config.disko.devices.disk.virt.content.partitions.linux.device;
inherit (config.disko.devices.disk.virt.content.partitions.linux) device;
in
lib.mkAfter ''
mkdir /mnt
@ -14,16 +14,17 @@
btrfs subvolume snapshot /mnt/root-blank /mnt/root
'';
services.openssh = {
hostKeys = lib.mkForce [{
path = "/persist/etc/ssh/ssh_host_ed25519_key";
type = "ed25519";
}];
services = {
openssh = {
hostKeys = lib.mkForce [{
path = "/persist/etc/ssh/ssh_host_ed25519_key";
type = "ed25519";
}];
};
forgejo.stateDir = "/persist/var/lib/forgejo";
postgresql.dataDir = "/persist/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}";
};
services.forgejo.stateDir = "/persist/var/lib/forgejo";
services.postgresql.dataDir = "/persist/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}";
fileSystems."/persist".neededForBoot = true;
environment.persistence."/persist" = {
hideMounts = true;

View file

@ -10,44 +10,44 @@ in
owner = config.systemd.services.hedgedoc.serviceConfig.User;
sopsFile = ../secrets.yaml;
};
services.hedgedoc = {
enable = true;
settings =
let
day = 24 * 60 * 60 * 1000;
in
{
domain = domain;
protocolUseSSL = true;
csp.enable = true;
port = ports.hedgedoc.tcp;
db = {
dialect = "postgres";
host = "/run/postgresql";
user = "hedgedoc";
database = "hedgedoc";
services = {
hedgedoc = {
enable = true;
settings =
let
day = 24 * 60 * 60 * 1000;
in
{
inherit domain;
protocolUseSSL = true;
csp.enable = true;
port = ports.hedgedoc.tcp;
db = {
dialect = "postgres";
host = "/run/postgresql";
user = "hedgedoc";
database = "hedgedoc";
};
allowEmailRegister = false;
sessionSecret = config.sops.secrets.hedgedoc-session-secret.path;
sessionLife = 90 * day;
};
allowEmailRegister = false;
sessionSecret = config.sops.secrets.hedgedoc-session-secret.path;
sessionLife = 90 * day;
};
postgresql = {
enable = true;
ensureDatabases = [ "hedgedoc" ];
ensureUsers = [{
name = "hedgedoc";
ensureDBOwnership = true;
}];
};
nginx.virtualHosts."${domain}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://${cfg.settings.host}:${toString cfg.settings.port}";
};
};
services.postgresql = {
enable = true;
ensureDatabases = [ "hedgedoc" ];
ensureUsers = [{
name = "hedgedoc";
ensureDBOwnership = true;
}];
};
services.nginx.virtualHosts."${domain}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://${cfg.settings.host}:${toString cfg.settings.port}";
};
};
}

View file

@ -6,15 +6,13 @@ let
publicKey = "GCmQs7upvDYFueEfqD2yJkkOZg3K7YaGluWWzdjsyTo=";
in
{
sops.secrets = (
lib.listToAttrs (map
(name: lib.nameValuePair "wireguard_key_${name}" {
sopsFile = ../secrets.yaml;
})
[
"hetzner-ha"
]
)
sops.secrets = lib.listToAttrs (map
(name: lib.nameValuePair "wireguard_key_${name}" {
sopsFile = ../secrets.yaml;
})
[
"hetzner-ha"
]
);
#boot.kernel.sysctl = {
@ -22,24 +20,27 @@ in
# "net.ipv4.conf.hetzner-ha.proxy_arp" = 1;
# "net.ipv4.conf.enp1s0.proxy_arp" = 1;
#};
networking.interfaces.hetzner-ha.proxyARP = true;
networking.interfaces.enp1s0.proxyARP = true;
networking.wireguard.interfaces = {
hetzner-ha = {
ips = [ ];
privateKeyFile = config.sops.secrets.wireguard_key_hetzner-ha.path;
listenPort = listenPort;
networking = {
interfaces = {
hetzner-ha.proxyARP = true;
enp1s0.proxyARP = true;
};
firewall.allowedUDPPorts = [ listenPort ];
wireguard.interfaces = {
hetzner-ha = {
ips = [ ];
privateKeyFile = config.sops.secrets.wireguard_key_hetzner-ha.path;
inherit listenPort;
peers = [{
publicKey = publicKey;
persistentKeepalive = 25;
allowedIPs = [
"159.69.103.126/32"
];
}];
peers = [{
inherit publicKey;
persistentKeepalive = 25;
allowedIPs = [
"159.69.103.126/32"
];
}];
};
};
};
networking.firewall.allowedUDPPorts = [ listenPort ];
}

View file

@ -2,10 +2,14 @@
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot.initrd.availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
boot = {
initrd = {
availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" "sr_mod" ];
kernelModules = [ ];
};
kernelModules = [ ];
extraModulePackages = [ ];
};
fileSystems = {
"/" = {

View file

@ -23,67 +23,15 @@ in
};
};
services.pretix = {
enable = true;
settings = {
pretix = {
instance_name = "Digitaler Dienst GmbH";
url = "https://${domain}";
registration = false;
password_reset = true;
};
locale = {
default = "de";
timezone = "Europe/Berlin";
};
mail = {
from = "no-reply@tickets.weinturm-open-air.de";
};
redis.location = "unix:///run/redis-pretix/redis.sock?db=0";
celery.backend = "redis+socket:///run/redis-pretix/redis.sock?virtual_host=2";
celery.broker = "redis+socket:///run/redis-pretix/redis.sock?virtual_host=1";
};
nginx = {
enable = true;
inherit domain;
};
gunicorn = {
extraArgs = [
"--workers=${toString gunicornWorkers}"
];
};
};
# Add user to `redis-pretix` group
# to grant access to /run/redis-pretix/redis.sock
users.users.pretix.extraGroups = [ "redis-pretix" ];
services.pretix-banktool = {
enable = true;
days = 14;
secretsFile = config.sops.secrets.pretix-banktool-cfg.path;
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.nginx = lib.mkIf cfg.nginx.enable {
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = {
"${cfg.nginx.domain}" = {
enableACME = true;
forceSSL = true;
kTLS = true;
extraConfig = ''
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload' always;
more_set_headers Referrer-Policy same-origin;
more_set_headers X-Content-Type-Options nosniff;
'';
serverAliases = extraDomains;
};
};
security.acme = {
acceptTerms = true;
defaults.email = lib.mkForce "helfer@weinturm-open-air.de";
};
jalr.mailserver = {
@ -101,8 +49,62 @@ in
spam.enable = false;
};
security.acme = {
acceptTerms = true;
defaults.email = lib.mkForce "helfer@weinturm-open-air.de";
services = {
pretix = {
enable = true;
settings = {
pretix = {
instance_name = "Digitaler Dienst GmbH";
url = "https://${domain}";
registration = false;
password_reset = true;
};
locale = {
default = "de";
timezone = "Europe/Berlin";
};
mail = {
from = "no-reply@tickets.weinturm-open-air.de";
};
redis.location = "unix:///run/redis-pretix/redis.sock?db=0";
celery.backend = "redis+socket:///run/redis-pretix/redis.sock?virtual_host=2";
celery.broker = "redis+socket:///run/redis-pretix/redis.sock?virtual_host=1";
};
nginx = {
enable = true;
inherit domain;
};
gunicorn = {
extraArgs = [
"--workers=${toString gunicornWorkers}"
];
};
};
pretix-banktool = {
enable = true;
days = 14;
secretsFile = config.sops.secrets.pretix-banktool-cfg.path;
};
nginx = lib.mkIf cfg.nginx.enable {
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = {
"${cfg.nginx.domain}" = {
enableACME = true;
forceSSL = true;
kTLS = true;
extraConfig = ''
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload' always;
more_set_headers Referrer-Policy same-origin;
more_set_headers X-Content-Type-Options nosniff;
'';
serverAliases = extraDomains;
};
};
};
};
}

View file

@ -9,9 +9,11 @@ in
};
config = lib.mkIf cfg.bluetooth.enable {
hardware.bluetooth.enable = true;
services.blueman.enable = true;
services.ofono.enable = true;
services.upower.enable = true;
services = {
blueman.enable = true;
ofono.enable = true;
upower.enable = true;
};
hardware.bluetooth.settings.General.Experimental = true; # to show battery state
};
}

View file

@ -45,20 +45,19 @@ in
});
};
};
config = lib.mkIf cfg.enable
(
let
makeUsbDevPath = usbDevice: "/dev/disk/" + usbDevice;
makeMountPath = usbDevice: "/key/" + (builtins.hashString "md5" usbDevice);
usbFsType = "vfat";
config = lib.mkIf cfg.enable (
let
makeUsbDevPath = usbDevice: "/dev/disk/" + usbDevice;
makeMountPath = usbDevice: "/key/" + (builtins.hashString "md5" usbDevice);
usbFsType = "vfat";
mapAttrsNameValue = f: set:
lib.listToAttrs (map f (lib.attrsToList set));
in
{
boot.initrd.kernelModules = [ "uas" "usbcore" "usb_storage" "vfat" "nls_cp437" "nls_iso8859_1" ];
boot.initrd.systemd.services =
mapAttrsNameValue = f: set:
lib.listToAttrs (map f (lib.attrsToList set));
in
{
boot.initrd = {
kernelModules = [ "uas" "usbcore" "usb_storage" "vfat" "nls_cp437" "nls_iso8859_1" ];
systemd.services =
let
makeService = name: { keyPath, usbDevice, waitForDevice }:
let
@ -89,7 +88,12 @@ in
if [ -e ${lib.escapeShellArg usbDevPath} ]; then
mkdir -m0500 -p ${lib.escapeShellArg usbMountPath}
mount -n -t ${lib.escapeShellArg usbFsType} -o ro,fmask=0137,dmask=0027 ${lib.escapeShellArg usbDevPath} ${lib.escapeShellArg usbMountPath}
mount \
-n \
-t ${lib.escapeShellArg usbFsType} \
-o ro,fmask=0137,dmask=0027 \
${lib.escapeShellArg usbDevPath} \
${lib.escapeShellArg usbMountPath}
fi
'';
};
@ -101,7 +105,7 @@ in
})
cfg.devices;
boot.initrd.luks.devices = builtins.mapAttrs
luks.devices = builtins.mapAttrs
(name: { keyPath, usbDevice, ... }:
let
usbMountPath = makeMountPath usbDevice;
@ -111,6 +115,7 @@ in
keyFileTimeout = 1;
})
cfg.devices;
}
);
};
}
);
}

View file

@ -5,26 +5,26 @@ let
listToString = lib.concatStringsSep ",";
# List of attribute sets with single key-value pair
plainAliases = (lib.flatten
plainAliases = lib.flatten
(map
({ address, aliases, ... }:
map
(alias: { "${alias}" = address; })
(aliases ++ lib.singleton address))
cfg.users));
cfg.users);
# Attribute set with every alias mapped to a list of receivers
mergedAliases = (lib.attrsets.foldAttrs
mergedAliases = lib.attrsets.foldAttrs
(val: col: lib.singleton val ++ col)
[ ]
plainAliases);
plainAliases;
# Contents of the aliases file
aliasesString = (lib.concatStringsSep
aliasesString = lib.concatStringsSep
"\n"
(lib.mapAttrsToList
(alias: addresses: "${alias} ${listToString addresses}")
mergedAliases));
mergedAliases);
valiases = pkgs.writeText "valiases" aliasesString;
@ -38,7 +38,7 @@ lib.mkIf cfg.enable {
services.postfix = {
enable = true;
relayPort = cfg.relayPort;
inherit (cfg) relayPort;
enableSubmission = false; # plain/STARTTLS (latter is forced in submissionOptions)
enableSubmissions = true; # submission with implicit TLS (TCP/465)

View file

@ -6,7 +6,7 @@ let
# nix shell nixpkgs#rspamd -c \
# rspamadm dkim_keygen -s default -d example.com -b 4096 -k /dev/shm/dkim.key > dkim.txt
dkimEnabledDomains = (lib.filter (d: d.enableDKIM) cfg.domains);
dkimEnabledDomains = lib.filter (d: d.enableDKIM) cfg.domains;
dkimSignatureDir = pkgs.stdenvNoCC.mkDerivation {
name = "dkim-signatures";
dontUnpack = true;

View file

@ -65,7 +65,7 @@ in
type = port;
};
settings = mkOption {
type = (pkgs.formats.json { }).type;
inherit ((pkgs.formats.json { })) type;
};
};
mautrix-whatsapp = {
@ -75,7 +75,7 @@ in
type = port;
};
settings = mkOption {
type = (pkgs.formats.json { }).type;
inherit ((pkgs.formats.json { })) type;
};
};
};

View file

@ -16,7 +16,7 @@ lib.mkIf cfg.mautrix-signal.enable {
};
appservice = rec {
hostname = "127.0.0.1";
port = cfg.mautrix-signal.port;
inherit (cfg.mautrix-signal) port;
address = "http://${hostname}:${toString port}";
provisioning.shared_secret = "disable";
database = "sqlite:///${dataDir}/mautrix-signal.db";

View file

@ -15,7 +15,7 @@ lib.mkIf cfg.mautrix-whatsapp.enable {
};
appservice = rec {
hostname = "127.0.0.1";
port = cfg.mautrix-whatsapp.port;
inherit (cfg.mautrix-whatsapp) port;
address = "http://${hostname}:${toString port}";
provisioning.shared_secret = "disable";
database = {

View file

@ -4,84 +4,107 @@ let
cfg = config.jalr.matrix;
in
lib.mkIf cfg.enable {
services.matrix-synapse = {
enable = true;
services = {
matrix-synapse = {
enable = true;
settings = {
server_name = cfg.domain;
public_baseurl = "https://${cfg.fqdn}";
settings = {
server_name = cfg.domain;
public_baseurl = "https://${cfg.fqdn}";
database.name = "sqlite3";
database.name = "sqlite3";
listeners = lib.singleton {
port = cfg.synapse.port;
bind_addresses = [ "127.0.0.1" "::1" ];
type = "http";
tls = false;
x_forwarded = true;
resources = lib.singleton {
names = [ "client" "federation" "metrics" ];
compress = false;
listeners = lib.singleton {
inherit (cfg.synapse) port;
bind_addresses = [ "127.0.0.1" "::1" ];
type = "http";
tls = false;
x_forwarded = true;
resources = lib.singleton {
names = [ "client" "federation" "metrics" ];
compress = false;
};
};
turn_uris = [
"turns:${cfg.turn.host}:5349?transport=udp"
"turns:${cfg.turn.host}:5349?transport=tcp"
"turn:${cfg.turn.host}:3478?transport=udp"
"turn:${cfg.turn.host}:3478?transport=tcp"
];
turn_user_lifetime = "1h";
enable_metrics = true;
# adapted from https://github.com/NixOS/nixpkgs/blob/7e10bf4327491a6ebccbe1aaa8e6c6c0aca4663a/nixos/modules/services/misc/matrix-synapse-log_config.yaml
# - set root.level to WARNING instead of INFO
log_config = pkgs.writeText "log_config.yaml" (builtins.toJSON {
version = 1;
formatters.journal_fmt.format = "%(name)s: [%(request)s] %(message)s";
filters.context = {
"()" = "synapse.util.logcontext.LoggingContextFilter";
request = "";
};
handlers.journal = {
class = "systemd.journal.JournalHandler";
formatter = "journal_fmt";
filters = [ "context" ];
SYSLOG_IDENTIFIER = "synapse";
};
root = {
level = "WARNING";
handlers = [ "journal" ];
};
disable_existing_loggers = false;
});
max_upload_size = "50M";
# Im okay with using matrix.org as trusted key server
suppress_key_server_warning = true;
# For mautrix-whatsapp backfilling
experimental_features.msc2716_enabled = true;
};
turn_uris = [
"turns:${cfg.turn.host}:5349?transport=udp"
"turns:${cfg.turn.host}:5349?transport=tcp"
"turn:${cfg.turn.host}:3478?transport=udp"
"turn:${cfg.turn.host}:3478?transport=tcp"
extraConfigFiles = [
cfg.turn.sharedSecretFile
];
turn_user_lifetime = "1h";
enable_metrics = true;
# adapted from https://github.com/NixOS/nixpkgs/blob/7e10bf4327491a6ebccbe1aaa8e6c6c0aca4663a/nixos/modules/services/misc/matrix-synapse-log_config.yaml
# - set root.level to WARNING instead of INFO
log_config = pkgs.writeText "log_config.yaml" (builtins.toJSON {
version = 1;
formatters.journal_fmt.format = "%(name)s: [%(request)s] %(message)s";
filters.context = {
"()" = "synapse.util.logcontext.LoggingContextFilter";
request = "";
};
handlers.journal = {
class = "systemd.journal.JournalHandler";
formatter = "journal_fmt";
filters = [ "context" ];
SYSLOG_IDENTIFIER = "synapse";
};
root = {
level = "WARNING";
handlers = [ "journal" ];
};
disable_existing_loggers = false;
});
max_upload_size = "50M";
# Im okay with using matrix.org as trusted key server
suppress_key_server_warning = true;
# For mautrix-whatsapp backfilling
experimental_features.msc2716_enabled = true;
};
extraConfigFiles = [
cfg.turn.sharedSecretFile
];
matrix-synapse.settings.app_service_config_files = lib.attrsets.mapAttrsToList
(
name: value:
"/run/matrix-synapse/app_service_config/${name}.yaml"
)
cfg.synapse.app_service_config;
nginx.virtualHosts = {
"${cfg.fqdn}" = {
enableACME = true;
forceSSL = true;
locations."/_matrix" =
let
listenerCfg = lib.elemAt config.services.matrix-synapse.settings.listeners 0;
in
{
proxyPass = "http://${lib.elemAt listenerCfg.bind_addresses 0}:${toString listenerCfg.port}";
extraConfig = ''
client_max_body_size ${config.services.matrix-synapse.settings.max_upload_size};
'';
};
};
};
};
services.matrix-synapse.settings.app_service_config_files = lib.attrsets.mapAttrsToList
(
name: value:
"/run/matrix-synapse/app_service_config/${name}.yaml"
)
cfg.synapse.app_service_config;
systemd.services.matrix-synapse = {
restartTriggers = lib.attrsets.mapAttrsToList
(
@ -109,24 +132,4 @@ lib.mkIf cfg.enable {
cfg.synapse.app_service_config;
};
};
services.nginx.virtualHosts = {
"${cfg.fqdn}" = {
enableACME = true;
forceSSL = true;
locations."/_matrix" =
let
listenerCfg = (lib.elemAt config.services.matrix-synapse.settings.listeners 0);
in
{
proxyPass = "http://${lib.elemAt listenerCfg.bind_addresses 0}:${toString listenerCfg.port}";
extraConfig = ''
client_max_body_size ${config.services.matrix-synapse.settings.max_upload_size};
'';
};
};
};
}

View file

@ -45,7 +45,7 @@
(final: prev: {
master = import inputs.nixpkgsMaster {
inherit system;
config = prev.config;
inherit (prev) config;
};
})
];

View file

@ -67,7 +67,7 @@ in
extraArgs = [ "-f" ];
postCreateHook =
let
device = cfg.devices.disk.virt.content.partitions.linux.device;
inherit (cfg.devices.disk.virt.content.partitions.linux) device;
in
''
mountpoint="$(mktemp -d)"

View file

@ -49,7 +49,7 @@ in
];
sops.secrets.sturzbach-htpasswd = {
sopsFile = cfg.sopsFile;
inherit (cfg) sopsFile;
owner = "nginx";
};

View file

@ -1,10 +1,14 @@
{ config, lib, pkgs, ... }:
lib.mkIf (config.jalr.gui.enable && config.jalr.gui.desktop == "sway") {
programs.sway = {
enable = true;
xwayland.enable = true;
wrapperFeatures.gtk = true;
programs = {
wshowkeys.enable = true;
dconf.enable = true;
sway = {
enable = true;
xwayland.enable = true;
wrapperFeatures.gtk = true;
};
};
hardware.graphics.enable = true;
@ -19,6 +23,7 @@ lib.mkIf (config.jalr.gui.enable && config.jalr.gui.desktop == "sway") {
}];
xdg = {
icons.enable = true;
portal = {
enable = true;
extraPortals = with pkgs; [
@ -27,13 +32,8 @@ lib.mkIf (config.jalr.gui.enable && config.jalr.gui.desktop == "sway") {
];
xdgOpenUsePortal = true;
};
icons.enable = true;
};
programs.wshowkeys.enable = true;
programs.dconf.enable = true;
environment.systemPackages = with pkgs; [
adwaita-icon-theme
];

View file

@ -1,8 +1,8 @@
{ lib, ... }:
{
nixpkgs.config.allowUnfreePredicate = (pkg: lib.elem (lib.getName pkg) [
nixpkgs.config.allowUnfreePredicate = pkg: lib.elem (lib.getName pkg) [
"unifi-controller"
"mongodb"
]);
];
}

View file

@ -1,4 +1,4 @@
{ ... }@inputs:
inputs:
final: prev:
let

View file

@ -84,73 +84,73 @@ in
config = lib.mkIf cfg.enable {
environment.etc."myintercom-doorbell/settings.json".text = builtins.toJSON {
host = cfg.host;
username = cfg.username;
passwordFile = cfg.passwordFile;
inherit (cfg) host;
inherit (cfg) username;
inherit (cfg) passwordFile;
audiosocket = {
address = cfg.audiosocket.address;
port = cfg.audiosocket.port;
uuid = cfg.audiosocket.uuid;
inherit (cfg.audiosocket) address;
inherit (cfg.audiosocket) port;
inherit (cfg.audiosocket) uuid;
};
callerId = cfg.callerId;
dialTime = cfg.dialTime;
inherit (cfg) callerId;
inherit (cfg) dialTime;
};
systemd.services.myintercom-doorbell-poll = {
enable = cfg.enable;
description = "Polls myintercom doorbell ring button status.";
after = [ "asterisk.service" "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
User = "asterisk";
# @TODO: Use unstable only until 23.11 is released
ExecStart = "${pkgs.myintercom-doorbell}/bin/myintercom-doorbell-poll";
systemd.services = {
myintercom-doorbell-poll = {
inherit (cfg) enable;
description = "Polls myintercom doorbell ring button status.";
after = [ "asterisk.service" "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
User = "asterisk";
# @TODO: Use unstable only until 23.11 is released
ExecStart = "${pkgs.myintercom-doorbell}/bin/myintercom-doorbell-poll";
};
};
};
systemd.services.myintercom-doorbell-audiosocket = {
enable = cfg.enable;
description = "myintercom doorbell AudioSocket for Asterisk";
requires = [ "asterisk.service" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
DynamicUser = true;
CapabilityBoundingSet = null;
PrivateUsers = true;
ProtectHome = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
SystemCallFilter = "@system-service";
LoadCredential = "password:${cfg.passwordFile}";
Environment = [
"LISTEN_ADDRESS=${cfg.audiosocket.address}"
"LISTEN_PORT=${toString cfg.audiosocket.port}"
"HOST=${cfg.host}"
"USERNAME=${cfg.username}"
"PASSWORD_FILE=%d/password"
];
ExecStart = "${pkgs.myintercom-doorbell}/bin/myintercom-doorbell-audiosocket";
myintercom-doorbell-audiosocket = {
inherit (cfg) enable;
description = "myintercom doorbell AudioSocket for Asterisk";
requires = [ "asterisk.service" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
DynamicUser = true;
CapabilityBoundingSet = null;
PrivateUsers = true;
ProtectHome = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
SystemCallFilter = "@system-service";
LoadCredential = "password:${cfg.passwordFile}";
Environment = [
"LISTEN_ADDRESS=${cfg.audiosocket.address}"
"LISTEN_PORT=${toString cfg.audiosocket.port}"
"HOST=${cfg.host}"
"USERNAME=${cfg.username}"
"PASSWORD_FILE=%d/password"
];
ExecStart = "${pkgs.myintercom-doorbell}/bin/myintercom-doorbell-audiosocket";
};
};
};
systemd.services.myintercom-doorbell-cam-proxy = {
enable = cfg.cam.enable;
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
description = "Proxies the videostream of myintercom doorbell.";
script = ''
sed "s:__PASSWORD__:$(cat "$PASSWORD_FILE"):" "${mediamtxConfig}" | ${pkgs.master.mediamtx}/bin/mediamtx /dev/stdin
'';
serviceConfig = {
Type = "simple";
DynamicUser = true;
LoadCredential = "password:${cfg.passwordFile}";
Environment = [
"PASSWORD_FILE=%d/password"
];
myintercom-doorbell-cam-proxy = {
inherit (cfg.cam) enable;
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
description = "Proxies the videostream of myintercom doorbell.";
script = ''
sed "s:__PASSWORD__:$(cat "$PASSWORD_FILE"):" "${mediamtxConfig}" | ${pkgs.master.mediamtx}/bin/mediamtx /dev/stdin
'';
serviceConfig = {
Type = "simple";
DynamicUser = true;
LoadCredential = "password:${cfg.passwordFile}";
Environment = [
"PASSWORD_FILE=%d/password"
];
};
};
};
};

View file

@ -8,8 +8,8 @@
stdenv.mkDerivation rec {
pname = "wofi-bluetooth";
version = rofi-bluetooth.version;
src = rofi-bluetooth.src;
inherit (rofi-bluetooth) version;
inherit (rofi-bluetooth) src;
patches = [
./wofi-bluetooth.patch
];

View file

@ -128,7 +128,7 @@ in
{
programs.alacritty = {
enable = nixosConfig.jalr.gui.enable;
inherit (nixosConfig.jalr.gui) enable;
};
xdg.configFile = lib.attrsets.mapAttrs'

View file

@ -1,7 +1,7 @@
{ nixosConfig, lib, pkgs, config, ... }:
let
xdg = config.xdg;
inherit (config) xdg;
in
{
config = lib.mkIf nixosConfig.jalr.aws.enable {
@ -17,7 +17,7 @@ in
xdg.configFile."aws/config".text = lib.generators.toINI { } (
lib.mapAttrs'
(name: value:
lib.attrsets.nameValuePair ("profile ${name}") (value)
lib.attrsets.nameValuePair "profile ${name}" value
)
nixosConfig.jalr.aws.accounts
//

View file

@ -12,8 +12,7 @@
} // (with config.lib.htop; leftMeters ([
(bar "LeftCPUs")
(bar "Memory")
] ++ lib.lists.optional nixosConfig.zramSwap.enable (bar "Zram") ++ [
] ++ lib.lists.optional (!(nixosConfig.swapDevices == [ ])) (bar "Swap") ++ [
] ++ lib.lists.optional nixosConfig.zramSwap.enable (bar "Zram") ++ lib.lists.optional (nixosConfig.swapDevices != [ ]) (bar "Swap") ++ [
(bar "DiskIO")
])) // (with config.lib.htop; rightMeters [
(bar "RightCPUs")

View file

@ -40,18 +40,16 @@ let
target = "myclirc";
}
{
exec = (
exec =
if nixosConfig.jalr.gui.enable
then [ "/usr/bin/env" "gsettings" "set" "org.gnome.desktop.interface" "color-scheme" "prefer-%scheme%" ]
else null
);
else null;
}
{
exec = (
exec =
if nixosConfig.jalr.gui.enable
then [ "/usr/bin/env" "gsettings" "set" "org.gnome.desktop.interface" "gtk-theme" "Adwaita-%scheme%" ]
else null
);
else null;
}
];
dynamic-colors = pkgs.writers.writePython3Bin "dynamic-colors" { } ''

View file

@ -1,7 +1,7 @@
{ nixosConfig, pkgs, ... }:
{
programs.firefox = {
enable = nixosConfig.jalr.gui.enable;
inherit (nixosConfig.jalr.gui) enable;
package = pkgs.firefox-esr;
policies = {
AllowedDomainsForApps = "";
@ -155,113 +155,115 @@
}
];
*/
SearchEngines.Default = "DuckDuckGo";
SearchEngines.Remove = [
"Google"
"Wikipedia (en)"
];
SearchEngines.Add = [
{
Name = "Startpage";
URLTemplate = "https://www.startpage.com/sp/search";
Method = "POST";
PostData = "qadf=none&query={searchTerms}";
IconURL = "https://www.startpage.com/sp/cdn/favicons/mobile/android-icon-192x192.png";
Alias = "sp";
}
{
Name = "DuckDuckGo";
URLTemplate = "https://duckduckgo.com/?q={searchTerms}";
Method = "GET";
IconURL = "https://duckduckgo.com/favicon.ico";
Alias = "ddg";
}
SearchEngines = {
Default = "DuckDuckGo";
Remove = [
"Google"
"Wikipedia (en)"
];
Add = [
{
Name = "Startpage";
URLTemplate = "https://www.startpage.com/sp/search";
Method = "POST";
PostData = "qadf=none&query={searchTerms}";
IconURL = "https://www.startpage.com/sp/cdn/favicons/mobile/android-icon-192x192.png";
Alias = "sp";
}
{
Name = "DuckDuckGo";
URLTemplate = "https://duckduckgo.com/?q={searchTerms}";
Method = "GET";
IconURL = "https://duckduckgo.com/favicon.ico";
Alias = "ddg";
}
# Wikipedia
{
Name = "Wikipedia en";
URLTemplate = "https://en.wikipedia.org/wiki/Special:Search?search={searchTerms}";
Method = "GET";
IconURL = "https://en.wikipedia.org/static/images/icons/wikipedia.png";
Alias = "wen";
}
{
Name = "Wikipedia de";
URLTemplate = "https://de.wikipedia.org/w/index.php?search={searchTerms}";
Method = "GET";
IconURL = "https://www.wikipedia.de/img/wikipedia.png";
Alias = "wde";
}
{
Name = "Nix Packages";
URLTemplate = "https://search.nixos.org/packages?query={searchTerms}";
Method = "GET";
IconURL = "https://nixos.org/favicon.png";
Alias = "pkg";
}
{
Name = "NixOS Options";
URLTemplate = "https://search.nixos.org/options?query={searchTerms}";
Method = "GET";
IconURL = "https://nixos.org/favicon.png";
Alias = "opt";
}
{
Name = "Docker images";
URLTemplate = "https://hub.docker.com/search/?q={searchTerms}";
Method = "GET";
IconURL = "https://hub.docker.com/favicon.ico";
Alias = "docker";
}
{
Name = "GitHub";
URLTemplate = "https://github.com/search?q={searchTerms}";
Method = "GET";
IconURL = "https://github.githubassets.com/favicons/favicon.svg";
Alias = "gh";
}
# Wikipedia
{
Name = "Wikipedia en";
URLTemplate = "https://en.wikipedia.org/wiki/Special:Search?search={searchTerms}";
Method = "GET";
IconURL = "https://en.wikipedia.org/static/images/icons/wikipedia.png";
Alias = "wen";
}
{
Name = "Wikipedia de";
URLTemplate = "https://de.wikipedia.org/w/index.php?search={searchTerms}";
Method = "GET";
IconURL = "https://www.wikipedia.de/img/wikipedia.png";
Alias = "wde";
}
{
Name = "Nix Packages";
URLTemplate = "https://search.nixos.org/packages?query={searchTerms}";
Method = "GET";
IconURL = "https://nixos.org/favicon.png";
Alias = "pkg";
}
{
Name = "NixOS Options";
URLTemplate = "https://search.nixos.org/options?query={searchTerms}";
Method = "GET";
IconURL = "https://nixos.org/favicon.png";
Alias = "opt";
}
{
Name = "Docker images";
URLTemplate = "https://hub.docker.com/search/?q={searchTerms}";
Method = "GET";
IconURL = "https://hub.docker.com/favicon.ico";
Alias = "docker";
}
{
Name = "GitHub";
URLTemplate = "https://github.com/search?q={searchTerms}";
Method = "GET";
IconURL = "https://github.githubassets.com/favicons/favicon.svg";
Alias = "gh";
}
# Shopping
{
Name = "Amazon de";
URLTemplate = "https://www.amazon.de/s?k={searchTerms}";
Method = "GET";
IconURL = "https://www.amazon.de/favicon.ico";
Alias = "amde";
}
{
Name = "Ebay de";
URLTemplate = "https://www.ebay.de/sch/i.html?_nkw={searchTerms}";
Method = "GET";
IconURL = "https://pages.ebay.com/favicon.ico";
Alias = "ebde";
}
# Shopping
{
Name = "Amazon de";
URLTemplate = "https://www.amazon.de/s?k={searchTerms}";
Method = "GET";
IconURL = "https://www.amazon.de/favicon.ico";
Alias = "amde";
}
{
Name = "Ebay de";
URLTemplate = "https://www.ebay.de/sch/i.html?_nkw={searchTerms}";
Method = "GET";
IconURL = "https://pages.ebay.com/favicon.ico";
Alias = "ebde";
}
# Dictionary
{
Name = "dict.cc";
URLTemplate = "https://www.dict.cc/?s={searchTerms}";
Method = "GET";
IconURL = "https://www4.dict.cc/img/favicons/favicon4.png";
Alias = "dcc";
}
{
Name = "Duden";
URLTemplate = "https://www.duden.de/suchen/dudenonline/{searchTerms}";
Method = "GET";
IconURL = "https://www.duden.de/sites/default/res/apple-touch-icon/180x180.png";
Alias = "duden";
}
# Dictionary
{
Name = "dict.cc";
URLTemplate = "https://www.dict.cc/?s={searchTerms}";
Method = "GET";
IconURL = "https://www4.dict.cc/img/favicons/favicon4.png";
Alias = "dcc";
}
{
Name = "Duden";
URLTemplate = "https://www.duden.de/suchen/dudenonline/{searchTerms}";
Method = "GET";
IconURL = "https://www.duden.de/sites/default/res/apple-touch-icon/180x180.png";
Alias = "duden";
}
# Map
{
Name = "OpenStreetMap";
URLTemplate = "https://www.openstreetmap.org/search?query={searchTerms}";
Method = "GET";
IconURL = "https://www.openstreetmap.org/assets/favicon-194x194-79d3fb0152c735866e64b1d7535d504483cd13c2fad0131a6142bd9629d30de2.png";
Alias = "osm";
}
];
# Map
{
Name = "OpenStreetMap";
URLTemplate = "https://www.openstreetmap.org/search?query={searchTerms}";
Method = "GET";
IconURL = "https://www.openstreetmap.org/assets/favicon-194x194-79d3fb0152c735866e64b1d7535d504483cd13c2fad0131a6142bd9629d30de2.png";
Alias = "osm";
}
];
};
};
profiles.default = {
id = 0;

View file

@ -169,36 +169,38 @@
};
};
xdg.configFile."fish/completions/mycli.fish".text = ''
complete -e -c mycli
complete -c mycli -f
complete -c mycli -f -s h -l host -d "Host address of the database."
complete -c mycli -f -s P -l port -d "Port number to use for connection."
complete -c mycli -f -s u -l user -d "User name to connect to the database."
complete -c mycli -f -s S -l socket -d "The socket file to use for connection."
complete -c mycli -f -s p -l pass \
-l password -d "Password to connect to the database."
complete -c mycli -f -s V -l version -d "Output mycli's version."
complete -c mycli -f -s v -l verbose -d "Verbose output."
complete -c mycli -f -s d -l dsn -d "Use DSN configured into the [alias_dsn] section of myclirc file."
complete -c mycli -f -l list-dsn -d "list of DSN configured into the [alias_dsn] section of myclirc file."
xdg.configFile = {
"fish/completions/mycli.fish".text = ''
complete -e -c mycli
complete -c mycli -f
complete -c mycli -f -s h -l host -d "Host address of the database."
complete -c mycli -f -s P -l port -d "Port number to use for connection."
complete -c mycli -f -s u -l user -d "User name to connect to the database."
complete -c mycli -f -s S -l socket -d "The socket file to use for connection."
complete -c mycli -f -s p -l pass \
-l password -d "Password to connect to the database."
complete -c mycli -f -s V -l version -d "Output mycli's version."
complete -c mycli -f -s v -l verbose -d "Verbose output."
complete -c mycli -f -s d -l dsn -d "Use DSN configured into the [alias_dsn] section of myclirc file."
complete -c mycli -f -l list-dsn -d "list of DSN configured into the [alias_dsn] section of myclirc file."
complete -c mycli -f -s t -l table -d "Display batch output in table format."
complete -c mycli -f -l csv -d "Display batch output in CSV format."
complete -c mycli -f -l warn \
-l no-warn -d "Warn before running a destructive query."
complete -c mycli -f -s e -l execute -d "Execute command and quit."
complete -c mycli -f -s t -l table -d "Display batch output in table format."
complete -c mycli -f -l csv -d "Display batch output in CSV format."
complete -c mycli -f -l warn \
-l no-warn -d "Warn before running a destructive query."
complete -c mycli -f -s e -l execute -d "Execute command and quit."
complete -c mycli -f -s h -l host -r -a '(__fish_print_hostnames)'
complete -c mycli -f -s d -l dsn -r -a '(mycli --list-dsn)'
'';
complete -c mycli -f -s h -l host -r -a '(__fish_print_hostnames)'
complete -c mycli -f -s d -l dsn -r -a '(mycli --list-dsn)'
'';
xdg.configFile."fish/completions/myssh.fish".text = ''
complete -c myssh -f -a '(myssh --list)'
'';
"fish/completions/myssh.fish".text = ''
complete -c myssh -f -a '(myssh --list)'
'';
xdg.configFile."fish/completions/just.fish".source = pkgs.runCommand "just-fish-completions" { } ''
${pkgs.just}/bin/just --completions fish > $out
'';
"fish/completions/just.fish".source = pkgs.runCommand "just-fish-completions" { } ''
${pkgs.just}/bin/just --completions fish > $out
'';
};
}

View file

@ -8,6 +8,6 @@ let
pkgs.gnuradio3_8Packages;
};
in
(lib.mkIf nixosConfig.jalr.gui.enable {
lib.mkIf nixosConfig.jalr.gui.enable {
home.packages = [ gnuradioEnv ];
})
}

View file

@ -139,111 +139,112 @@ in
]);
};
xdg.configFile."nvim/lua/init.lua".text = builtins.concatStringsSep "\n" (
[
''
-- init.lua
-- this configuration applies to servers and workstations
''
] ++ lib.optional nixosConfig.jalr.workstation.enable (
''
-- this configuration applies to workstations only
-- https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
local lsp = require('lspconfig')
'' +
builtins.concatStringsSep "\n" (
lib.mapAttrsToList
(
lang: cfg: "lsp.${lang}.setup\n" + lib.generators.toLua { } cfg
)
{
# C and C++
ccls = {
cmd = [ "${pkgs.ccls}/bin/ccls" ];
};
xdg.configFile = {
"nvim/ftplugin/gitcommit.vim".text = ''
setlocal spell
setlocal colorcolumn=73
'';
"nvim/ftplugin/markdown.vim".text = ''
setlocal spell
setlocal colorcolumn=81
'';
"nvim/ftplugin/sshconfig.vim".text = ''
setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab
'';
"nvim/lua/init.lua".text = builtins.concatStringsSep "\n" (
[
''
-- init.lua
-- this configuration applies to servers and workstations
''
] ++ lib.optional nixosConfig.jalr.workstation.enable (
''
-- this configuration applies to workstations only
-- https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
local lsp = require('lspconfig')
'' +
builtins.concatStringsSep "\n" (
lib.mapAttrsToList
(
lang: cfg: "lsp.${lang}.setup\n" + lib.generators.toLua { } cfg
)
{
# C and C++
ccls = {
cmd = [ "${pkgs.ccls}/bin/ccls" ];
};
# Nix
nixd = {
cmd = [ "${pkgs.nixd}/bin/nixd" ];
};
# Nix
nixd = {
cmd = [ "${pkgs.nixd}/bin/nixd" ];
};
# PHP
phpactor = {
cmd = [ "${pkgs.phpactor}/bin/phpactor" "language-server" ];
};
# PHP
phpactor = {
cmd = [ "${pkgs.phpactor}/bin/phpactor" "language-server" ];
};
# Python
pylsp = {
cmd = [ "${pkgs.python3Packages.python-lsp-server}/bin/pylsp" ];
settings = {
# https://github.com/python-lsp/python-lsp-server/blob/develop/CONFIGURATION.md
pylsp = {
plugins = {
flake8 = {
enabled = true;
executable = "${pkgs.python3Packages.flake8}/bin/flake8";
# Python
pylsp = {
cmd = [ "${pkgs.python3Packages.python-lsp-server}/bin/pylsp" ];
settings = {
# https://github.com/python-lsp/python-lsp-server/blob/develop/CONFIGURATION.md
pylsp = {
plugins = {
flake8 = {
enabled = true;
executable = "${pkgs.python3Packages.flake8}/bin/flake8";
};
jedi_completion = { enabled = true; };
jedi_definition = { enabled = true; };
jedi_hover = { enabled = true; };
jedi_references = { enabled = true; };
jedi_signature_help = { enabled = true; };
jedi_symbols = { enabled = true; };
mccabe = { enabled = true; };
lsp_signature-nvim = { enabled = true; };
preload = { enabled = true; };
pycodestyle = { enabled = true; };
pyflakes = { enabled = true; };
rope_completion = { enabled = true; };
yapf = { enabled = true; };
};
jedi_completion = { enabled = true; };
jedi_definition = { enabled = true; };
jedi_hover = { enabled = true; };
jedi_references = { enabled = true; };
jedi_signature_help = { enabled = true; };
jedi_symbols = { enabled = true; };
mccabe = { enabled = true; };
lsp_signature-nvim = { enabled = true; };
preload = { enabled = true; };
pycodestyle = { enabled = true; };
pyflakes = { enabled = true; };
rope_completion = { enabled = true; };
yapf = { enabled = true; };
};
};
};
};
# Ruby
solargraph = {
cmd = [ "${pkgs.solargraph}/bin/solargraph" "stdio" ];
};
# Ruby
solargraph = {
cmd = [ "${pkgs.solargraph}/bin/solargraph" "stdio" ];
};
# Rust
rust_analyzer = {
cmd = [ "${pkgs.rust-analyzer}/bin/rust-analyzer" ];
};
# Rust
rust_analyzer = {
cmd = [ "${pkgs.rust-analyzer}/bin/rust-analyzer" ];
};
# Bash
bashls = {
cmd = [ "${pkgs.nodePackages.bash-language-server}/bin/bash-language-server" "start" ];
};
# Bash
bashls = {
cmd = [ "${pkgs.nodePackages.bash-language-server}/bin/bash-language-server" "start" ];
};
# Terraform
terraformls = {
cmd = [ "${pkgs.terraform-ls}/bin/terraform-ls" "serve" ];
};
# Terraform
terraformls = {
cmd = [ "${pkgs.terraform-ls}/bin/terraform-ls" "serve" ];
};
# YAML
yamlls = {
cmd = [ "${pkgs.nodePackages.yaml-language-server}/bin/yaml-language-server" "--stdio" ];
settings = {
yaml = {
keyOrdering = false;
# YAML
yamlls = {
cmd = [ "${pkgs.nodePackages.yaml-language-server}/bin/yaml-language-server" "--stdio" ];
settings = {
yaml = {
keyOrdering = false;
};
};
};
};
}
}
)
)
)
);
xdg.configFile."nvim/ftplugin/gitcommit.vim".text = ''
setlocal spell
setlocal colorcolumn=73
'';
xdg.configFile."nvim/ftplugin/markdown.vim".text = ''
setlocal spell
setlocal colorcolumn=81
'';
xdg.configFile."nvim/ftplugin/sshconfig.vim".text = ''
setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab
'';
);
};
}

View file

@ -2,7 +2,7 @@
{
programs.obs-studio = {
enable = nixosConfig.jalr.gui.enable;
inherit (nixosConfig.jalr.gui) enable;
plugins = with pkgs; [
obs-studio-plugins.wlrobs
];

View file

@ -35,7 +35,7 @@ let
#gsettings set $gnome_schema gtk-theme 'Dracula'
${pkgs.glib}/bin/gsettings "$@"
'';
matchHostname = (hostname: lib.optionalAttrs (nixosConfig.networking.hostName == hostname));
matchHostname = hostname: lib.optionalAttrs (nixosConfig.networking.hostName == hostname);
resumeTimeTrackingNotification = pkgs.writeShellScript "resume-time-tracking-notification" ''
export PATH=${pkgs.lib.makeBinPath [pkgs.timewarrior pkgs.libnotify]}
task="$1"
@ -97,19 +97,6 @@ in
end
'';
xdg.configFile."sway/light-theme".text = with solarized; ''
client.focused ${base01.hex} ${blue.hex} ${base3.hex} ${blue.hex} ${blue.hex}
client.focused_inactive ${base2.hex} ${base2.hex} ${base01.hex} ${base0.hex} ${base2.hex}
client.unfocused ${base2.hex} ${base3.hex} ${base01.hex} ${base2.hex} ${base2.hex}
client.urgent ${red.hex} ${red.hex} ${base3.hex} ${red.hex} ${red.hex}
'';
xdg.configFile."sway/dark-theme".text = with solarized; ''
client.focused ${base1.hex} ${blue.hex} ${base03.hex} ${blue.hex} ${blue.hex}
client.focused_inactive ${base02.hex} ${base02.hex} ${base1.hex} ${base03.hex} ${base02.hex}
client.unfocused ${base02.hex} ${base03.hex} ${base1.hex} ${base02.hex} ${base02.hex}
client.urgent ${red.hex} ${red.hex} ${base03.hex} ${red.hex} ${red.hex}
'';
wayland.windowManager.sway = {
enable = true;
@ -379,26 +366,40 @@ in
};
};
xdg.configFile."swaynag/config".text =
let
# adding it to the header doesnt work since the defaults overwrite it
commonConfig = /* ini */ ''
background=${lib.substring 1 6 solarized.base3.hex}
border-bottom=${lib.substring 1 6 solarized.base2.hex}
border=${lib.substring 1 6 solarized.base2.hex}
button-background=${lib.substring 1 6 solarized.base3.hex}
button-text=${lib.substring 1 6 solarized.base00.hex}
'';
in
/* ini */ ''
font=Monospace 12
[warning]
text=${lib.substring 1 6 solarized.yellow.hex}
${commonConfig}
[error]
text=${lib.substring 1 6 solarized.red.hex}
${commonConfig}
xdg.configFile = {
"sway/light-theme".text = with solarized; ''
client.focused ${base01.hex} ${blue.hex} ${base3.hex} ${blue.hex} ${blue.hex}
client.focused_inactive ${base2.hex} ${base2.hex} ${base01.hex} ${base0.hex} ${base2.hex}
client.unfocused ${base2.hex} ${base3.hex} ${base01.hex} ${base2.hex} ${base2.hex}
client.urgent ${red.hex} ${red.hex} ${base3.hex} ${red.hex} ${red.hex}
'';
"sway/dark-theme".text = with solarized; ''
client.focused ${base1.hex} ${blue.hex} ${base03.hex} ${blue.hex} ${blue.hex}
client.focused_inactive ${base02.hex} ${base02.hex} ${base1.hex} ${base03.hex} ${base02.hex}
client.unfocused ${base02.hex} ${base03.hex} ${base1.hex} ${base02.hex} ${base02.hex}
client.urgent ${red.hex} ${red.hex} ${base03.hex} ${red.hex} ${red.hex}
'';
"swaynag/config".text =
let
# adding it to the header doesnt work since the defaults overwrite it
commonConfig = /* ini */ ''
background=${lib.substring 1 6 solarized.base3.hex}
border-bottom=${lib.substring 1 6 solarized.base2.hex}
border=${lib.substring 1 6 solarized.base2.hex}
button-background=${lib.substring 1 6 solarized.base3.hex}
button-text=${lib.substring 1 6 solarized.base00.hex}
'';
in
/* ini */ ''
font=Monospace 12
[warning]
text=${lib.substring 1 6 solarized.yellow.hex}
${commonConfig}
[error]
text=${lib.substring 1 6 solarized.red.hex}
${commonConfig}
'';
};
})

View file

@ -18,7 +18,7 @@ let
thinsp = "&#8201;";
solarized = import ../solarized.nix;
solarizedColors = (as: lib.strings.concatLines (lib.attrsets.mapAttrsToList (name: value: let color = solarized."${value}".hex; in "@define-color ${name} ${color};") as));
solarizedColors = as: lib.strings.concatLines (lib.attrsets.mapAttrsToList (name: value: let color = solarized."${value}".hex; in "@define-color ${name} ${color};") as);
in
{
# home-managers waybar module performs additional checks that are overly strict
@ -227,198 +227,200 @@ in
};
};
xdg.configFile."waybar/theme-light.css".text = solarizedColors {
base00 = "base3";
base01 = "base2";
base02 = "base1";
base03 = "base0";
base04 = "base00";
base05 = "base01";
base06 = "base02";
base07 = "base03";
base08 = "red";
base09 = "orange";
base0A = "yellow";
base0B = "green";
base0C = "cyan";
base0D = "blue";
base0E = "violet";
base0F = "magenta";
};
xdg.configFile."waybar/theme-dark.css".text = solarizedColors {
base00 = "base03";
base01 = "base02";
base02 = "base01";
base03 = "base00";
base04 = "base0";
base05 = "base1";
base06 = "base2";
base07 = "base3";
base08 = "red";
base09 = "orange";
base0A = "yellow";
base0B = "green";
base0C = "cyan";
base0D = "blue";
base0E = "violet";
base0F = "magenta";
};
xdg.configFile."waybar/style.css".text = ''
@import "theme.css";
xdg.configFile = {
"waybar/theme-light.css".text = solarizedColors {
base00 = "base3";
base01 = "base2";
base02 = "base1";
base03 = "base0";
base04 = "base00";
base05 = "base01";
base06 = "base02";
base07 = "base03";
base08 = "red";
base09 = "orange";
base0A = "yellow";
base0B = "green";
base0C = "cyan";
base0D = "blue";
base0E = "violet";
base0F = "magenta";
};
"waybar/theme-dark.css".text = solarizedColors {
base00 = "base03";
base01 = "base02";
base02 = "base01";
base03 = "base00";
base04 = "base0";
base05 = "base1";
base06 = "base2";
base07 = "base3";
base08 = "red";
base09 = "orange";
base0A = "yellow";
base0B = "green";
base0C = "cyan";
base0D = "blue";
base0E = "violet";
base0F = "magenta";
};
"waybar/style.css".text = ''
@import "theme.css";
* {
border-radius: 0;
border: none;
font-family: "Iosevka Nerd Font";
font-size: 14px;
min-height: 0;
transition-property: none;
}
* {
border-radius: 0;
border: none;
font-family: "Iosevka Nerd Font";
font-size: 14px;
min-height: 0;
transition-property: none;
}
window#waybar {
background-color: @base00;
color: @base04;
}
window#waybar {
background-color: @base00;
color: @base04;
}
#workspaces button {
padding: 0 5px;
background-color: @base00;
color: inherit;
border-bottom: 2px solid transparent;
}
#workspaces button {
padding: 0 5px;
background-color: @base00;
color: inherit;
border-bottom: 2px solid transparent;
}
#workspaces button:hover {
background: @base01;
box-shadow: inherit;
text-shadow: inherit;
}
#workspaces button:hover {
background: @base01;
box-shadow: inherit;
text-shadow: inherit;
}
#workspaces button.focused {
border-bottom: 2px solid @base0B;
}
#workspaces button.focused {
border-bottom: 2px solid @base0B;
}
#workspaces button.urgent {
background-color: @base08;
}
#workspaces button.urgent {
background-color: @base08;
}
#mode {
background-color: @base01;
font-style: italic;
}
#mode {
background-color: @base01;
font-style: italic;
}
/* all modules on the right */
#waybar > box > box:nth-child(3) > widget > label {
padding: 0 10px;
}
/* all modules on the right */
#waybar > box > box:nth-child(3) > widget > label {
padding: 0 10px;
}
#battery.charging {
color: @base01;
background-color: @base0B;
}
#battery.charging {
color: @base01;
background-color: @base0B;
}
@keyframes blink {
to {
@keyframes blink {
to {
background-color: @base07;
color: @base03;
}
}
#battery.critical:not(.charging),
#temperature.critical {
background-color: @base08;
animation-name: blink;
animation-duration: 0.5s;
/* FIXME use nearest neighbor interpolation if possible */
animation-timing-function: cubic-bezier(1, 0, 0, 1);
animation-iteration-count: infinite;
animation-direction: alternate;
}
#cpu {
background-color: @base0C;
color: @base01
}
#memory {
background-color: @base0A;
color: @base01
}
#backlight {
background-color: @base07;
color: @base03;
}
}
#battery.critical:not(.charging),
#temperature.critical {
background-color: @base08;
animation-name: blink;
animation-duration: 0.5s;
/* FIXME use nearest neighbor interpolation if possible */
animation-timing-function: cubic-bezier(1, 0, 0, 1);
animation-iteration-count: infinite;
animation-direction: alternate;
}
#network {
background-color: @base0E;
color: @base01
}
#cpu {
background-color: @base0C;
color: @base01
}
#network.disconnected {
background-color: @base08;
}
#memory {
background-color: @base0A;
color: @base01
}
#pulseaudio {
background-color: @base07;
color: @base03;
}
#backlight {
background-color: @base07;
color: @base03;
}
#pulseaudio.muted {
background-color: @base00;
color: @base04;
}
#network {
background-color: @base0E;
color: @base01
}
#temperature {
background-color: @base0F;
color: @base01;
}
#network.disconnected {
background-color: @base08;
}
#idle_inhibitor.activated {
background-color: @base07;
color: @base00;
}
#pulseaudio {
background-color: @base07;
color: @base03;
}
#custom-redshift {
color: @base01;
}
#pulseaudio.muted {
background-color: @base00;
color: @base04;
}
#custom-redshift.active {
background-color: @base08;
}
#temperature {
background-color: @base0F;
color: @base01;
}
#custom-redshift.inactive {
background-color: @base0D;
}
#idle_inhibitor.activated {
background-color: @base07;
color: @base00;
}
#tray {
padding: 0 5px;
}
#custom-redshift {
color: @base01;
}
#custom-notification_inhibitor.active {
background-color: @base07;
color: @base00;
}
#custom-redshift.active {
background-color: @base08;
}
#custom-screencast {
background-color: @base08;
color: @base00;
animation-name: blink;
animation-duration: 1s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
animation-direction: alternate;
}
#custom-redshift.inactive {
background-color: @base0D;
}
#custom-pomodoro.resumed {
color: @base01;
background-color: @base0B;
}
#tray {
padding: 0 5px;
}
#custom-notification_inhibitor.active {
background-color: @base07;
color: @base00;
}
#custom-screencast {
background-color: @base08;
color: @base00;
animation-name: blink;
animation-duration: 1s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
animation-direction: alternate;
}
#custom-pomodoro.resumed {
color: @base01;
background-color: @base0B;
}
#custom-dnd.active {
color: @base01;
background-color: @base0B;
}
'';
#custom-dnd.active {
color: @base01;
background-color: @base0B;
}
'';
};
systemd.user.services.waybar = {
Unit = {

View file

@ -4,86 +4,88 @@ let
solarized = import ../solarized.nix;
in
{
xdg.configFile."wofi/color-light".text = lib.strings.concatLines (map (c: solarized."${c}".hex) [
"base3"
"base2"
"base1"
"base0"
"base00"
"base01"
"base02"
"base03"
"red"
"orange"
"yellow"
"green"
"cyan"
"blue"
"violet"
"magenta"
]);
xdg.configFile."wofi/color-dark".text = lib.strings.concatLines (map (c: solarized."${c}".hex) [
"base03"
"base02"
"base01"
"base00"
"base0"
"base1"
"base2"
"base3"
"red"
"orange"
"yellow"
"green"
"cyan"
"blue"
"violet"
"magenta"
]);
xdg.configFile."wofi/style.css".text = ''
window {
margin: 0px;
border: 3px solid --wofi-color1;
border-radius: 8px;
background-color: rgba(--wofi-rgb-color0,0.8);
}
xdg.configFile = {
"wofi/color-light".text = lib.strings.concatLines (map (c: solarized."${c}".hex) [
"base3"
"base2"
"base1"
"base0"
"base00"
"base01"
"base02"
"base03"
"red"
"orange"
"yellow"
"green"
"cyan"
"blue"
"violet"
"magenta"
]);
"wofi/color-dark".text = lib.strings.concatLines (map (c: solarized."${c}".hex) [
"base03"
"base02"
"base01"
"base00"
"base0"
"base1"
"base2"
"base3"
"red"
"orange"
"yellow"
"green"
"cyan"
"blue"
"violet"
"magenta"
]);
"wofi/style.css".text = ''
window {
margin: 0px;
border: 3px solid --wofi-color1;
border-radius: 8px;
background-color: rgba(--wofi-rgb-color0,0.8);
}
#input {
margin: 5px;
border: none;
color: --wofi-color4;
background-color: rgba(--wofi-rgb-color1,0.8);
}
#input {
margin: 5px;
border: none;
color: --wofi-color4;
background-color: rgba(--wofi-rgb-color1,0.8);
}
#inner-box {
margin: 5px;
border: none;
background: none;
}
#inner-box {
margin: 5px;
border: none;
background: none;
}
#outer-box {
margin: 5px;
border: none;
background: none;
}
#outer-box {
margin: 5px;
border: none;
background: none;
}
#scroll {
margin: 0px;
border: none;
}
#scroll {
margin: 0px;
border: none;
}
#text {
margin: 5px;
border: none;
color: --wofi-color4;
}
#text {
margin: 5px;
border: none;
color: --wofi-color4;
}
#entry:selected {
background-color: rgba(--wofi-rgb-color1,0.8);
}
#entry:selected {
background-color: rgba(--wofi-rgb-color1,0.8);
}
#entry:selected #text{
color: --wofi-color11;
}
'';
#entry:selected #text{
color: --wofi-color11;
}
'';
};
}

View file

@ -1,7 +1,7 @@
{ nixosConfig, pkgs, ... }:
{
programs.thunderbird = {
enable = nixosConfig.jalr.gui.enable;
inherit (nixosConfig.jalr.gui) enable;
package = pkgs.thunderbird-esr;
profiles."default" = {
isDefault = true;