Compare commits

..

1 commit

Author SHA1 Message Date
hexchen
05c4fe4823 WIP funkwhale, DO NOT MERGE 2021-01-02 10:58:41 +00:00
288 changed files with 25888 additions and 43139 deletions

View file

@ -1,9 +1,31 @@
stages:
- instantiate
- build
build-parsons:
instantiate 20.09:
tags:
- nix
stage: instantiate
script:
- nix-instantiate -I nixpkgs=https://github.com/hexchen/nixpkgs/archive/hexchen-20.09.tar.gz -A deploy.all
instantiate main:
tags:
- nix
stage: instantiate
script:
- nix-instantiate -I nixpkgs=https://github.com/hexchen/nixpkgs/archive/hexchen-main.tar.gz -A deploy.all
build 20.09:
tags:
- nix
stage: build
script:
- nix-build -A deploy.parsons
- nix-build -A deploy.all -I nixpkgs=https://github.com/hexchen/nixpkgs/archive/hexchen-20.09.tar.gz
build main:
tags:
- nix
stage: build
script:
- nix-build -A deploy.all -I nixpkgs=https://github.com/hexchen/nixpkgs/archive/hexchen-main.tar.gz

View file

@ -1,47 +0,0 @@
# hacc nixfiles
welcome to hacc nixfiles (haccfiles). this is the code describing our nix-based infrastructure.
## structure
- `default.nix`: Entrypoint to the config
- `common/`: configuration common to all hosts
- `desktop/`: desktop-relevant communication
- `modules/`: home-grown modules for hacc-specific services
- `nix/`: sources files, managed with niv
- `pkgs/`: packages we built and don't want to upstream
- `hosts/`: configuration.nix per host
- `services/`: all services we run; imported in appropriate host config
## working with the haccfiles
deploy:
``` shell
nix build -f . deploy.$hostname && ./result switch
```
`$hostname` can be replaced with any hostname or group
## I don't want to build this long dependency / want a cached version!
If it's still available on parsons from a previous deploy, do:
```shell
nix copy --from ssh://parsons /nix/store/...
```
Note: don't just copy the .drv file (which Nix complains about if it can't
build something), that's just the description of how to build it! If you
don't know the actual outpath, look in the .drv file (should start with
`Derive([("out","[the path you want]"...`)
## committing to haccfiles
- Golden Rule: DO NOT COMMIT TO MAIN
- exceptions apply, if you are not sure where to commit, don't commit to main
- split up commits, every commit is one atomic change
- e.g. no big "did some changes" but instead "updated service x", "updated service y", "update service z"
- follow the commit format: "$prefix$place: $change"
- prefix: one of fixup, nothing
- place: one of "modules/$module", "$hostname/service", "common/($place)", "pkgs/$pkgs" or "sources"
- change: describe your change, don't go over the character limit where git starts hiding/wrapping
- Exception: autogenerated messages (merge commits, reverts, etc)

View file

@ -1,9 +0,0 @@
{config, lib, pkgs, ...}:
let
sources = import ../nix/sources.nix;
in {
imports = [
(import sources.nix-hexchen {}).users.hexchen.base
];
}

View file

@ -1,24 +1,25 @@
{ config, lib, pkgs, modules, ... }:
{ config, lib, pkgs, ... }:
let
sources = import ../nix/sources.nix;
in {
{
imports = [
../modules
../../modules
./external.nix
./users.nix
(sources.home-manager + "/nixos")
modules.network.nftables
];
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages;
nixpkgs.overlays = [
(self: super: import ../../pkgs { nixpkgs = super.path; })
];
boot.kernelPackages = lib.mkDefault pkgs.linuxPackages_latest;
boot.kernelParams = [ "quiet" ];
networking.domain = lib.mkDefault "hacc.space";
petabyte.nftables = {
enable = lib.mkDefault true;
};
services.journald.extraConfig = ''
SystemMaxUse=512M
MaxRetentionSec=48h
'';
services.journald.extraConfig = "SystemMaxUse=512M";
nix.gc.automatic = lib.mkDefault true;
nix.gc.options = lib.mkDefault "--delete-older-than 1w";
nix.trustedUsers = [ "root" "@wheel" ];
@ -36,6 +37,7 @@ in {
security.sudo.wheelNeedsPassword = lib.mkDefault false;
i18n.defaultLocale = "en_IE.UTF-8";
time.timeZone = "UTC";
console = {
font = "Lat2-Terminus16";
keyMap = "de";
@ -44,8 +46,8 @@ in {
environment.systemPackages = with pkgs; [
smartmontools lm_sensors htop tcpdump nload iftop
bottom
ripgrep vgrep
# bottom
ripgrep
git wget
kitty.terminfo
rsync pv progress
@ -61,7 +63,7 @@ in {
socat
tmux
gnupg
vim neovim
vim
patchelf
binutils
dnsutils
@ -69,17 +71,13 @@ in {
nmap
s-tui stress
ffmpeg-full
bat
niv
];
petabyte.vnstat = {
enable = true;
nginx.enable = true;
};
security.acme.email = "info+acme@hacc.space";
security.acme.acceptTerms = true;
services.nginx.appendHttpConfig = ''
access_log off;
add_header Permissions-Policy "interest-cohort=()";
'';
networking.nftables.enable = true;
}

View file

@ -0,0 +1,32 @@
let
pbb-nixfiles = fetchGit {
url = "https://git.petabyte.dev/petabyteboy/nixfiles";
rev = "b15d29e0440716fc37414547d55839717c9ed2f9";
};
qyliss-nixlib = fetchTarball {
url = "https://git.qyliss.net/nixlib/snapshot/nixlib-e14330c5be9b005d4310cd4dc0d384cff882aedc.tar.zst";
sha256 = "0nan14ixhdzxxddnckqqhaxhr96yw08rgcmxssddhji6aq5a445j";
};
home-manager = fetchGit {
url = "https://github.com/nix-community/home-manager";
rev = "a98ec6ec158686387d66654ea96153ec06be33d7";
};
in {
imports = [
(pbb-nixfiles + "/modules")
(home-manager + "/nixos")
];
nixpkgs.overlays = [
(self: super: {
pleroma = self.callPackage (pbb-nixfiles + "/pkgs/pleroma") {
elixir_1_10 = super.elixir;
};
dino = self.callPackage (qyliss-nixlib + "/overlays/patches/dino") {
inherit (super) dino;
};
})
];
}

View file

@ -0,0 +1,79 @@
{config, lib, pkgs, ...}:
{
home-manager.users.hexchen = {
programs.direnv = {
enable = true;
enableFishIntegration = true;
enableNixDirenvIntegration = true;
};
programs.fish = {
enable = true;
shellAliases = {
icat = "${pkgs.kitty}/bin/kitty +kitten icat";
};
plugins = [
{
name = "bass";
src = pkgs.fetchFromGitHub {
owner = "edc";
repo = "bass";
rev = "d63054b24c2f63aaa3a08fb9ec9d0da4c70ab922";
sha256 = "0pwci5xxm8308nrb52s5nyxijk0svar8nqrdfvkk2y34z1cg319b";
};
}
];
};
programs.vim = {
enable = true;
extraConfig = ''
set viminfo='20,<1000
set mouse=a
''; /*
set tabstop=2
set shiftwidth=2
set expandtab
'';*/
};
programs.git = {
enable = true;
userName = "hexchen";
userEmail = "hexchen@lilwit.ch";
signing = {
key = "B1DF5EAD";
signByDefault = false;
};
extraConfig = {
pull.rebase = true;
};
};
programs.bat.enable = true;
programs.jq.enable = true;
programs.tmux.enable = true;
programs.ssh = {
enable = true;
controlMaster = "auto";
controlPersist = "10m";
hashKnownHosts = true;
matchBlocks = let
hexchen = {
forwardAgent = true;
extraOptions = {
RemoteForward = "/run/user/1000/gnupg/S.gpg-agent /run/user/1000/gnupg/S.gpg-agent.extra";
};
port = 62954;
};
in {
"*.chaoswit.ch" = hexchen;
"*.copyonwit.ch" = hexchen;
"*.lilwit.ch" = hexchen;
"*.hxchn.de" = hexchen;
"*.hacc.space" = hexchen;
"*.hacc.media" = hexchen;
};
};
};
}

View file

@ -1,4 +1,4 @@
{ config, pkgs, lib, ... }:
{ config, pkgs, ... }:
{
imports = [
@ -12,11 +12,17 @@
openssh.authorizedKeys.keys = with pkgs.lib; concatLists (mapAttrsToList (name: user: if elem "wheel" user.extraGroups then user.openssh.authorizedKeys.keys else []) config.users.users);
};
# all the actual config is imported from hexchen's nixfiles
hexchen = {
uid = lib.mkForce 1000;
uid = 1000;
isNormalUser = true;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDNVUDKx9sukRkb6INny432+2HZBWx/qIEAOvngF1qcj hexchen@montasch"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEvzA8w0/th/EJcqwogd5LIyTV4lcK6iSbkRYUtKli/V hexchen@mobile"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI3T1eFS77URHZ/HVWkMOqx7W1U54zJtn9C7QWsHOtyH72i/4EVj8SxYqLllElh1kuKUXSUipPeEzVsipFVvfH0wEuTDgFffiSQ3a8lfUgdEBuoySwceEoPgc5deapkOmiDIDeeWlrRe3nqspLRrSWU1DirMxoFPbwqJXRvpl6qJPxRg+2IolDcXlZ6yxB4Vv48vzRfVzZNUz7Pjmy2ebU8PbDoFWL/S3m7yOzQpv3L7KYBz7+rkjuF3AU2vy6CAfIySkVpspZZLtkTGCIJF228ev0e8NvhuN6ZnjzXxVTQOy32HCdPdbBbicu0uHfZ5O7JX9DjGd8kk1r2dnZwwy/ hexchen@yubi5"
];
shell = pkgs.fish;
packages = with pkgs; [ python38 go ];
};
stuebinm = {
@ -48,13 +54,12 @@
packages = with pkgs; [ ffmpeg ];
};
moira = {
schweby = {
uid = 1004;
shell = pkgs.fish;
isNormalUser = true;
extraGroups = [ "wheel" "cdrom" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJrcJRF71+XM5YZj+SaSiGcdVZ0IDxGBXIWssDtHiTtr moira_2022_06"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL6JWi0MBDz0Zy4zjauQv28xYmHyapb8D4zeesq91LLE schweby@txsbcct"
];
hashedPassword = "$6$zkAsaVdmIduqZxez$GY9aBlYeP41F0it/VbbZzLLLRQhHAbDdFsa3e/1GS9McTuSimMHODg6HqNVEH1zSqD3afhK/0UHfqbtF5qpi90";
};

View file

@ -0,0 +1,51 @@
{ config, lib, pkgs, ... }:
{
boot.plymouth.enable = true;
nixpkgs.config = {
mumble.speechdSupport = true;
allowUnfree = true;
};
# boot.plymouth.splashBeforeUnlock = true;
users.users.schweby.packages = config.users.users.hexchen.packages
++ (with pkgs; [ alacritty picom feh copyq polybar cinnamon.nemo rofi arandr notepadqq nomacs bat ]);
users.users.hexchen = {
packages = with pkgs; [
pulsemixer pavucontrol
firefox git kitty j4-dmenu-desktop bemenu
breeze-qt5 mako
mpv youtube-dl
wl-clipboard mumble
xdg_utils
slurp grim libnotify
_1password-gui
# gnome3.nautilus
];
extraGroups = [ "video" "audio" ];
};
home-manager.users.hexchen = {
gtk = {
enable = true;
iconTheme = {
name = "Adwaita";
package = pkgs.gnome3.adwaita-icon-theme;
};
theme = {
name = "Adwaita";
package = pkgs.gnome3.adwaita-icon-theme;
};
};
};
sound.enable = true;
hardware.pulseaudio = {
enable = true;
package = pkgs.pulseaudioFull;
};
networking.useDHCP = lib.mkDefault true;
hardware.opengl.enable = true;
services.xserver = {
windowManager.bspwm.enable = true;
layout = "de";
};
}

View file

@ -7,4 +7,13 @@
};
environment.systemPackages = with pkgs; [ obs-studio ];
home-manager.users.hexchen = {
programs.obs-studio = {
enable = true;
plugins = with pkgs; [
obs-wlrobs obs-v4l2sink
];
};
};
}

View file

@ -0,0 +1,42 @@
{ config, pkgs, lib, ... }:
{
fonts.fonts = with pkgs; [ font-awesome nerdfonts ];
users.users.hexchen.packages = with pkgs; [ ];
home-manager.users.hexchen = {
programs.waybar = {
enable = true;
settings = [{
modules-left = [ "sway/workspaces" "sway/mode" ];
modules-center = [ "sway/window" ];
modules-right = [ "pulseaudio" "network" "cpu" "memory" "temperature" "battery" "clock" "tray" ];
modules = {
battery = {
states = {
good = 95;
warning = 30;
critical = 15;
};
format = "{capacity}% {icon}";
format-charging = "{capacity}% ";
format-plugged = "{capacity}% ";
format-alt = "{time} {icon}";
format-icons = ["" "" "" "" ""];
};
network = {
format-wifi = "{essid} ({signalStrength}%) ";
format-ethernet = "{ifname}: {ipaddr}/{cidr} ";
format-linked = "{ifname} (No IP) ";
format-disconnected = "Disconnected ";
format-alt = "{ifname}: {ipaddr}/{cidr}";
};
};
}];
};
};
programs.sway.enable = true;
}

View file

@ -0,0 +1,22 @@
# deploy auf hainich
**NICHT** nix os-re build sw itch
Auf hainich mit ssh verbinden.
Im root Verzeichnis sollte das haccfiles repro (das hier) liegen
Falls ja, einfach pullen
``git pull origin main;``
sonst erneut clonen
``git clone https://gitlab.infra4future.de/infra/haccfiles.git``
dann in das repro wechseln
``cd /root/haccfiles``
Und das ganze bauen
``nix build -f . -I nixpkgs=https://github.com/hexchen/nixpkgs/archive/hexchen-20.09.tar.gz deploy.hainich``
und mit ``./result`` als neue boot option auswählen und darauf wechseln
oder
mit``./result test`` das ganze nur bis zum reboot zu behalten.

View file

@ -0,0 +1,26 @@
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-config.nix
../../../common
../../../server/cdn/cdn-lb.nix
];
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.devices = [ "/dev/sda" ];
networking.interfaces.ens3.useDHCP = true;
networking.hostName = "cdn-loadbalancer";
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "20.03"; # Did you read the comment?
}

View file

@ -0,0 +1,26 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, ... }:
{
imports =
[ <nixpkgs/nixos/modules/profiles/qemu-guest.nix>
];
boot.initrd.availableKernelModules = [ "ata_piix" "virtio_pci" "xhci_pci" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/e371ee1d-a03f-4964-b03d-4a5c59ff5911";
fsType = "ext4";
};
swapDevices = [ ];
nix.maxJobs = lib.mkDefault 1;
}

View file

@ -0,0 +1,26 @@
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-config.nix
../../../common
../../../server/cdn/cdn-master.nix
];
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.devices = [ "/dev/sda" ];
networking.interfaces.ens3.useDHCP = true;
networking.hostName = "cdn-master";
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "20.03"; # Did you read the comment?
}

View file

@ -0,0 +1,25 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, ... }:
{
imports =
[ <nixpkgs/nixos/modules/profiles/qemu-guest.nix>
];
boot.initrd.availableKernelModules = [ "ata_piix" "virtio_pci" "xhci_pci" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/14cc7936-f928-41e3-8f72-ee6bf18d6c19";
fsType = "ext4";
};
swapDevices = [ ];
nix.maxJobs = lib.mkDefault 1;
}

View file

@ -0,0 +1,26 @@
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-config.nix
../../../common
../../../server/cdn/cdn-node.nix
];
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.devices = [ "/dev/sda" ];
networking.interfaces.ens3.useDHCP = true;
networking.hostName = "cdn-node-1";
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "20.03"; # Did you read the comment?
}

View file

@ -0,0 +1,25 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, ... }:
{
imports =
[ <nixpkgs/nixos/modules/profiles/qemu-guest.nix>
];
boot.initrd.availableKernelModules = [ "ata_piix" "virtio_pci" "xhci_pci" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/52dddb3d-9294-4105-9157-bf003dc7bdf9";
fsType = "ext4";
};
swapDevices = [ ];
nix.maxJobs = lib.mkDefault 1;
}

View file

@ -0,0 +1,26 @@
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-config.nix
../../../common
../../../server/cdn/cdn-node.nix
];
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.devices = [ "/dev/sda" ];
networking.interfaces.ens3.useDHCP = true;
networking.hostName = "cdn-node-2";
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "20.03"; # Did you read the comment?
}

View file

@ -0,0 +1,25 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, ... }:
{
imports =
[ <nixpkgs/nixos/modules/profiles/qemu-guest.nix>
];
boot.initrd.availableKernelModules = [ "ata_piix" "virtio_pci" "xhci_pci" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/a92ff89e-e1c2-4fda-8711-1be7257f6470";
fsType = "ext4";
};
swapDevices = [ ];
nix.maxJobs = lib.mkDefault 1;
}

View file

@ -0,0 +1,37 @@
let
hosts = {
hainich = {
ssh.host = "hainich.hacc.space";
groups = [ "server" "hacc" ];
};
nixda = {
ssh.host = "nixda.hacc.space";
groups = [ "server" "desktop" "hacc" "live" ];
};
"cdn/node-2" = {
ssh.host = "cdn-node-2.live.hacc.media";
groups = [ "server" "hacc" "live" "livecdn" "livecdn-node" ];
};
"cdn/node-1" = {
ssh.host = "cdn-node-1.live.hacc.media";
groups = [ "server" "hacc" "live" "livecdn" "livecdn-node" ];
};
"cdn/master" = {
ssh.host = "cdn-master.live.hacc.media";
groups = [ "server" "hacc" "live" "livecdn" "livecdn-master" ];
};
"cdn/loadbalancer" = {
ssh.host = "cdn-loadbalancer.live.hacc.media";
groups = [ "server" "hacc" "live" "livecdn" "livecdn-lb" ];
};
};
pkgs = import <nixpkgs> {};
evalConfig = import <nixpkgs/nixos/lib/eval-config.nix>;
lib = pkgs.lib;
in lib.mapAttrs (name: host: host // {
config = if (host ? config) then host.config else (evalConfig {
modules = [
(import "${toString ./.}/${name}/configuration.nix")
];
}).config;
}) hosts

View file

@ -0,0 +1,107 @@
{ config, lib, pkgs, ... }:
{
imports = [
../../common
./encboot.nix
./hardware.nix
./services/murmur.nix
./services/mail.nix
# ./services/engelsystem.nix
./services/codimd.nix
../../common
# ./wireguard.nix
./services/nginx.nix
# ./k8s.nix
./services/docker.nix
./services/gitlab-runner.nix
./services/funkwhale.nix
];
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.device = "/dev/sda";
boot.supportedFilesystems = [ "zfs" ];
# networking
networking.hostName = "hainich";
networking.hostId = "8a58cb2f";
networking.useDHCP = true;
networking.interfaces.enp6s0.ipv4.addresses = [
{
address = "46.4.63.148";
prefixLength = 27;
}
{
address = "46.4.63.158";
prefixLength = 27;
}
];
networking.interfaces.enp6s0.ipv6.addresses = [ {
address = "2a01:4f8:140:84c9::1";
prefixLength = 64;
} ];
networking.defaultGateway = "46.4.63.129";
networking.nameservers = [
"1.1.1.1" "1.0.0.1"
"2606:4700:4700::1111" "2606:4700:4700::1001"
];
networking.defaultGateway6 = {
address = "fe80::1";
interface = "enp6s0";
};
networking.nat.enable = true;
networking.nat.internalInterfaces = ["ve-+"];
networking.nat.externalInterface = "enp6s0";
networking.firewall.allowedTCPPorts = [ 22 80 443 ];
# networking.firewall.allowedUDPPorts = [ ... ];
# networking.firewall.enable = false;
# misc
time.timeZone = "UTC";
environment.systemPackages = with pkgs; [
wget vim git
];
services.openssh.enable = true;
services.openssh.ports = [ 22 62954 ];
users.users.root = {
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDNVUDKx9sukRkb6INny432+2HZBWx/qIEAOvngF1qcj hexchen@montasch"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL6JWi0MBDz0Zy4zjauQv28xYmHyapb8D4zeesq91LLE schweby@txsbcct"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCvmrk3i04tXfrSlZtHFbG3o6lQgh3ODMWmGDING4TJ4ctidexmMNY15IjVjzXZgQSET1uKLDLITiaPsii8vaWERZfjm3jjub845mpKkKv48nYdM0eCbv7n604CA3lwoB5ebRgULg4oGTi60rQ4trFf3iTkJfmiLsieFBZz7l+DfgeDEjDNSJcrkOggGBrjE5vBXoDimdkNh8kBNwgMDj1kPR/FHDqybSd5hohCJ5FzQg9vzl/x/H1rzJJKYPO4svSgHkYNkeoL84IZNeHom+UEHX0rw2qAIEN6AiHvNUJR38relvQYxbVdDSlaGN3g26H2ehsmolf+U0uQlRAXTHo0NbXNVYOfijFKL/jWxNfH0aRycf09Lu60oY54gkqS/J0GoQe/OGNq1Zy72DI+zAwEzyCGfSDbAgVF7Y3mU2HqcqGqNzu7Ade5oCbLmkT7yzDM3x6IsmT1tO8dYiT8Qv+zFAECkRpw3yDkJkPOxNKg10oM318whMTtM3yqntE90hk= schweby@taxusbaccata"
];
initialHashedPassword = "$6$F316njEF2$GMF4OmPSF6QgZ3P/DblQ/UFMgoo98bztbdw7X0ygvBGC1UMMIc13Vtxjd/ZGRYW/pEHACZZ7sbRZ48t6xhvO7/";
# shell = pkgs.fish;
};
# storage stuffs!
services.zfs = {
autoSnapshot = {
enable = true;
};
autoScrub = {
enable = true;
};
};
services.journald.extraConfig = ''
MaxFileSec=6h
MaxRetentionSec=72h
'';
boot.kernelPackages = pkgs.linuxPackages;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "20.03"; # Did you read the comment?
}

View file

@ -0,0 +1,28 @@
{ config, lib, pkgs, ... }:
{
boot.initrd.kernelModules = [ "r8169" ]; # add network card driver
boot.kernelParams = ["ip=:::::enp6s0:dhcp"]; # enable dhcp on primary network interface
boot.initrd.network = {
enable = true;
ssh = {
enable = true;
port = 2222;
# TODO: Modify system config so that this works
# authorizedKeys = with lib; concatLists (mapAttrsToList (name: user: if elem "wheel" user.extraGroups then user.openssh.authorizedKeys.keys else []) config.users.users);
authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys;
hostKeys = [ /run/keys/ecdsa_host ];
};
# TODO: curl some webhook here to alert?
# possibly quite hard to do, we only have limited wget or netcat available
# how this all works:
# when someone logs in via ssh, they are prompted to unlock the zfs volume
# afterwards zfs is killed in order for the boot to progress
# timeout of 120s still applies afaik
postCommands = ''
zpool import zroot
zpool import dpool
echo "zfs load-key -a; killall zfs && exit" >> /root/.profile
'';
};
}

View file

@ -0,0 +1,52 @@
{ config, lib, pkgs, ... }:
{
boot.initrd.availableKernelModules = [ "uhci_hcd" "ahci" "sd_mod" ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "zroot/root/nixos";
fsType = "zfs";
};
fileSystems."/nix" =
{ device = "zroot/root/nixos/nix";
fsType = "zfs";
};
fileSystems."/home" =
{ device = "dpool/home";
fsType = "zfs";
};
fileSystems."/var/lib/containers" =
{ device = "dpool/containers";
fsType = "zfs";
};
fileSystems."/var/lib/docker" =
{ device = "dpool/docker";
fsType = "zfs";
};
fileSystems."/var/lib/gitlab-runner" =
{ device = "dpool/gitlab-runner";
fsType = "zfs";
};
fileSystems."/data" =
{ device = "dpool/data";
fsType = "zfs";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/40125f55-7fe8-4850-902e-b4d6e22f0335";
fsType = "ext2";
};
swapDevices = [ ];
nix.maxJobs = lib.mkDefault 12;
powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
}

View file

@ -0,0 +1,125 @@
{ config, pkgs, ... }:
{
services.etcd = {
advertiseClientUrls = [
"https://[2a0d:eb04:8:10::1]:2379"
];
listenClientUrls = [
"https://[2a0d:eb04:8:10::1]:2379"
];
listenPeerUrls = [
"https://[::1]:2380"
];
};
services.kubernetes = {
roles = [ "master" "node" ];
flannel.enable = false;
addons.dns = {
enable = true;
clusterIp = "2a0d:eb04:8:11::53";
reconcileMode = "EnsureExists";
};
pki.cfsslAPIExtraSANs = [ "hainich.hacc.space" ];
apiserver = {
advertiseAddress = "2a0d:eb04:8:10::1";
extraSANs = [
"2a0d:eb04:8:10::1" "2a0d:eb04:8:11::1" "hainich.hacc.space"
];
bindAddress = "::";
insecureBindAddress = "::1";
etcd = {
servers = [ "https://[2a0d:eb04:8:10::1]:2379" ];
};
serviceClusterIpRange = "2a0d:eb04:8:11::/120";
extraOpts = "--allow-privileged=true";
};
controllerManager = {
bindAddress = "::";
clusterCidr = "2a0d:eb04:8:12::/64";
};
kubelet = {
address = "::";
clusterDns = "2a0d:eb04:8:11::53";
};
proxy = {
bindAddress = "::";
};
scheduler = {
address = "::1" ;
};
apiserverAddress = "https://[2a0d:eb04:8:10::1]:6443";
clusterCidr = "2a0d:eb04:8:12::/64";
easyCerts = true;
masterAddress = "hainich.hacc.space";
};
networking.firewall = {
allowedTCPPorts = [ 80 443 6443 ];
trustedInterfaces = [
"cbr0" "tunnat64"
];
extraCommands = ''
iptables -t nat -A POSTROUTING -o enp6s0 -j SNAT --to 46.4.63.158
iptables -A FORWARD -i tunnat64 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp -d 46.4.63.158 --dport 80 -j DNAT --to-destination 10.255.255.2:80
iptables -t nat -A PREROUTING -p tcp -d 46.4.63.158 --dport 443 -j DNAT --to-destination 10.255.255.2:443
iptables -t nat -A PREROUTING -p tcp -d 46.4.63.158 --dport 6443 -j DNAT --to-destination 10.255.255.1:443
ip6tables -A FORWARD -i tunnat64 -j ACCEPT
ip6tables -A INPUT -i tunnat64 -j ACCEPT
'';
extraStopCommands = ''
iptables -t nat -D POSTROUTING -o enp6s0 -j SNAT --to 46.4.63.158
iptables -D FORWARD -i tunnat64 -j ACCEPT
iptables -t nat -D PREROUTING -p tcp -d 46.4.63.158 --dport 80 -j DNAT --to-destination 10.255.255.2:80
iptables -t nat -D PREROUTING -p tcp -d 46.4.63.158 --dport 443 -j DNAT --to-destination 10.255.255.2:443
iptables -t nat -D PREROUTING -p tcp -d 46.4.63.158 --dport 6443 -j DNAT --to-destination 10.255.255.1:443
ip6tables -A FORWARD -i tunnat64 -j ACCEPT
ip6tables -A INPUT -i tunnat64 -j ACCEPT
'';
};
systemd.services.tayga = (let
config = pkgs.writeText "tayga.conf" ''
tun-device tunnat64
ipv4-addr 10.255.255.254
prefix 2a0d:eb04:8:10:64::/96
dynamic-pool 10.255.255.0/24
map 10.255.255.1 2a0d:eb04:8:10::1
map 10.255.255.2 2a0d:eb04:8:11::2
strict-frag-hdr 1
'';
startScript = pkgs.writeScriptBin "tayga-start" ''
#! ${pkgs.runtimeShell} -e
${pkgs.iproute}/bin/ip link set up tunnat64 || true
${pkgs.iproute}/bin/ip route add 10.255.255.0/24 dev tunnat64 || true
${pkgs.iproute}/bin/ip -6 route add 2a0d:eb04:8:10:64::/96 dev tunnat64 || true
${pkgs.tayga}/bin/tayga -d --config ${config}
'';
in {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
ExecStart = ''${startScript}/bin/tayga-start'';
};
});
networking.interfaces.cbr0.ipv6.routes = [{
address = "2a0d:eb04:8:10::";
prefixLength = 60;
}];
networking.interfaces.tunnat64 = {
virtual = true;
};
# openebs expects some stuff to be there.
system.activationScripts.openebs = ''
mkdir -p /usr/lib /usr/sbin
ln -sf ${pkgs.zfs.lib}/lib/* /usr/lib/
ln -sf ${pkgs.zfs}/bin/zfs /usr/sbin/
'';
}

View file

@ -0,0 +1,80 @@
{ config, lib, pkgs, ... }:
{
containers.codimd = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.3";
autoStart = true;
config = { config, lib, pkgs, ... }: {
networking.firewall.allowedTCPPorts = [ 3000 ];
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
services.hedgedoc = {
enable = true;
configuration = {
allowAnonymous = true;
allowFreeURL = true;
allowGravatar = false;
allowOrigin = [ "localhost" "pad.hacc.space" "fff-muc.de" ];
dbURL = "postgres://codimd:codimd@localhost:5432/codimd";
defaultPermission = "limited";
domain = "pad.hacc.space";
host = "0.0.0.0";
protocolUseSSL = true;
hsts.preload = false;
email = false;
oauth2 = {
authorizationURL = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/auth";
tokenURL = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/token";
clientID = "codimd";
clientSecret = "1a730af1-4d6e-4c1d-8f7e-72375c9b8d62";
};
};
};
systemd.services.hedgedoc.environment = {
"CMD_OAUTH2_USER_PROFILE_URL" = "https://auth.infra4future.de/auth/realms/forfuture/protocol/openid-connect/userinfo";
"CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR" = "name";
"CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR" = "display-name";
"CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR" = "email";
"CMD_OAUTH2_PROVIDERNAME" = "Infra4Future";
};
services.postgresql = {
enable = true;
ensureDatabases = [ "codimd" ];
ensureUsers = [{
name = "codimd";
ensurePermissions = {
"DATABASE codimd" = "ALL PRIVILEGES";
};
}];
};
};
};
services.nginx.virtualHosts."pad.hacc.space" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://192.168.100.3:3000";
extraConfig = ''
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
add_header Access-Control-Allow-Origin "*";
proxy_buffering off;
'';
};
};
}

View file

@ -0,0 +1,34 @@
{ config, lib, pkgs, ... }:
{
# disable nftables since it breaks shit
petabyte.nftables.enable = false;
virtualisation.oci-containers.containers."ghost-waszumfff" = {
autoStart = true;
environment = {
url = "https://waszumfff.4future.dev";
};
image = "ghost:alpine";
ports = [ "127.0.0.1:2368:2368" ];
volumes = [ "/run/florinori:/var/lib/ghost/content" ];
};
fileSystems."/run/florinori" =
{ device = "dpool/k8s/florinori";
fsType = "zfs";
};
services.nginx.virtualHosts."waszumfff.4future.dev" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:2368";
extraConfig = "
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
";
};
};
}

View file

@ -0,0 +1,93 @@
{ config, lib, pkgs, ... }:
# TODO: Make this confix nix-y, so it doesn't require a metric shitton of
# manual intervention to install
{
containers.engelsystem = {
config = { pkgs, lib, config, ... }:
let
app = "engelsystem";
domain = "himmel.hacc.earth";
dataDir = "/srv/http/${domain}/public";
engelport-py-pack = python-packages: with pkgs.python38Packages; [
mysqlclient
];
engelport-py = pkgs.python38.withPackages engelport-py-pack;
in {
networking.firewall.enable = false;
networking.nameservers = ["1.1.1.1" "1.0.0.1"];
networking.hosts."192.168.100.1" = [ "mail.hacc.space" ];
services.phpfpm.pools.${app} = {
user = app;
settings = {
"listen.owner" = config.services.nginx.user;
"pm" = "dynamic";
"pm.max_children" = 32;
"pm.max_requests" = 500;
"pm.start_servers" = 2;
"pm.min_spare_servers" = 2;
"pm.max_spare_servers" = 5;
"php_admin_value[error_log]" = "stderr";
"php_admin_flag[log_errors]" = true;
"catch_workers_output" = true;
};
phpEnv."PATH" = lib.makeBinPath [ pkgs.php ];
};
services.nginx = {
enable = true;
virtualHosts.${domain}.locations = {
"/" = {
extraConfig = "rewrite ^ /index.php;";
};
"/assets" = {
root = dataDir;
};
"/index.php" = {
root = dataDir;
extraConfig = ''
include ${pkgs.nginx}/conf/fastcgi.conf;
fastcgi_split_path_info ^(.+\.php)(\\/.*)$;
try_files $fastcgi_script_name =404;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass unix:${config.services.phpfpm.pools.${app}.socket};
fastcgi_intercept_errors on;
'';
};
};
};
users.users.${app} = {
isSystemUser = true;
createHome = true;
home = dataDir;
group = app;
};
users.groups.${app} = {};
services.mysql = {
enable = true;
ensureDatabases = [ "engelsystem" ];
ensureUsers = [{
name = "engelsystem";
ensurePermissions."engelsystem.*" = "ALL PRIVILEGES";
}];
package = pkgs.mariadb;
};
environment.systemPackages = [
pkgs.php pkgs.php74Packages.composer pkgs.yarn engelport-py
];
};
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.2";
autoStart = true;
};
services.nginx.virtualHosts."himmel.hacc.earth" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://192.168.100.2";
extraConfig = "add_header Host himmel.hacc.earth;";
};
};
}

View file

@ -0,0 +1,55 @@
{ config, lib, pkgs, ... }:
{
containers.funkwhale = {
inherit pkgs;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.4";
autoStart = true;
config = { config, lib, pkgs, ... }: {
imports = [
../../../../modules
];
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
networking.firewall.enable = false;
services.funkwhale = {
enable = true;
apiIp = "192.168.100.4";
hostname = "funkwhale.hacc.media";
protocol = "https";
defaultFromEmail = "funkwhale@hacc.media";
api.djangoSecretKey = "TwsgANNKid+HZ0HwhR/FgTcxFIW6sZ8s4n7HxV6zPdU=";
};
services.nginx.virtualHosts."funkwhale.hacc.media" = {
enableACME = lib.mkForce false;
forceSSL = lib.mkForce false;
};
};
};
services.nginx.virtualHosts."funkwhale.hacc.media" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://192.168.100.4";
extraConfig = ''
proxy_pass_request_headers on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_buffering off;
'';
};
};
}

View file

@ -0,0 +1,62 @@
{config, pkgs, lib, ...}:
{
services.gitlab-runner = {
enable = true;
concurrent = 4;
services = {
infra4future = {
buildsDir = "/var/lib/gitlab-runner/builds";
dockerImage = "nixos/nix";
executor = "docker";
registrationConfigFile = "/run/gitlab-runner.env";
};
nix = {
registrationConfigFile = "/run/gitlab-runner.env";
dockerImage = "alpine";
dockerVolumes = [
"/nix/store:/nix/store:ro"
"/nix/var/nix/db:/nix/var/nix/db:ro"
"/nix/var/nix/daemon-socket:/nix/var/nix/daemon-socket:ro"
];
dockerDisableCache = true;
preBuildScript = pkgs.writeScript "setup-container" ''
mkdir -p -m 0755 /nix/var/log/nix/drvs
mkdir -p -m 0755 /nix/var/nix/gcroots
mkdir -p -m 0755 /nix/var/nix/profiles
mkdir -p -m 0755 /nix/var/nix/temproots
mkdir -p -m 0755 /nix/var/nix/userpool
mkdir -p -m 1777 /nix/var/nix/gcroots/per-user
mkdir -p -m 1777 /nix/var/nix/profiles/per-user
mkdir -p -m 0755 /nix/var/nix/profiles/per-user/root
mkdir -p -m 0700 "$HOME/.nix-defexpr"
. ${pkgs.nix}/etc/profile.d/nix.sh
${pkgs.nix}/bin/nix-env -i ${lib.concatStringsSep " " (with pkgs; [ nix cacert git openssh ])}
${pkgs.nix}/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
${pkgs.nix}/bin/nix-channel --update nixpkgs
'';
environmentVariables = {
ENV = "/etc/profile";
USER = "root";
NIX_REMOTE = "daemon";
PATH = "/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/bin:/sbin:/usr/bin:/usr/sbin";
NIX_SSL_CERT_FILE = "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt";
};
tagList = [ "nix" ];
};
};
};
systemd.services.gitlab-runner.serviceConfig = {
DynamicUser = lib.mkForce false;
User = "gitlab-runner";
};
users.users.gitlab-runner = {
home = "/var/lib/gitlab-runner";
extraGroups = [ "docker" ];
isSystemUser = true;
};
virtualisation.docker.storageDriver = "zfs";
}

View file

@ -0,0 +1,154 @@
{ config, pkgs, lib, ... }:
{
imports = let commit = "02a45d9965133434c7b816cab2f47c8a7505e764"; in [
(builtins.fetchTarball {
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/${commit}/nixos-mailserver-${commit}.tar.gz";
sha256 = "04v66z0ijjm8bqpiqmq1aqrqj6r6jjz591lgijmk4frz7lksnz8k";
})
];
mailserver = {
mailDirectory = "/data/mail";
enable = true;
fqdn = "mail.hacc.space";
domains = [ "hacc.space" "hacc.earth" "4future.dev" "4futu.re" ];
loginAccounts = {
"hexchen@hacc.space" = {
hashedPassword = "$6$x9skYtRp4dgxC$1y8gPC2BuVqG3kJVSMGgzZv0Bg1T9qxcnBWLIDbANy1d//SQ23Y7s3IMYcEPd1/l/MYWD9Y/Qse6HbT5w5Xwq/";
aliases = [
"postmaster@hacc.space"
"abuse@hacc.space"
];
};
"octycs@hacc.space" = {
hashedPassword = "$6$KceTivtJ$58jxhYF6ULfivNsb3Z0J7PnGea0Hs2wTWh3c9FrKRIAmuOD96u2IDgZRCn6P5NrXA0BL.n6HC2RS3r.4JnOmg.";
aliases = [
"markus@hacc.space"
];
};
"raphael@hacc.space" = {
hashedPassword = "$6$QveHpwMcp9mkFVAU$EFuahOrJIxPg.c.WGFHtrP3.onwJYwvP7fiBHHGb9jhosewZ2tEUP.2D3uyDLhd9Cfny6Yp4jDk/Hkjk7/ME1/";
};
"engelsystem@hacc.space" = {
hashedPassword = "$6$5cIAEhJ7af7M$eJBPQc3ONd.N3HKPFpxfG7liZbUXPvWuSpWVgeG7rmsG7f7.Zdxtodvt5VaXoA3AEiv3GqcY.gKHISK/Gg0ib/";
};
"schweby@hacc.space" = {
hashedPassword = "$6$BpYhwcZNrkLhVqK$6FMqA/vUkdV4GBlHLSqS5DRCb/CaLDNeIsBcZ8G30heytS/tJj2Ag7b1ovSltTA4PUfhee3pJrz1BkwkA93vN1";
};
"zauberberg@hacc.space" = {
hashedPassword = "$6$ISAaU8X6D$oGKe9WXDWrRpGzHUTdxrxdtg9zuGOlBMuDc82IZhegpsv1bqd550FhZZrI40IjZTA5Hy2MZ8j/0efpnQ4fOQH0";
aliases = [
"lukas@hacc.space"
];
};
"talx@hacc.space" = {
hashedPassword = "$6$0hIKRoMJS./JSE$tXizRgphhNM3ZYx216VdRv1OiyZoYXsjGqSudTDu8vB8eZb03Axi31VKV87RXiEGGixdvTsHEKpx032aOzzt31";
};
"unms@hacc.space" = {
hashedPassword = "$6$pYlNP37913$sGE3L722ceP.1Qm5lsffYUN919hPP1xRTrzco3ic3Op21iiknBkOY04eY2l3Um/Bpk/yV89aJD0eaB/5RCbWR1";
};
"noreply@hacc.space" = {
hashedPassword = "$6$YsqMoItITZUzI5wo$5Lejf8XBHRx4LW4VuZ9wJCiBbT4kOV/EZaCdWQ07eVIrkRTZwXWZ5zfsh.olXEFwvpNWN.DBnU.dQc.cC0/ra/";
};
"stuebinm@hacc.space" = {
hashedPassword = "$6$mjrMQG5smqLRlm$WzmbiZnGlEXGT7hj/n2qz0nvVzGyZfMToCyLRi0wErfVEHI7y7jtWoHqIWnpcHAM29UocsIFFsUCb3XqQCwwB.";
};
"newsletter@hacc.space" = {
hashedPassword = "$6$f0xKnQxBInd$zbVIi1lTKWauqW.c8sMNLHNwzn81oQrVOiIfJwPa98n9xWz/NkjuWLYuFpK.MSZwNwP7Yv/a/qaOb9v8qv/.N1";
};
"lenny@hacc.space" = {
hashedPassword = "$6$dR.lhYiJDpsR4.dw$n7bCbyTm97v/O8Ue44n58YwOmmct..Gt5TeAmen8C5FWyPTwTh65XCjwc27gNFVGnZLwsRJwMJ.E9D0oJEzUh0";
};
};
extraVirtualAliases = {
# address = forward address;
"info@hacc.space" = [
"hexchen@hacc.space"
"octycs@hacc.space"
"raphael@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
"stuebinm@hacc.space"
"lenny@hacc.space"
];
"himmel@hacc.space" = [
"hexchen@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
];
"admin@hacc.space" = [
"hexchen@hacc.space"
"schweby@hacc.space"
];
"voc@hacc.space" = [
"hexchen@hacc.space"
"schweby@hacc.space"
"octycs@hacc.space"
"stuebinm@hacc.space"
"zauberberg@hacc.space"
"lenny@hacc.space"
];
"vorstand@hacc.space" = [
"raphael@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
];
"mitglieder@hacc.space" = [
"raphael@hacc.space"
"schweby@hacc.space"
"zauberberg@hacc.space"
"lenny@hacc.space"
"octycs@hacc.space"
];
};
# Use Let's Encrypt certificates. Note that this needs to set up a stripped
# down nginx and opens port 80.
certificateScheme = 3;
# Enable IMAP and POP3
enableImap = true;
enablePop3 = true;
enableImapSsl = true;
enablePop3Ssl = true;
# Enable the ManageSieve protocol
enableManageSieve = true;
# whether to scan inbound emails for viruses (note that this requires at least
# 1 Gb RAM for the server. Without virus scanning 256 MB RAM should be plenty)
virusScanning = false;
};
services.postfix.submissionOptions.smtpd_sender_restrictions = "reject_non_fqdn_sender,reject_unknown_sender_domain,permit";
services.postfix.virtual = ''
@4future.dev @hacc.space
@4futu.re @hacc.space
@hacc.earth @hacc.space
contact@hacc.space info@hacc.space
'';
systemd.services.alps = {
enable = true;
script = "${pkgs.alps}/bin/alps -theme alps imaps://mail.hacc.space:993 smtps://mail.hacc.space:465";
serviceConfig.WorkingDirectory = "${pkgs.alps}/share/alps";
};
services.nginx.virtualHosts."mail.hacc.space" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://[::1]:1323";
};
}

View file

@ -0,0 +1,26 @@
{ config, lib, pkgs, ... }:
{
services.murmur = {
enable = true;
logDays = -1;
welcometext = "Welcome to mumble4future! Brought to you by infra4future";
sslKey = "/var/lib/acme/mumble.hacc.space/key.pem";
sslCert = "/var/lib/acme/mumble.hacc.space/fullchain.pem";
bandwidth = 128000;
};
networking.firewall.allowedTCPPorts = [ config.services.murmur.port ];
networking.firewall.allowedUDPPorts = [ config.services.murmur.port ];
services.nginx.virtualHosts."mumble.hacc.space" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "https://stuebinm.4future.dev/mumble.infra4future.de/";
};
};
# set ACLs so that the murmur user can read the certificates
security.acme.certs."mumble.hacc.space".postRun = "setfacl -Rm u:murmur:rX /var/lib/acme/mumble.hacc.space";
}

View file

@ -0,0 +1,61 @@
{ config, lib, pkgs, ... }:
{
security.acme.acceptTerms = true;
security.acme.email = "info+acme@hacc.space";
services.nginx.enable = true;
services.nginx.package = pkgs.nginx.override {
modules = [ pkgs.nginxModules.rtmp ];
};
# services.nginx.recommendedProxySettings = true;
services.nginx.virtualHosts = let
rc3clustersite = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "https://stuebinm.4future.dev/about-future-website/";
};
in {
"hainich.chaoswit.ch" = {
enableACME = true;
forceSSL = true;
};
"hainich.hacc.space" = {
enableACME = true;
forceSSL = true;
locations = {
"/" = {
return = "404";
};
};
};
"freedom.rc3.io" = rc3clustersite;
"future.rc3.io" = rc3clustersite;
};
networking.firewall.allowedTCPPorts = [ 1935 ];
services.nginx.appendConfig = ''
rtmp {
server {
listen 1935;
application cutiestream {
live on;
allow publish all;
allow play all;
}
application ingest {
live on;
record all;
record_path /data/ingest;
record_unique on;
include /var/secrets/ingest.conf;
}
}
}
'';
systemd.services.nginx.serviceConfig.ReadWriteDirectories = "/data/ingest /var/secrets";
}

View file

@ -0,0 +1,34 @@
{ config, lib, pkgs, ... }:
{
systemd.services.wireguard-upstream = {
wants = [ "wg-upstream-key.service" ];
after = [ "wg-upstream-key.service" ];
};
networking.wireguard.interfaces.upstream = {
ips = [ "2a0d:eb04:8:ffff:2::2/128" ];
generatePrivateKeyFile = true;
privateKeyFile = "/etc/wireguard/upstream.key";
listenPort = 51820;
peers = [
{
allowedIPs = [ "::/0" ];
endpoint = "103.105.50.220:51823";
publicKey = "qL5xKnQ7xLbtTvu0VmLBwHExteJBhmCe5S/0ZoXBeXY=";
}
];
postSetup = ''
${pkgs.iproute}/bin/ip addr del dev upstream 2a0d:eb04:8:ffff:2::2/128
${pkgs.iproute}/bin/ip addr add dev upstream 2a0d:eb04:8:ffff:2::2/128 peer 2a0d:eb04:8:ffff:2::1/128
'';
};
networking.interfaces.lo.ipv6 = {
addresses = [{
address = "2a0d:eb04:8:10::1";
prefixLength = 128;
}];
};
networking.defaultGateway6 = {
address = "2a0d:eb04:8:ffff:2::1";
interface = "upstream";
};
}

View file

@ -1,4 +1,4 @@
{ config, pkgs, lib, ... }:
{ config, pkgs, ... }:
{
imports =
@ -7,6 +7,7 @@
../../common
../../desktop
../../desktop/streaming.nix
../../desktop/sway.nix
../../desktop/gnome.nix
];
@ -25,15 +26,14 @@
networking.hostName = "nixda"; # Define your hostname.
environment.systemPackages = with pkgs; [ blackmagicDesktopVideo blender companion ];
environment.systemPackages = with pkgs; [ blackmagicDesktopVideo makemkv blender ];
networking.wg-quick.interfaces.cornbox = {
privateKeyFile = "/etc/wireguard/cornbox.key";
address = [ "195.39.247.67/28" "2a0f:4ac0:1337::12/64" ];
postUp = "/run/wrappers/bin/ping -c5 195.39.247.65";
postUp = "ip link set dev cornbox mtu 1400";
peers = [
{
persistentKeepalive = 25;
allowedIPs = [ "2a0f:4ac0:1337::/48" "195.39.247.64/27" ];
publicKey = "8IWyiQL3wKP9CD/4UdS9b8mcbL67mkUyeSPORgEPvV0=";
endpoint = "cornbox.hetzner.chaoswit.ch:51821";
@ -41,34 +41,6 @@
];
};
services.xserver = {
enable = true;
videoDrivers = [ "nvidia" ];
};
hardware.nvidia.modesetting.enable = true;
boot.kernelPackages = pkgs.linuxPackages;
boot.blacklistedKernelModules = [ "snd_blackmagic_io" ];
users.users.stream = {
isNormalUser = true;
password = "hacchacc";
extraGroups = [ "audio" "video" ];
openssh.authorizedKeys.keys = with pkgs.lib; concatLists (mapAttrsToList (name: user: if elem "wheel" user.extraGroups then user.openssh.authorizedKeys.keys else []) config.users.users);
};
services.pipewire.enable = true;
services.pipewire.pulse.enable = true;
hardware.pulseaudio.enable = lib.mkForce false;
services.udev.extraRules = ''
SUBSYSTEM=="input", GROUP="input", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006?", MODE:="666", GROUP="plugdev"
KERNEL=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006?", MODE:="666", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="ffff", ATTRS{idProduct}=="1f4?", MODE:="666", GROUP="plugdev"
KERNEL=="hidraw", ATTRS{idVendor}=="ffff", ATTRS{idProduct}=="1f4?", MODE:="666", GROUP="plugdev"
'';
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. Its perfectly fine and recommended to leave

View file

@ -0,0 +1,26 @@
{config, lib, pkgs, ...}:
{
imports = [
./common.nix
];
services.nginx = {
virtualHosts."${config.networking.hostName}.live.hacc.media" = {
locations = {
"/" = {
return = "301 \"https://$cdnhosts$request_uri\"";
extraConfig = ''
auth_basic off;
add_header 'Access-Control-Allow-Origin' '*';
'';
};
};
};
appendHttpConfig = ''
split_clients "$remote_addr" $cdnhosts {
50% "cdn-node-1.live.hacc.media";
50% "cdn-node-2.live.hacc.media";
}
'';
};
}

View file

@ -0,0 +1,42 @@
{config, lib, pkgs, ...}:
let
host-server = "https://rosenbaum.lukas.studio";
in {
imports = [
./common.nix
];
services.nginx = {
virtualHosts."${config.networking.hostName}.live.hacc.media" = {
locations = {
"~* \\.(m3u8)$" = {
proxyPass = "${host-server}$request_uri";
extraConfig = ''
#proxy_cache = off;
expires 2s;
auth_basic off;
'';
};
"/hls" = {
proxyPass = "${host-server}$request_uri";
extraConfig = ''
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
proxy_cache hls;
proxy_ignore_headers Cache-Control;
proxy_cache_valid any 30m;
auth_basic off;
'';
};
};
};
appendHttpConfig = ''
proxy_cache_path /tmp keys_zone=hls:10m max_size=10g inactive=60m use_temp_path=on;
resolver 1.1.1.1;
'';
};
}

View file

@ -0,0 +1,43 @@
{config, lib, pkgs, ...}:
{
imports = [
./common.nix
];
# Enable nginx service
services.nginx = {
virtualHosts."${config.networking.hostName}.live.hacc.media" = {
forceSSL = true;
enableACME = true;
# basicAuth = basicAuthLogin;
locations = {
"~* \\.(m3u8)$" = {
proxyPass = "https://cdn-master.live.hacc.media$request_uri";
extraConfig = ''
#proxy_cache = off;
expires 3s;
auth_basic off;
'';
};
"/hls" = {
proxyPass = "https://cdn-master.live.hacc.media$request_uri";
extraConfig = ''
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
proxy_cache hls;
proxy_ignore_headers Cache-Control;
proxy_cache_valid any 30m;
auth_basic off;
'';
};
};
};
appendHttpConfig = ''
proxy_cache_path /tmp keys_zone=hls:10m max_size=10g inactive=60m use_temp_path=on;
resolver 1.1.1.1;
'';
};
}

View file

@ -0,0 +1,61 @@
{config, lib, pkgs, ...}:
{
networking.firewall.allowedTCPPorts = [
80 # HTTP
443 # HTTPs
];
services.netdata = {
enable = true;
configText = ''
[global]
dbengine multihost disk space = 2307
'';
};
# Enable nginx service
services.nginx = {
enable = true;
# Use recommended settings
# Don't use recommended Proxy settings because it does funky things with the setup
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedTlsSettings = true;
virtualHosts."${config.networking.hostName}.live.hacc.media" = {
forceSSL = true;
enableACME = true;
# basicAuth = basicAuthLogin;
locations = {
"/stats" = {
return = "301 /stats/";
};
"~ /stats/(?<ndpath>.*)" = {
proxyPass = "http://127.0.0.1:19999/$ndpath$is_args$args";
extraConfig = ''
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_pass_request_headers on;
proxy_set_header Connection "keep-alive";
proxy_store off;
gzip on;
gzip_proxied any;
gzip_types *;
'';
};
"/nginx_status" = {
extraConfig = ''
stub_status;
auth_basic off;
'';
};
};
};
};
}

View file

@ -1,11 +1,4 @@
rec {
sources = import ./nix/sources.nix;
pkgs = import ./pkgs {};
inherit (pkgs) lib;
inherit (import (sources.nix-hexchen + "/lib/hosts.nix") {
inherit pkgs sources;
inherit ((import sources.nix-hexchen) {}) modules;
hostsDir = ./hosts; commonImports = [./common]; pkgsPath = ./pkgs;
}) hosts groups;
deploy = import (sources.nix-hexchen + "/lib/deploy.nix") { inherit pkgs hosts groups; };
{
inherit (import ./lib/deploy.nix) deploy;
pkgs = import ./pkgs;
}

View file

@ -1,35 +0,0 @@
{ config, lib, pkgs, ... }:
{
boot.plymouth.enable = true;
nixpkgs.config = {
mumble.speechdSupport = true;
allowUnfree = true;
};
# boot.plymouth.splashBeforeUnlock = true;
environment.systemPackages = with pkgs; [
pulsemixer pavucontrol
firefox kitty j4-dmenu-desktop bemenu
breeze-qt5 mako
mpv youtube-dl
wl-clipboard mumble
xdg_utils
slurp grim libnotify
_1password-gui
gimp
# gnome3.nautilus
] ++ (with pkgs; [ alacritty picom feh copyq polybar cinnamon.nemo rofi arandr notepadqq nomacs imv gthumb ]);
sound.enable = true;
time.timeZone = "Europe/Berlin";
hardware.pulseaudio = {
enable = true;
package = pkgs.pulseaudioFull;
};
networking.useDHCP = lib.mkDefault true;
hardware.opengl.enable = true;
services.xserver = {
windowManager.bspwm.enable = true;
layout = "de";
};
}

View file

@ -1,96 +0,0 @@
{ config, lib, pkgs, sources, modules, ... }:
{
imports = [
../../common
./hardware.nix
modules.encboot
modules.network.nftables modules.nftnat
((import sources.nix-hexchen) {}).profiles.nopersist
../../services/nextcloud
../../services/mattermost.nix
../../services/thelounge.nix
../../services/murmur.nix
../../services/hedgedoc-hacc.nix
../../services/hedgedoc-i4f.nix
../../services/mail.nix
../../services/syncthing.nix
../../services/gitea.nix
../../services/nginx-pages.nix
../../services/lantifa.nix
../../services/vaultwarden.nix
../../services/uffd.nix
# ../../services/workadventure.nix
./lxc.nix
];
hexchen.encboot = {
enable = true;
dataset = "-a";
networkDrivers = [ "igb" ];
};
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
boot.loader.grub.devices = [ "/dev/nvme0n1" "/dev/nvme1n1" ];
boot.supportedFilesystems = [ "zfs" ];
networking.hostId = "b2867696";
networking.useDHCP = true;
networking.nftables.enable = true;
hexchen.nftables.nat.enable = true;
networking.nat.internalInterfaces = ["ve-+"];
networking.nat.externalInterface = "enp35s0";
networking.interfaces.enp35s0.ipv6.addresses = [{
address = "2a01:4f9:3a:2ddb::1";
prefixLength = 64;
}];
networking.defaultGateway6 = {
address = "fe80::1";
interface = "enp35s0";
};
boot = {
kernelModules = [ "nf_nat_ftp" ];
kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = lib.mkOverride 90 true;
"net.ipv4.conf.default.forwarding" = lib.mkOverride 90 true;
};
};
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts = {
"parsons.hacc.space" = {
default = true;
locations."/".return = "404";
};
"hacc.space" = {
enableACME = true;
forceSSL = true;
locations."/".return = "302 https://hacc.earth";
};
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.restic.backups.tardis = {
passwordFile = "/persist/restic/system";
environmentFile = "/persist/restic/system.s3creds";
paths = [
"/home"
"/persist"
];
pruneOpts = [
"--keep-daily 7"
"--keep-weekly 5"
"--keep-monthly 3"
];
repository = "b2:tardis-parsons:system";
};
system.stateVersion = "21.05";
}

View file

@ -1,65 +0,0 @@
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "zroot/local/root";
fsType = "zfs";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/daf2a731-952f-45c7-9c25-49e1a2f56062";
fsType = "ext4";
};
fileSystems."/nix" =
{ device = "zroot/local/nix";
fsType = "zfs";
};
fileSystems."/persist" =
{ device = "zroot/safe/persist";
fsType = "zfs";
};
fileSystems."/home" =
{ device = "zroot/safe/home";
fsType = "zfs";
};
fileSystems."/root" =
{ device = "zroot/safe/root";
fsType = "zfs";
};
fileSystems."/var/cache/restic-backups-tardis" =
{ device = "zroot/safe/restic-cache";
fsType = "zfs";
};
fileSystems."/tmp" =
{ device = "zroot/local/tmp";
fsType = "zfs";
};
fileSystems."/persist/data" =
{ device = "dpool/safe/data";
fsType = "zfs";
};
fileSystems."/var/lib/docker" =
{ device = "zroot/local/docker";
fsType = "zfs";
};
swapDevices = [ ];
}

View file

@ -1,36 +0,0 @@
{ config, lib, pkgs, ... }:
{
networking.bridges.lxcbr0.interfaces = [];
networking.interfaces.lxcbr0.ipv4.addresses = [
{
address = "10.1.2.1";
prefixLength = 24;
}
];
networking.nat.internalInterfaces = [ "lxcbr0" ];
virtualisation.lxc.enable = true;
virtualisation.lxc.systemConfig = ''
lxc.bdev.zfs.root = zroot/safe/containers/lxc
lxc.lxcpath = /persist/lxc
'';
users.users.root.subUidRanges = [{ count = 65536; startUid = 100000; }];
users.users.root.subGidRanges = [{ count = 65536; startGid = 100000; }];
environment.etc."lxc/share".source = "${pkgs.lxc}/share/lxc";
services.nginx.virtualHosts."onlyoffice.infra4future.de" = {
locations."/".proxyPass = "http://10.1.2.233:80";
enableACME = true;
forceSSL = true;
};
services.nginx.virtualHosts."auth.infra4future.de" = {
locations."/".proxyPass = "http://10.1.2.104:8080";
enableACME = true;
forceSSL = true;
};
}

76
lib/deploy.nix Normal file
View file

@ -0,0 +1,76 @@
let
pkgs = import <nixpkgs> {};
lib = pkgs.lib;
hosts = import ../configuration/hosts;
nixosHosts = lib.filterAttrs (name: host: host ? ssh) hosts;
allGroups = lib.unique (
lib.flatten (
lib.mapAttrsToList (
name: host: host.groups
) hosts
)
);
hostsInGroup = group:
lib.filterAttrs (
k: v: builtins.elem group v.groups
) hosts;
hostsInAllGroups = lib.listToAttrs (
map (
group: lib.nameValuePair group (
lib.attrNames (hostsInGroup group)
)
) allGroups );
mkDeploy = hostnames: pkgs.writeScript "deploy-${lib.concatStringsSep "-" hostnames}" ''
#!${pkgs.stdenv.shell}
set -e -o pipefail
export PATH=/run/wrappers/bin/:${with pkgs; lib.makeBinPath [
coreutils
openssh
nix
gnutar
findutils
nettools
gzip
git
]}
MODE=$1
shift || true
ARGS=$@
[ "$MODE" == "" ] && MODE="switch"
${lib.concatMapStrings (hostname: let
hostAttrs = nixosHosts.${hostname};
nixosSystem = (import <nixpkgs/nixos/lib/eval-config.nix> {
modules = [
"${toString ../configuration}/hosts/${hostname}/configuration.nix"
];
system = if hostAttrs ? system then hostAttrs.system else "x86_64-linux";
}).config.system.build.toplevel;
in ''
(
echo "deploying ${hostname}..."
nix copy --no-check-sigs -s --to ssh://${hostAttrs.ssh.host} ${nixosSystem}
ssh $NIX_SSHOPTS ${hostAttrs.ssh.host} "sudo nix-env -p /nix/var/nix/profiles/system -i ${nixosSystem}"
ssh $NIX_SSHOPTS ${hostAttrs.ssh.host} "sudo /nix/var/nix/profiles/system/bin/switch-to-configuration $MODE $ARGS"
) &
PID_LIST+=" $!"
'') hostnames}
echo "deploys started, waiting for them to finish..."
trap "kill $PID_LIST" SIGINT
wait $PID_LIST
'';
in {
deploy = (lib.mapAttrs (hostname: hostAttrs: mkDeploy [ hostname ]) nixosHosts)
// (lib.mapAttrs (group: hosts: mkDeploy hosts) hostsInAllGroups)
// { all = mkDeploy (lib.attrNames nixosHosts); };
}

View file

@ -1,21 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.hardware.decklink;
kernelPackages = config.boot.kernelPackages;
in
{
options.hardware.decklink.enable = mkEnableOption "Enable hardware support for the Blackmagic Design Decklink audio/video interfaces.";
config = mkIf cfg.enable {
boot.kernelModules = [ "blackmagic" "blackmagic-io" "snd_blackmagic-io" ];
boot.extraModulePackages = [ kernelPackages.decklink ];
systemd.services."DecklinkVideoHelper" = {
after = [ "syslog.target" "local-fs.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.blackmagicDesktopVideo}/bin/DesktopVideoHelper -n";
};
};
}

View file

@ -1,16 +1,13 @@
{ ... }:
let
sources = import ../nix/sources.nix;
immaeNix = fetchGit {
url = "https://git.immae.eu/perso/Immae/Config/Nix.git";
rev = "7ad4966f41db0669a77c7a6ee7f87f0d4e586b0c";
};
in {
imports = [
./nftnat
./decklink.nix
./websites.nix
];
# disabled since vaultwarden defines a dummy bitwarden_rs option that
# shows a deprication warning, which conflicts with this module
disabledModules = [
"services/security/bitwarden_rs/default.nix"
"${immaeNix}/modules/webapps/peertube.nix"
./funkwhale
];
}

View file

@ -0,0 +1,563 @@
{config, lib, pkgs, ...}:
with lib;
let
django-cacheops = with final; with pkgs.python3.pkgs; ( buildPythonPackage rec {
pname = "django-cacheops";
version = "5.1";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-1YUc178whzhKH87PqN3bj1UDDu39b98SciW3W8oPmd0=";
};
propagatedBuildInputs = [ django redis six funcy ];
doCheck = false;
});
pythonEnv = (pkgs.python3.override {
packageOverrides = self: super: rec {
django = self.django_2_2;
};
}).withPackages (ps: [
django-cacheops
ps.aioredis
ps.aiohttp
ps.arrow
ps.autobahn
ps.av
ps.bleach
ps.boto3
ps.celery
ps.channels
ps.channels-redis
ps.click
ps.django
ps.django-allauth
ps.django-auth-ldap
ps.django-oauth-toolkit
ps.django-cleanup
ps.django-cors-headers
ps.django-dynamic-preferences
ps.django_environ
ps.django-filter
ps.django_redis
ps.django-rest-auth
ps.djangorestframework
ps.djangorestframework-jwt
ps.django-storages
ps.django_taggit
ps.django-versatileimagefield
ps.feedparser
ps.gunicorn
ps.kombu
ps.ldap
ps.markdown
ps.mutagen
ps.musicbrainzngs
ps.pillow
ps.pendulum
ps.persisting-theory
ps.psycopg2
ps.pyacoustid
ps.pydub
ps.PyLD
ps.pymemoize
ps.pyopenssl
ps.python_magic
ps.pytz
ps.redis
ps.requests
ps.requests-http-signature
ps.service-identity
ps.unidecode
ps.unicode-slugify
ps.uvicorn
ps.watchdog
]);
cfg = config.services.funkwhale;
databasePassword = if (cfg.database.passwordFile != null)
then builtins.readFile cfg.database.passwordFile
else cfg.database.password;
databaseUrl = if (cfg.database.createLocally && cfg.database.socket != null)
then "postgresql:///${cfg.database.name}?host=${cfg.database.socket}"
else "postgresql://${cfg.database.user}:${databasePassword}@${cfg.database.host}:${toString cfg.database.port}/${cfg.database.name}";
funkwhaleEnvironment = [
"FUNKWHALE_URL=${cfg.hostname}"
"FUNKWHALE_HOSTNAME=${cfg.hostname}"
"FUNKWHALE_PROTOCOL=${cfg.protocol}"
"EMAIL_CONFIG=${cfg.emailConfig}"
"DEFAULT_FROM_EMAIL=${cfg.defaultFromEmail}"
"REVERSE_PROXY_TYPE=nginx"
"DATABASE_URL=${databaseUrl}"
"CACHE_URL=redis://localhost:${toString config.services.redis.port}/0"
"MEDIA_ROOT=${cfg.api.mediaRoot}"
"STATIC_ROOT=${cfg.api.staticRoot}"
"DJANGO_SECRET_KEY=${cfg.api.djangoSecretKey}"
"RAVEN_ENABLED=${boolToString cfg.enableRaven}"
"RAVEN_DSN=${cfg.ravenDsn}"
"MUSIC_DIRECTORY_PATH=${cfg.musicDirectoryPath}"
"MUSIC_DIRECTORY_SERVE_PATH=${cfg.musicDirectoryPath}"
"FUNKWHALE_FRONTEND_PATH=${cfg.dataDir}/front/dist"
];
funkwhaleEnvFileData = builtins.concatStringsSep "\n" funkwhaleEnvironment;
funkwhaleEnvScriptData = builtins.concatStringsSep " " funkwhaleEnvironment;
funkwhaleEnvFile = pkgs.writeText "funkwhale.env" funkwhaleEnvFileData;
funkwhaleEnv = {
ENV_FILE = "${funkwhaleEnvFile}";
};
in
{
options = {
services.funkwhale = {
enable = mkEnableOption "funkwhale";
user = mkOption {
type = types.str;
default = "funkwhale";
description = "User under which Funkwhale is ran.";
};
group = mkOption {
type = types.str;
default = "funkwhale";
description = "Group under which Funkwhale is ran.";
};
database = {
host = mkOption {
type = types.str;
default = "localhost";
description = "Database host address.";
};
port = mkOption {
type = types.int;
default = 5432;
defaultText = "5432";
description = "Database host port.";
};
name = mkOption {
type = types.str;
default = "funkwhale";
description = "Database name.";
};
user = mkOption {
type = types.str;
default = "funkwhale";
description = "Database user.";
};
password = mkOption {
type = types.str;
default = "";
description = ''
The password corresponding to <option>database.user</option>.
Warning: this is stored in cleartext in the Nix store!
Use <option>database.passwordFile</option> instead.
'';
};
passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/run/keys/funkwhale-dbpassword";
description = ''
A file containing the password corresponding to
<option>database.user</option>.
'';
};
socket = mkOption {
type = types.nullOr types.path;
default = "/run/postgresql";
defaultText = "/run/postgresql";
example = "/run/postgresql";
description = "Path to the unix socket file to use for authentication for local connections.";
};
createLocally = mkOption {
type = types.bool;
default = true;
description = "Create the database and database user locally.";
};
};
dataDir = mkOption {
type = types.str;
default = "/srv/funkwhale";
description = ''
Where to keep the funkwhale data.
'';
};
apiIp = mkOption {
type = types.str;
default = "127.0.0.1";
description = ''
Funkwhale API IP.
'';
};
webWorkers = mkOption {
type = types.int;
default = 1;
description = ''
Funkwhale number of web workers.
'';
};
apiPort = mkOption {
type = types.port;
default = 5000;
description = ''
Funkwhale API Port.
'';
};
hostname = mkOption {
type = types.str;
description = ''
The definitive, public domain you will use for your instance.
'';
example = "funkwhale.yourdomain.net";
};
protocol = mkOption {
type = types.enum [ "http" "https" ];
default = "https";
description = ''
Web server protocol.
'';
};
emailConfig = mkOption {
type = types.str;
default = "consolemail://";
description = ''
Configure email sending. By default, it outputs emails to console instead of sending them. See https://docs.funkwhale.audio/configuration.html#email-config for details.
'';
example = "smtp+ssl://user@:password@youremail.host:465";
};
defaultFromEmail = mkOption {
type = types.str;
description = ''
The email address to use to send system emails.
'';
example = "funkwhale@yourdomain.net";
};
api = {
mediaRoot = mkOption {
type = types.str;
default = "/srv/funkwhale/media";
description = ''
Where media files (such as album covers or audio tracks) should be stored on your system ? Ensure this directory actually exists.
'';
};
staticRoot = mkOption {
type = types.str;
default = "/srv/funkwhale/static";
description = ''
Where static files (such as API css or icons) should be compiled on your system ? Ensure this directory actually exists.
'';
};
djangoSecretKey = mkOption {
type = types.str;
description = ''
Django secret key. Generate one using `openssl rand -base64 45` for example.
'';
example = "6VhAWVKlqu/dJSdz6TVgEJn/cbbAidwsFvg9ddOwuPRssEs0OtzAhJxLcLVC";
};
};
musicDirectoryPath = mkOption {
type = types.str;
default = "/srv/funkwhale/music";
description = ''
In-place import settings.
'';
};
enableRaven = mkOption {
type = types.bool;
default = false;
description = ''
Sentry/Raven error reporting (server side).
Enable Raven if you want to help improve funkwhale by
automatically sending error reports to the funkwhale developers Sentry instance.
This will help them detect and correct bugs.
'';
};
ravenDsn = mkOption {
type = types.str;
default = "https://44332e9fdd3d42879c7d35bf8562c6a4:0062dc16a22b41679cd5765e5342f716@sentry.eliotberriot.com/5";
description = ''
Sentry/Raven DSN.
The default is the Funkwhale developers instance DSN.
'';
};
};
};
config = mkIf cfg.enable {
assertions = [
{ assertion = cfg.database.passwordFile != null || cfg.database.password != "" || cfg.database.socket != null;
message = "one of services.funkwhale.database.socket, services.funkwhale.database.passwordFile, or services.funkwhale.database.password must be set";
}
{ assertion = cfg.database.createLocally -> cfg.database.user == cfg.user;
message = "services.funkwhale.database.user must be set to ${cfg.user} if services.funkwhale.database.createLocally is set true";
}
{ assertion = cfg.database.createLocally -> cfg.database.socket != null;
message = "services.funkwhale.database.socket must be set if services.funkwhale.database.createLocally is set to true";
}
{ assertion = cfg.database.createLocally -> cfg.database.host == "localhost";
message = "services.funkwhale.database.host must be set to localhost if services.funkwhale.database.createLocally is set to true";
}
];
users.users.funkwhale = mkIf (cfg.user == "funkwhale")
{ name = "funkwhale";
group = cfg.group;
};
users.groups.funkwhale = mkIf (cfg.group == "funkwhale") { name = "funkwhale"; };
services.postgresql = mkIf cfg.database.createLocally {
enable = true;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
{ name = cfg.database.user;
ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
}
];
};
services.redis.enable = true;
services.nginx = {
enable = true;
appendHttpConfig = ''
upstream funkwhale-api {
server ${cfg.apiIp}:${toString cfg.apiPort};
}
'';
virtualHosts =
let proxyConfig = ''
# global proxy conf
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Port $server_port;
proxy_redirect off;
# websocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
'';
withSSL = cfg.protocol == "https";
in {
"${cfg.hostname}" = {
enableACME = withSSL;
forceSSL = withSSL;
root = "${pkgs.funkwhale}/front";
# gzip config is nixos nginx recommendedGzipSettings with gzip_types from funkwhale doc (https://docs.funkwhale.audio/changelog.html#id5)
extraConfig = ''
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; object-src 'none'; media-src 'self' data:";
add_header Referrer-Policy "strict-origin-when-cross-origin";
gzip on;
gzip_disable "msie6";
gzip_proxied any;
gzip_comp_level 5;
gzip_types
application/javascript
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
font/opentype
image/bmp
image/svg+xml
image/x-icon
text/cache-manifest
text/css
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy;
gzip_vary on;
'';
locations = {
"/" = {
extraConfig = proxyConfig;
proxyPass = "http://funkwhale-api/";
};
"/front/" = {
alias = "${pkgs.funkwhale}/front/";
extraConfig = ''
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; object-src 'none'; media-src 'self' data:";
add_header Referrer-Policy "strict-origin-when-cross-origin";
expires 30d;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
'';
};
"= /front/embed.html" = {
alias = "${pkgs.funkwhale}/front/embed.html";
extraConfig = ''
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; object-src 'none'; media-src 'self' data:";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header X-Frame-Options "ALLOW";
expires 30d;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
'';
};
"/federation/" = {
extraConfig = proxyConfig;
proxyPass = "http://funkwhale-api/federation/";
};
"/rest/" = {
extraConfig = proxyConfig;
proxyPass = "http://funkwhale-api/api/subsonic/rest/";
};
"/.well-known/" = {
extraConfig = proxyConfig;
proxyPass = "http://funkwhale-api/.well-known/";
};
"/media/".alias = "${cfg.api.mediaRoot}/";
"/_protected/media/" = {
extraConfig = ''
internal;
'';
alias = "${cfg.api.mediaRoot}/";
};
"/_protected/music/" = {
extraConfig = ''
internal;
'';
alias = "${cfg.musicDirectoryPath}/";
};
"/staticfiles/".alias = "${cfg.api.staticRoot}/";
};
};
};
};
systemd.tmpfiles.rules = [
"d ${cfg.dataDir} 0755 ${cfg.user} ${cfg.group} - -"
"d ${cfg.api.mediaRoot} 0755 ${cfg.user} ${cfg.group} - -"
"d ${cfg.api.staticRoot} 0755 ${cfg.user} ${cfg.group} - -"
"d ${cfg.musicDirectoryPath} 0755 ${cfg.user} ${cfg.group} - -"
];
systemd.targets.funkwhale = {
description = "Funkwhale";
wants = ["funkwhale-server.service" "funkwhale-worker.service" "funkwhale-beat.service"];
};
systemd.services =
let serviceConfig = {
User = "${cfg.user}";
WorkingDirectory = "${pkgs.funkwhale}";
EnvironmentFile = "${funkwhaleEnvFile}";
};
in {
funkwhale-psql-init = mkIf cfg.database.createLocally {
description = "Funkwhale database preparation";
after = [ "redis.service" "postgresql.service" ];
wantedBy = [ "funkwhale-init.service" ];
before = [ "funkwhale-init.service" ];
serviceConfig = {
User = "postgres";
ExecStart = '' ${config.services.postgresql.package}/bin/psql -d ${cfg.database.name} -c 'CREATE EXTENSION IF NOT EXISTS "unaccent";CREATE EXTENSION IF NOT EXISTS "citext";' '';
};
};
funkwhale-init = {
description = "Funkwhale initialization";
wantedBy = [ "funkwhale-server.service" "funkwhale-worker.service" "funkwhale-beat.service" ];
before = [ "funkwhale-server.service" "funkwhale-worker.service" "funkwhale-beat.service" ];
environment = funkwhaleEnv;
serviceConfig = {
User = "${cfg.user}";
Group = "${cfg.group}";
};
script = ''
${pythonEnv}/bin/python ${pkgs.funkwhale}/manage.py migrate
${pythonEnv}/bin/python ${pkgs.funkwhale}/manage.py collectstatic --no-input
if ! test -e ${cfg.dataDir}/createSuperUser.sh; then
echo "#!/bin/sh
${funkwhaleEnvScriptData} ${pythonEnv}/bin/python ${pkgs.funkwhale}/manage.py createsuperuser" > ${cfg.dataDir}/createSuperUser.sh
chmod u+x ${cfg.dataDir}/createSuperUser.sh
chown -R ${cfg.user}.${cfg.group} ${cfg.dataDir}
fi
if ! test -e ${cfg.dataDir}/config; then
mkdir -p ${cfg.dataDir}/config
ln -s ${funkwhaleEnvFile} ${cfg.dataDir}/config/.env
ln -s ${funkwhaleEnvFile} ${cfg.dataDir}/.env
fi
'';
};
funkwhale-server = {
description = "Funkwhale application server";
partOf = [ "funkwhale.target" ];
serviceConfig = serviceConfig // {
ExecStart = "${pythonEnv}/bin/gunicorn config.asgi:application -w ${toString cfg.webWorkers} -k uvicorn.workers.UvicornWorker -b ${cfg.apiIp}:${toString cfg.apiPort}";
};
environment = funkwhaleEnv;
wantedBy = [ "multi-user.target" ];
};
funkwhale-worker = {
description = "Funkwhale celery worker";
partOf = [ "funkwhale.target" ];
serviceConfig = serviceConfig // {
RuntimeDirectory = "funkwhaleworker";
ExecStart = "${pythonEnv}/bin/celery -A funkwhale_api.taskapp worker -l INFO";
};
environment = funkwhaleEnv;
wantedBy = [ "multi-user.target" ];
};
funkwhale-beat = {
description = "Funkwhale celery beat process";
partOf = [ "funkwhale.target" ];
serviceConfig = serviceConfig // {
RuntimeDirectory = "funkwhalebeat";
ExecStart = '' ${pythonEnv}/bin/celery -A funkwhale_api.taskapp beat -l INFO --schedule="/run/funkwhalebeat/celerybeat-schedule.db" --pidfile="/run/funkwhalebeat/celerybeat.pid" '';
};
environment = funkwhaleEnv;
wantedBy = [ "multi-user.target" ];
};
};
};
meta = {
maintainers = with lib.maintainers; [ mmai ];
};
}

View file

@ -1,251 +0,0 @@
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.services.mattermost-patched;
database = "postgres://${cfg.localDatabaseUser}:${cfg.localDatabasePassword}@localhost:5432/${cfg.localDatabaseName}?sslmode=disable&connect_timeout=10";
mattermostConf = foldl recursiveUpdate {}
[ { ServiceSettings.SiteURL = cfg.siteUrl;
ServiceSettings.ListenAddress = cfg.listenAddress;
TeamSettings.SiteName = cfg.siteName;
}
cfg.extraConfig
];
mattermostConfJSON = pkgs.writeText "mattermost-config-raw.json" (builtins.toJSON mattermostConf);
in
{
options = {
services.mattermost-patched = {
enable = mkEnableOption "Mattermost chat server";
statePath = mkOption {
type = types.str;
default = "/var/lib/mattermost";
description = "Mattermost working directory";
};
siteUrl = mkOption {
type = types.str;
example = "https://chat.example.com";
description = ''
URL this Mattermost instance is reachable under, without trailing slash.
'';
};
siteName = mkOption {
type = types.str;
default = "Mattermost";
description = "Name of this Mattermost site.";
};
listenAddress = mkOption {
type = types.str;
default = ":8065";
example = "[::1]:8065";
description = ''
Address and port this Mattermost instance listens to.
'';
};
mutableConfig = mkOption {
type = types.bool;
default = false;
description = ''
Whether the Mattermost config.json is writeable by Mattermost.
Most of the settings can be edited in the system console of
Mattermost if this option is enabled. A template config using
the options specified in services.mattermost will be generated
but won't be overwritten on changes or rebuilds.
If this option is disabled, changes in the system console won't
be possible (default). If an config.json is present, it will be
overwritten!
'';
};
extraConfig = mkOption {
type = types.attrs;
default = { };
description = ''
Addtional configuration options as Nix attribute set in config.json schema.
'';
};
secretConfig = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Path to a json file containing secret config values, which should
not be written into the Nix store. If it is not null (the default)
and mutableConfig is set to false, then the mattermost service will
join the file at this path into its config.
Note that this file cannot be used to overwrite values already
specified by the other options of this module.
'';
};
localDatabaseCreate = mkOption {
type = types.bool;
default = true;
description = ''
Create a local PostgreSQL database for Mattermost automatically.
'';
};
localDatabaseName = mkOption {
type = types.str;
default = "mattermost";
description = ''
Local Mattermost database name.
'';
};
localDatabaseUser = mkOption {
type = types.str;
default = "mattermost";
description = ''
Local Mattermost database username.
'';
};
localDatabasePassword = mkOption {
type = types.str;
default = "mmpgsecret";
description = ''
Password for local Mattermost database user.
'';
};
user = mkOption {
type = types.str;
default = "mattermost";
description = ''
User which runs the Mattermost service.
'';
};
group = mkOption {
type = types.str;
default = "mattermost";
description = ''
Group which runs the Mattermost service.
'';
};
matterircd = {
enable = mkEnableOption "Mattermost IRC bridge";
parameters = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "-mmserver chat.example.com" "-bind [::]:6667" ];
description = ''
Set commandline parameters to pass to matterircd. See
https://github.com/42wim/matterircd#usage for more information.
'';
};
};
};
};
config = mkMerge [
(mkIf cfg.enable {
users.users = optionalAttrs (cfg.user == "mattermost") {
mattermost = {
group = cfg.group;
uid = config.ids.uids.mattermost;
home = cfg.statePath;
};
};
users.groups = optionalAttrs (cfg.group == "mattermost") {
mattermost.gid = config.ids.gids.mattermost;
};
services.postgresql.enable = cfg.localDatabaseCreate;
# The systemd service will fail to execute the preStart hook
# if the WorkingDirectory does not exist
system.activationScripts.mattermost = ''
mkdir -p ${cfg.statePath}
'';
systemd.services.mattermost = {
description = "Mattermost chat service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "postgresql.service" ];
preStart = ''
mkdir -p ${cfg.statePath}/{data,config,logs}
ln -sf ${pkgs.mattermost}/{bin,fonts,i18n,templates,client} ${cfg.statePath}
'' + lib.optionalString (!cfg.mutableConfig) ''
rm -f ${cfg.statePath}/config/config.json
'' + (if cfg.secretConfig == null
then ''
cp ${mattermostConfJSON} ${cfg.statePath}/config/config.json
''
else ''
${pkgs.jq}/bin/jq -s ".[1] * .[0]" ${cfg.secretConfig} ${mattermostConfJSON} > ${cfg.statePath}/config/config.json
'')
+ ''
${pkgs.mattermost}/bin/mattermost config migrate ${cfg.statePath}/config/config.json ${database}
'' + lib.optionalString cfg.mutableConfig ''
if ! test -e "${cfg.statePath}/config/.initial-created"; then
rm -f ${cfg.statePath}/config/config.json
cp ${mattermostConfJSON} ${cfg.statePath}/config/config.json
touch ${cfg.statePath}/config/.initial-created
fi
'' + lib.optionalString cfg.localDatabaseCreate ''
if ! test -e "${cfg.statePath}/.db-created"; then
${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} \
${config.services.postgresql.package}/bin/psql postgres -c \
"CREATE ROLE ${cfg.localDatabaseUser} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '${cfg.localDatabasePassword}'"
${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} \
${config.services.postgresql.package}/bin/createdb \
--owner ${cfg.localDatabaseUser} ${cfg.localDatabaseName}
touch ${cfg.statePath}/.db-created
fi
'' + ''
chown ${cfg.user}:${cfg.group} -R ${cfg.statePath}
chmod u+rw,g+r,o-rwx -R ${cfg.statePath}
'';
serviceConfig = {
PermissionsStartOnly = true;
User = cfg.user;
Group = cfg.group;
ExecStart = "${pkgs.mattermost}/bin/mattermost" +
(if cfg.mutableConfig then " -c ${database}" else " -c ${cfg.statePath}/config/config.json");
WorkingDirectory = "${cfg.statePath}";
Restart = "always";
RestartSec = "10";
LimitNOFILE = "49152";
};
unitConfig.JoinsNamespaceOf = mkIf cfg.localDatabaseCreate "postgresql.service";
};
})
(mkIf cfg.matterircd.enable {
systemd.services.matterircd = {
description = "Mattermost IRC bridge service";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = "nobody";
Group = "nogroup";
ExecStart = "${pkgs.matterircd}/bin/matterircd ${concatStringsSep " " cfg.matterircd.parameters}";
WorkingDirectory = "/tmp";
PrivateTmp = true;
Restart = "always";
RestartSec = "5";
};
};
})
];
}

View file

@ -1,755 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.nextcloud-patched;
fpm = config.services.phpfpm.pools.nextcloud;
phpPackage =
let
base = pkgs.php74;
in
base.buildEnv {
extensions = { enabled, all }: with all;
enabled ++ [
apcu redis memcached imagick
];
extraConfig = phpOptionsStr;
};
toKeyValue = generators.toKeyValue {
mkKeyValue = generators.mkKeyValueDefault {} " = ";
};
phpOptions = {
upload_max_filesize = cfg.maxUploadSize;
post_max_size = cfg.maxUploadSize;
memory_limit = cfg.maxUploadSize;
} // cfg.phpOptions
// optionalAttrs cfg.caching.apcu {
"apc.enable_cli" = "1";
};
phpOptionsStr = toKeyValue phpOptions;
occ = pkgs.writeScriptBin "nextcloud-occ" ''
#! ${pkgs.runtimeShell}
cd ${cfg.package}
sudo=exec
if [[ "$USER" != nextcloud ]]; then
sudo='exec /run/wrappers/bin/sudo -u nextcloud --preserve-env=NEXTCLOUD_CONFIG_DIR --preserve-env=OC_PASS'
fi
export NEXTCLOUD_CONFIG_DIR="${cfg.home}/config"
$sudo \
${phpPackage}/bin/php \
occ $*
'';
inherit (config.system) stateVersion;
in {
imports = [
(mkRemovedOptionModule [ "services" "nextcloud-patched" "nginx" "enable" ] ''
The nextcloud module supports `nginx` as reverse-proxy by default and doesn't
support other reverse-proxies officially.
However it's possible to use an alternative reverse-proxy by
* disabling nginx
* setting `listen.owner` & `listen.group` in the phpfpm-pool to a different value
Further details about this can be found in the `Nextcloud`-section of the NixOS-manual
(which can be openend e.g. by running `nixos-help`).
'')
];
options.services.nextcloud-patched = {
enable = mkEnableOption "nextcloud";
hostName = mkOption {
type = types.str;
description = "FQDN for the nextcloud instance.";
};
home = mkOption {
type = types.str;
default = "/var/lib/nextcloud";
description = "Storage path of nextcloud.";
};
logLevel = mkOption {
type = types.ints.between 0 4;
default = 2;
description = "Log level value between 0 (DEBUG) and 4 (FATAL).";
};
https = mkOption {
type = types.bool;
default = false;
description = "Use https for generated links.";
};
package = mkOption {
type = types.package;
description = "Which package to use for the Nextcloud instance.";
relatedPackages = [ "nextcloud18" "nextcloud19" "nextcloud20" "nextcloud21" ];
};
maxUploadSize = mkOption {
default = "512M";
type = types.str;
description = ''
Defines the upload limit for files. This changes the relevant options
in php.ini and nginx if enabled.
'';
};
skeletonDirectory = mkOption {
default = "";
type = types.str;
description = ''
The directory where the skeleton files are located. These files will be
copied to the data directory of new users. Leave empty to not copy any
skeleton files.
'';
};
webfinger = mkOption {
type = types.bool;
default = false;
description = ''
Enable this option if you plan on using the webfinger plugin.
The appropriate nginx rewrite rules will be added to your configuration.
'';
};
phpOptions = mkOption {
type = types.attrsOf types.str;
default = {
short_open_tag = "Off";
expose_php = "Off";
error_reporting = "E_ALL & ~E_DEPRECATED & ~E_STRICT";
display_errors = "stderr";
"opcache.enable_cli" = "1";
"opcache.interned_strings_buffer" = "8";
"opcache.max_accelerated_files" = "10000";
"opcache.memory_consumption" = "128";
"opcache.revalidate_freq" = "1";
"opcache.fast_shutdown" = "1";
"openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt";
catch_workers_output = "yes";
};
description = ''
Options for PHP's php.ini file for nextcloud.
'';
};
poolSettings = mkOption {
type = with types; attrsOf (oneOf [ str int bool ]);
default = {
"pm" = "dynamic";
"pm.max_children" = "32";
"pm.start_servers" = "2";
"pm.min_spare_servers" = "2";
"pm.max_spare_servers" = "4";
"pm.max_requests" = "500";
};
description = ''
Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
'';
};
poolConfig = mkOption {
type = types.nullOr types.lines;
default = null;
description = ''
Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives.
'';
};
config = {
dbtype = mkOption {
type = types.enum [ "sqlite" "pgsql" "mysql" ];
default = "sqlite";
description = "Database type.";
};
dbname = mkOption {
type = types.nullOr types.str;
default = "nextcloud";
description = "Database name.";
};
dbuser = mkOption {
type = types.nullOr types.str;
default = "nextcloud";
description = "Database user.";
};
dbpass = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Database password. Use <literal>dbpassFile</literal> to avoid this
being world-readable in the <literal>/nix/store</literal>.
'';
};
dbpassFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The full path to a file that contains the database password.
'';
};
dbhost = mkOption {
type = types.nullOr types.str;
default = "localhost";
description = ''
Database host.
Note: for using Unix authentication with PostgreSQL, this should be
set to <literal>/run/postgresql</literal>.
'';
};
dbport = mkOption {
type = with types; nullOr (either int str);
default = null;
description = "Database port.";
};
dbtableprefix = mkOption {
type = types.nullOr types.str;
default = null;
description = "Table prefix in Nextcloud database.";
};
adminuser = mkOption {
type = types.str;
default = "root";
description = "Admin username.";
};
adminpass = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Admin password. Use <literal>adminpassFile</literal> to avoid this
being world-readable in the <literal>/nix/store</literal>.
'';
};
adminpassFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The full path to a file that contains the admin's password. Must be
readable by user <literal>nextcloud</literal>.
'';
};
extraTrustedDomains = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Trusted domains, from which the nextcloud installation will be
acessible. You don't need to add
<literal>services.nextcloud.hostname</literal> here.
'';
};
trustedProxies = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Trusted proxies, to provide if the nextcloud installation is being
proxied to secure against e.g. spoofing.
'';
};
overwriteProtocol = mkOption {
type = types.nullOr (types.enum [ "http" "https" ]);
default = null;
example = "https";
description = ''
Force Nextcloud to always use HTTPS i.e. for link generation. Nextcloud
uses the currently used protocol by default, but when behind a reverse-proxy,
it may use <literal>http</literal> for everything although Nextcloud
may be served via HTTPS.
'';
};
defaultPhoneRegion = mkOption {
default = null;
type = types.nullOr types.str;
example = "DE";
description = ''
<warning>
<para>This option exists since Nextcloud 21! If older versions are used,
this will throw an eval-error!</para>
</warning>
<link xlink:href="https://www.iso.org/iso-3166-country-codes.html">ISO 3611-1</link>
country codes for automatic phone-number detection without a country code.
With e.g. <literal>DE</literal> set, the <literal>+49</literal> can be omitted for
phone-numbers.
'';
};
defaultapp = mkOption {
default = null;
type = types.nullOr types.str;
example = "files";
description = ''
This options sets the app that opens as default.
'';
};
};
caching = {
apcu = mkOption {
type = types.bool;
default = true;
description = ''
Whether to load the APCu module into PHP.
'';
};
redis = mkOption {
type = types.bool;
default = false;
description = ''
Whether to load the Redis module into PHP.
You still need to enable Redis in your config.php.
See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html
'';
};
memcached = mkOption {
type = types.bool;
default = false;
description = ''
Whether to load the Memcached module into PHP.
You still need to enable Memcached in your config.php.
See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html
'';
};
};
autoUpdateApps = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Run regular auto update of all apps installed from the nextcloud app store.
'';
};
startAt = mkOption {
type = with types; either str (listOf str);
default = "05:00:00";
example = "Sun 14:00:00";
description = ''
When to run the update. See `systemd.services.&lt;name&gt;.startAt`.
'';
};
};
occ = mkOption {
type = types.package;
default = occ;
internal = true;
description = ''
The nextcloud-occ program preconfigured to target this Nextcloud instance.
'';
};
extraOptions = mkOption {
type = types.attrs;
default = "";
description = ''
Extra options which should be appended to nextcloud's config.php file
'';
};
secretFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Secret options which will be appended to nextcloud's config.php file (written in JSON, in the same
form as the `extraOptions` option).
'';
};
};
config = mkIf cfg.enable (mkMerge [
{ assertions = let acfg = cfg.config; in [
{ assertion = !(acfg.dbpass != null && acfg.dbpassFile != null);
message = "Please specify no more than one of dbpass or dbpassFile";
}
{ assertion = ((acfg.adminpass != null || acfg.adminpassFile != null)
&& !(acfg.adminpass != null && acfg.adminpassFile != null));
message = "Please specify exactly one of adminpass or adminpassFile";
}
{ assertion = versionOlder cfg.package.version "21" -> cfg.config.defaultPhoneRegion == null;
message = "The `defaultPhoneRegion'-setting is only supported for Nextcloud >=21!";
}
];
warnings = []
++ (optional (cfg.poolConfig != null) ''
Using config.services.nextcloud.poolConfig is deprecated and will become unsupported in a future release.
Please migrate your configuration to config.services.nextcloud.poolSettings.
'')
++ (optional (versionOlder cfg.package.version "18") ''
A legacy Nextcloud install (from before NixOS 20.03) may be installed.
You're currently deploying an older version of Nextcloud. This may be needed
since Nextcloud doesn't allow major version upgrades that skip multiple
versions (i.e. an upgrade from 16 is possible to 17, but not 16 to 18).
It is assumed that Nextcloud will be upgraded from version 16 to 17.
* If this is a fresh install, there will be no upgrade to do now.
* If this server already had Nextcloud installed, first deploy this to your
server, and wait until the upgrade to 17 is finished.
Then, set `services.nextcloud.package` to `pkgs.nextcloud18` to upgrade to
Nextcloud version 18. Please note that Nextcloud 19 is already out and it's
recommended to upgrade to nextcloud19 after that.
'')
++ (optional (versionOlder cfg.package.version "19") ''
A legacy Nextcloud install (from before NixOS 20.09) may be installed.
If/After nextcloud18 is installed successfully, you can safely upgrade to
nextcloud19. If not, please upgrade to nextcloud18 first since Nextcloud doesn't
support upgrades that skip multiple versions (i.e. an upgrade from 17 to 19 isn't
possible, but an upgrade from 18 to 19).
'')
++ (optional (versionOlder cfg.package.version "21") ''
The latest Nextcloud release is v21 which can be installed by setting
`services.nextcloud.package` to `pkgs.nextcloud21`. Please note that if you're
on `pkgs.nextcloud19`, you'll have to install `pkgs.nextcloud20` first.
'');
services.nextcloud-patched.package = with pkgs;
mkDefault (
if pkgs ? nextcloud
then throw ''
The `pkgs.nextcloud`-attribute has been removed. If it's supposed to be the default
nextcloud defined in an overlay, please set `services.nextcloud.package` to
`pkgs.nextcloud`.
''
else if versionOlder stateVersion "20.03" then nextcloud17
else if versionOlder stateVersion "20.09" then nextcloud18
else nextcloud19
);
}
{ systemd.timers.nextcloud-cron = {
wantedBy = [ "timers.target" ];
timerConfig.OnBootSec = "5m";
timerConfig.OnUnitActiveSec = "15m";
timerConfig.Unit = "nextcloud-cron.service";
};
systemd.services = {
# When upgrading the Nextcloud package, Nextcloud can report errors such as
# "The files of the app [all apps in /var/lib/nextcloud/apps] were not replaced correctly"
# Restarting phpfpm on Nextcloud package update fixes these issues (but this is a workaround).
phpfpm-nextcloud.restartTriggers = [ cfg.package ];
nextcloud-setup = let
c = cfg.config;
writePhpArrary = a: "[${concatMapStringsSep "," (val: ''"${toString val}"'') a}]";
overrideConfig = pkgs.writeText "nextcloud-config.php" ''
<?php
${optionalString (c.dbpassFile != null) ''
function nix_read_pwd() {
$file = "${c.dbpassFile}";
if (!file_exists($file)) {
throw new \RuntimeException(sprintf(
"Cannot start Nextcloud, dbpass file %s set by NixOS doesn't exist!",
$file
));
}
return trim(file_get_contents($file));
}
''}
${optionalString (cfg.secretFile != null) ''
function nix_read_secrets() {
$file = "${cfg.secretFile}";
if (!file_exists($file)) {
throw new \RuntimeException(sprintf(
"Cannot start Nextcloud, secrets file %s set by NixOS doesn't exist!",
$file
));
}
return json_decode(file_get_contents($file));
}
''}
$CONFIG = [
'apps_paths' => [
[ 'path' => '${cfg.home}/apps', 'url' => '/apps', 'writable' => false ],
[ 'path' => '${cfg.home}/store-apps', 'url' => '/store-apps', 'writable' => true ],
],
'datadirectory' => '${cfg.home}/data',
'skeletondirectory' => '${cfg.skeletonDirectory}',
${optionalString cfg.caching.apcu "'memcache.local' => '\\OC\\Memcache\\APCu',"}
'log_type' => 'syslog',
'log_level' => '${builtins.toString cfg.logLevel}',
${optionalString (c.defaultapp != null) "'defaultapp' => '${c.defaultapp}',"}
${optionalString (c.overwriteProtocol != null) "'overwriteprotocol' => '${c.overwriteProtocol}',"}
${optionalString (c.dbname != null) "'dbname' => '${c.dbname}',"}
${optionalString (c.dbhost != null) "'dbhost' => '${c.dbhost}',"}
${optionalString (c.dbport != null) "'dbport' => '${toString c.dbport}',"}
${optionalString (c.dbuser != null) "'dbuser' => '${c.dbuser}',"}
${optionalString (c.dbtableprefix != null) "'dbtableprefix' => '${toString c.dbtableprefix}',"}
${optionalString (c.dbpass != null) "'dbpassword' => '${c.dbpass}',"}
${optionalString (c.dbpassFile != null) "'dbpassword' => nix_read_pwd(),"}
'dbtype' => '${c.dbtype}',
'trusted_domains' => ${writePhpArrary ([ cfg.hostName ] ++ c.extraTrustedDomains)},
'trusted_proxies' => ${writePhpArrary (c.trustedProxies)},
${optionalString (c.defaultPhoneRegion != null) "'default_phone_region' => '${c.defaultPhoneRegion}',"}
];
$EXTRACONFIG = json_decode('${builtins.toJSON cfg.extraOptions}', true);
array_push($CONFIG, $EXTRACONFIG);
${optionalString (cfg.secretFile != null) "array_push($CONFIG, nix_read_secrets());"}
'';
occInstallCmd = let
dbpass = if c.dbpassFile != null
then ''"$(<"${toString c.dbpassFile}")"''
else if c.dbpass != null
then ''"${toString c.dbpass}"''
else ''""'';
adminpass = if c.adminpassFile != null
then ''"$(<"${toString c.adminpassFile}")"''
else ''"${toString c.adminpass}"'';
installFlags = concatStringsSep " \\\n "
(mapAttrsToList (k: v: "${k} ${toString v}") {
"--database" = ''"${c.dbtype}"'';
# The following attributes are optional depending on the type of
# database. Those that evaluate to null on the left hand side
# will be omitted.
${if c.dbname != null then "--database-name" else null} = ''"${c.dbname}"'';
${if c.dbhost != null then "--database-host" else null} = ''"${c.dbhost}"'';
${if c.dbport != null then "--database-port" else null} = ''"${toString c.dbport}"'';
${if c.dbuser != null then "--database-user" else null} = ''"${c.dbuser}"'';
"--database-pass" = dbpass;
${if c.dbtableprefix != null
then "--database-table-prefix" else null} = ''"${toString c.dbtableprefix}"'';
"--admin-user" = ''"${c.adminuser}"'';
"--admin-pass" = adminpass;
"--data-dir" = ''"${cfg.home}/data"'';
});
in ''
${occ}/bin/nextcloud-occ maintenance:install \
${installFlags}
'';
occSetTrustedDomainsCmd = concatStringsSep "\n" (imap0
(i: v: ''
${occ}/bin/nextcloud-occ config:system:set trusted_domains \
${toString i} --value="${toString v}"
'') ([ cfg.hostName ] ++ cfg.config.extraTrustedDomains));
in {
wantedBy = [ "multi-user.target" ];
before = [ "phpfpm-nextcloud.service" ];
path = [ occ ];
script = ''
chmod og+x ${cfg.home}
${optionalString (c.dbpassFile != null) ''
if [ ! -r "${c.dbpassFile}" ]; then
echo "dbpassFile ${c.dbpassFile} is not readable by nextcloud:nextcloud! Aborting..."
exit 1
fi
if [ -z "$(<${c.dbpassFile})" ]; then
echo "dbpassFile ${c.dbpassFile} is empty!"
exit 1
fi
''}
${optionalString (c.adminpassFile != null) ''
if [ ! -r "${c.adminpassFile}" ]; then
echo "adminpassFile ${c.adminpassFile} is not readable by nextcloud:nextcloud! Aborting..."
exit 1
fi
if [ -z "$(<${c.adminpassFile})" ]; then
echo "adminpassFile ${c.adminpassFile} is empty!"
exit 1
fi
''}
ln -sf ${cfg.package}/apps ${cfg.home}/
# create nextcloud directories.
# if the directories exist already with wrong permissions, we fix that
for dir in ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps; do
if [ ! -e $dir ]; then
install -o nextcloud -g nextcloud -d $dir
elif [ $(stat -c "%G" $dir) != "nextcloud" ]; then
chgrp -R nextcloud $dir
fi
done
ln -sf ${overrideConfig} ${cfg.home}/config/override.config.php
# Do not install if already installed
if [[ ! -e ${cfg.home}/config/config.php ]]; then
${occInstallCmd}
fi
${occ}/bin/nextcloud-occ upgrade
${occ}/bin/nextcloud-occ config:system:delete trusted_domains
${occSetTrustedDomainsCmd}
'';
serviceConfig.Type = "oneshot";
serviceConfig.User = "nextcloud";
};
nextcloud-cron = {
environment.NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config";
serviceConfig.Type = "oneshot";
serviceConfig.User = "nextcloud";
serviceConfig.ExecStart = "${phpPackage}/bin/php -f ${cfg.package}/cron.php";
};
nextcloud-update-plugins = mkIf cfg.autoUpdateApps.enable {
serviceConfig.Type = "oneshot";
serviceConfig.ExecStart = "${occ}/bin/nextcloud-occ app:update --all";
serviceConfig.User = "nextcloud";
startAt = cfg.autoUpdateApps.startAt;
};
};
services.phpfpm = {
pools.nextcloud = {
user = "nextcloud";
group = "nextcloud";
phpOptions = phpOptionsStr;
phpPackage = phpPackage;
phpEnv = {
NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config";
PATH = "/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin";
};
settings = mapAttrs (name: mkDefault) {
"listen.owner" = config.services.nginx.user;
"listen.group" = config.services.nginx.group;
} // cfg.poolSettings;
extraConfig = cfg.poolConfig;
};
};
users.users.nextcloud = {
home = "${cfg.home}";
group = "nextcloud";
createHome = true;
isSystemUser = true;
};
users.groups.nextcloud.members = [ "nextcloud" config.services.nginx.user ];
environment.systemPackages = [ occ ];
services.nginx.enable = mkDefault true;
services.nginx.virtualHosts.${cfg.hostName} = let
major = toInt (versions.major cfg.package.version);
in {
root = cfg.package;
locations = {
"= /robots.txt" = {
priority = 100;
extraConfig = ''
allow all;
log_not_found off;
access_log off;
'';
};
"= /" = {
priority = 100;
extraConfig = ''
if ( $http_user_agent ~ ^DavClnt ) {
return 302 /remote.php/webdav/$is_args$args;
}
'';
};
"/" = {
priority = 900;
extraConfig = "rewrite ^ /index.php;";
};
"~ ^/store-apps" = {
priority = 201;
extraConfig = "root ${cfg.home};";
};
"^~ /.well-known" = {
priority = 210;
extraConfig = ''
absolute_redirect off;
location = /.well-known/carddav {
return 301 /remote.php/dav;
}
location = /.well-known/caldav {
return 301 /remote.php/dav;
}
location ~ ^/\.well-known/(?!acme-challenge|pki-validation) {
return 301 /index.php$request_uri;
}
try_files $uri $uri/ =404;
'';
};
"~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)".extraConfig = ''
return 404;
'';
"~ ^/(?:\\.(?!well-known)|autotest|occ|issue|indie|db_|console)".extraConfig = ''
return 404;
'';
"~ ^\\/(?:index|remote|public|cron|core\\/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|oc[ms]-provider\\/.+|.+\\/richdocumentscode\\/proxy)\\.php(?:$|\\/)" = {
priority = 500;
extraConfig = ''
include ${config.services.nginx.package}/conf/fastcgi.conf;
fastcgi_split_path_info ^(.+?\.php)(\\/.*)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS ${if cfg.https then "on" else "off"};
fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true;
fastcgi_pass unix:${fpm.socket};
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_read_timeout 120s;
'';
};
"~ \\.(?:css|js|woff2?|svg|gif|map)$".extraConfig = ''
try_files $uri /index.php$request_uri;
expires 6M;
access_log off;
'';
"~ ^\\/(?:updater|ocs-provider|ocm-provider)(?:$|\\/)".extraConfig = ''
try_files $uri/ =404;
index index.php;
'';
"~ \\.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$".extraConfig = ''
try_files $uri /index.php$request_uri;
access_log off;
'';
};
extraConfig = ''
index index.php index.html /index.php$request_uri;
expires 1m;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Frame-Options sameorigin;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
client_max_body_size ${cfg.maxUploadSize};
fastcgi_buffers 64 4K;
fastcgi_hide_header X-Powered-By;
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
${optionalString cfg.webfinger ''
rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
''}
'';
};
}
]);
}

View file

@ -1,60 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.hacc.nftables.nat;
nats = config.networking.nat;
in {
options.hacc.nftables.nat = {
enable = mkEnableOption "Wrap NAT into nftables.";
forwardPorts = mkOption {
type = with types; listOf (submodule {
options = {
ports = mkOption {
type = types.listOf (types.either types.int (types.strMatching "[[:digit:]]+-[[:digit:]]+"));
};
destination = mkOption {
type = types.str;
example = "10.0.0.1";
};
proto = mkOption {
type = types.str;
default = "tcp";
example = "udp";
};
};
});
default = [];
example = [{ ports = [ 8080 "9100-9200" ]; destination = "192.168.100.2"; proto = "udp"; }];
};
};
config = mkIf cfg.enable {
networking.nat.enable = mkOverride 99 false;
boot = {
kernelModules = [ "nf_nat_ftp" ];
kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = mkOverride 90 true;
"net.ipv4.conf.default.forwarding" = mkOverride 90 true;
};
};
networking.nftables = {
extraConfig = ''
table ip nat {
chain prerouting {
type nat hook prerouting priority -100
${concatMapStringsSep "\n" (rule: "iif ${nats.externalInterface} ${rule.proto} dport { ${concatStringsSep ", " (map (x: toString x) rule.ports)} } dnat ${rule.destination}") cfg.forwardPorts}
}
chain postrouting {
type nat hook postrouting priority 100
${concatMapStringsSep "\n" (iface: "iifname ${replaceStrings ["+"] ["*"] iface} oifname ${nats.externalInterface} masquerade") nats.internalInterfaces}
${concatMapStringsSep "\n" (addr: "ip saddr ${addr} oifname ${nats.externalInterface} masquerade") nats.internalIPs}
}
}
'';
};
};
}

View file

@ -1,53 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.hacc.websites;
in
{
options.hacc.websites = {
enable = mkOption {
type = types.bool;
default = false;
};
directory = mkOption {
type = types.path;
description = "all subdirectories of the given path are expected to contain a (static) website";
};
ignore = mkOption {
type = types.listOf types.str;
default = [];
description = "subdirectories that shouldn't be published";
};
};
config = mkIf cfg.enable {
services.nginx = {
enable = true;
virtualHosts =
let
subdirs =
let dirAttrs = filterAttrs
(n: v: v == "directory" || lists.elem n cfg.ignore)
(builtins.readDir cfg.directory);
in mapAttrsToList (n: v: n) dirAttrs;
mkWebsite = subdir: {
name = subdir;
# the nginx virtualhost config (for all sites) goes in here
value = {
enableACME = true;
forceSSL = true;
# naive string interpolation is safe here since nix will always immediately
# resolve relative paths to absolute paths; it's not lazy about that.
locations."/".root =
(pkgs.callPackage "${cfg.directory}/${subdir}" {}).outPath;
};
};
in listToAttrs (map mkWebsite subdirs);
};
};
}

View file

@ -1,102 +0,0 @@
{
"haccmap": {
"branch": "master",
"repo": "https://gitlab.infra4future.de/hacc/haccspace-rc3-map",
"rev": "9490ebf656ef379e51cb518ec0038e15d6aeaac6",
"type": "git"
},
"home-manager": {
"branch": "release-21.11",
"description": "Manage a user environment using Nix [maintainer=@rycee] ",
"homepage": "https://nix-community.github.io/home-manager/",
"owner": "nix-community",
"repo": "home-manager",
"rev": "d93d56ab8c1c6aa575854a79b9d2f69d491db7d0",
"sha256": "1fi27zabvqlyc2ggg7wr01j813gs46rswg1i897h9hqkbgqsjkny",
"type": "tarball",
"url": "https://github.com/nix-community/home-manager/archive/d93d56ab8c1c6aa575854a79b9d2f69d491db7d0.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"mattermost-server": {
"branch": "master",
"description": "Open source Slack-alternative in Golang and React - Mattermost",
"homepage": "https://mattermost.com",
"owner": "mattermost",
"repo": "mattermost-server",
"rev": "2ea14ef395fad8919b2f4137642a7f50b370ffba",
"sha256": "1k5zqnc4yqnad2cw1wpqk22mjra08jz9gf4v692kbrgx3x4d13kh",
"type": "tarball",
"url": "https://github.com/mattermost/mattermost-server/archive/refs/tags/v6.7.2.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/refs/tags/v<version>.tar.gz",
"version": "6.7.2"
},
"mattermost-webapp": {
"sha256": "0pwjfklk0q28yza2iny0im5pq3x430jskvq6rvfq7ycx251s98hx",
"type": "tarball",
"url": "https://releases.mattermost.com/6.7.2/mattermost-6.7.2-linux-amd64.tar.gz",
"url_template": "https://releases.mattermost.com/<version>/mattermost-<version>-linux-amd64.tar.gz",
"version": "6.7.2"
},
"niv": {
"branch": "master",
"description": "Easy dependency management for Nix projects",
"homepage": "https://github.com/nmattia/niv",
"owner": "nmattia",
"repo": "niv",
"rev": "82e5cd1ad3c387863f0545d7591512e76ab0fc41",
"sha256": "090l219mzc0gi33i3psgph6s2pwsc8qy4lyrqjdj4qzkvmaj65a7",
"type": "tarball",
"url": "https://github.com/nmattia/niv/archive/82e5cd1ad3c387863f0545d7591512e76ab0fc41.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nix-hexchen": {
"branch": "main",
"ref": "main",
"repo": "https://gitlab.com/hexchen/nixfiles",
"rev": "ef358992030e9a6fa975a24bf4d9aa133bc72424",
"sha256": "01hcdrpfc8g1bbc96h7gi04zmyxi9vd7392ncadwfkx5xfd2fp17",
"type": "tarball",
"url": "https://gitlab.com/hexchen/nixfiles/-/archive/ef358992030e9a6fa975a24bf4d9aa133bc72424.tar.gz",
"url_template": "<repo>/-/archive/<rev>.tar.gz"
},
"nixos-mailserver": {
"branch": "nixos-21.11",
"ref": "nixos-21.11",
"repo": "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver",
"rev": "6e3a7b2ea6f0d68b82027b988aa25d3423787303",
"sha256": "1i56llz037x416bw698v8j6arvv622qc0vsycd20lx3yx8n77n44",
"type": "tarball",
"url": "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/6e3a7b2ea6f0d68b82027b988aa25d3423787303.tar.gz",
"url_template": "<repo>/-/archive/<rev>.tar.gz"
},
"nixpkgs": {
"branch": "nixos-21.11",
"description": "Nix Packages collection",
"homepage": "",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "eabc38219184cc3e04a974fe31857d8e0eac098d",
"sha256": "04ffwp2gzq0hhz7siskw6qh9ys8ragp7285vi1zh8xjksxn1msc5",
"type": "tarball",
"url": "https://github.com/nixos/nixpkgs/archive/eabc38219184cc3e04a974fe31857d8e0eac098d.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs-unstable": {
"branch": "nixos-unstable",
"description": "Nix Packages collection",
"homepage": "",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "ae1dc133ea5f1538d035af41e5ddbc2ebcb67b90",
"sha256": "0dq22dagzk76x2ws4dz88w018i6byamd6rnzqizx68bzimg6g7xn",
"type": "tarball",
"url": "https://github.com/nixos/nixpkgs/archive/ae1dc133ea5f1538d035af41e5ddbc2ebcb67b90.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"workadventure": {
"branch": "master",
"repo": "https://stuebinm.eu/git/workadventure-nix",
"rev": "8db4bbc5eccaac218c68fb0853f1972dadd7a40c",
"type": "git"
}
}

View file

@ -1,194 +0,0 @@
# This file has been generated by Niv.
let
#
# The fetchers. fetch_<type> fetches specs of type <type>.
#
fetch_file = pkgs: name: spec:
let
name' = sanitizeName name + "-src";
in
if spec.builtin or true then
builtins_fetchurl { inherit (spec) url sha256; name = name'; }
else
pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
fetch_tarball = pkgs: name: spec:
let
name' = sanitizeName name + "-src";
in
if spec.builtin or true then
builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
else
pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
fetch_git = name: spec:
let
ref =
if spec ? ref then spec.ref else
if spec ? branch then "refs/heads/${spec.branch}" else
if spec ? tag then "refs/tags/${spec.tag}" else
abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
submodules = if spec ? submodules then spec.submodules else false;
submoduleArg =
let
nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0;
emptyArgWithWarning =
if submodules == true
then
builtins.trace
(
"The niv input \"${name}\" uses submodules "
+ "but your nix's (${builtins.nixVersion}) builtins.fetchGit "
+ "does not support them"
)
{}
else {};
in
if nixSupportsSubmodules
then { inherit submodules; }
else emptyArgWithWarning;
in
builtins.fetchGit
({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg);
fetch_local = spec: spec.path;
fetch_builtin-tarball = name: throw
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=tarball -a builtin=true'';
fetch_builtin-url = name: throw
''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=file -a builtin=true'';
#
# Various helpers
#
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
sanitizeName = name:
(
concatMapStrings (s: if builtins.isList s then "-" else s)
(
builtins.split "[^[:alnum:]+._?=-]+"
((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
)
);
# The set of packages used when specs are fetched using non-builtins.
mkPkgs = sources: system:
let
sourcesNixpkgs =
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
in
if builtins.hasAttr "nixpkgs" sources
then sourcesNixpkgs
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
import <nixpkgs> {}
else
abort
''
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
add a package called "nixpkgs" to your sources.json.
'';
# The actual fetching function.
fetch = pkgs: name: spec:
if ! builtins.hasAttr "type" spec then
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
else if spec.type == "file" then fetch_file pkgs name spec
else if spec.type == "tarball" then fetch_tarball pkgs name spec
else if spec.type == "git" then fetch_git name spec
else if spec.type == "local" then fetch_local spec
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
else if spec.type == "builtin-url" then fetch_builtin-url name
else
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
# If the environment variable NIV_OVERRIDE_${name} is set, then use
# the path directly as opposed to the fetched source.
replace = name: drv:
let
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
in
if ersatz == "" then drv else
# this turns the string into an actual Nix path (for both absolute and
# relative paths)
if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
# Ports of functions for older nix versions
# a Nix version of mapAttrs if the built-in doesn't exist
mapAttrs = builtins.mapAttrs or (
f: set: with builtins;
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
concatMapStrings = f: list: concatStrings (map f list);
concatStrings = builtins.concatStringsSep "";
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
optionalAttrs = cond: as: if cond then as else {};
# fetchTarball version that is compatible between all the versions of Nix
builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchTarball;
in
if lessThan nixVersion "1.12" then
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
else
fetchTarball attrs;
# fetchurl version that is compatible between all the versions of Nix
builtins_fetchurl = { url, name ? null, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchurl;
in
if lessThan nixVersion "1.12" then
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
else
fetchurl attrs;
# Create the final "sources" from the config
mkSources = config:
mapAttrs (
name: spec:
if builtins.hasAttr "outPath" spec
then abort
"The values in sources.json should not have an 'outPath' attribute"
else
spec // { outPath = replace name (fetch config.pkgs name spec); }
) config.sources;
# The "config" used by the fetchers
mkConfig =
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
, sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
, system ? builtins.currentSystem
, pkgs ? mkPkgs sources system
}: rec {
# The sources, i.e. the attribute set of spec name to spec
inherit sources;
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
inherit pkgs;
};
in
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

View file

@ -1,49 +0,0 @@
{ stdenv, requireFile, lib,
libcxx, libcxxabi
}:
stdenv.mkDerivation rec {
pname = "blackmagic-desktop-video";
version = "12.2.2";
buildInputs = [
libcxx libcxxabi
];
src = requireFile {
name = "Blackmagic_Desktop_Video_Linux_12.2.2.tar.gz";
url = "https://www.blackmagicdesign.com/support/";
sha256 = "8bca946bd3f002d2d404a74210c881935351e1a0d03f750559b180fdb439ef35";
};
setSourceRoot = ''
tar xf Blackmagic_Desktop_Video_Linux_12.2.2/other/x86_64/desktopvideo-12.2.2a6-x86_64.tar.gz
sourceRoot=$NIX_BUILD_TOP/desktopvideo-12.2.2a6-x86_64
'';
installPhase = ''
runHook preInstall
mkdir -p $out/{bin,share/doc,lib}
cp -r $sourceRoot/usr/share/doc/desktopvideo $out/share/doc
cp $sourceRoot/usr/lib/*.so $out/lib
ln -s ${libcxx}/lib/* ${libcxxabi}/lib/* $out/lib
cp $sourceRoot/usr/lib/blackmagic/DesktopVideo/libgcc_s.so.1 $out/lib/
cp $sourceRoot/usr/lib/blackmagic/DesktopVideo/DesktopVideoHelper $out/bin/
runHook postInstall
'';
postFixup = ''
patchelf --set-interpreter ${stdenv.cc.bintools.dynamicLinker} \
--set-rpath "$out/lib:${lib.makeLibraryPath [ libcxx libcxxabi ]}" \
$out/bin/DesktopVideoHelper
'';
meta = with lib; {
homepage = "https://www.blackmagicdesign.com/support/family/capture-and-playback";
maintainers = [ maintainers.hexchen ];
license = licenses.unfree;
description = "Supporting applications for Blackmagic Decklink. Doesn't include the desktop applications, only the helper required to make the driver work.";
platforms = platforms.linux;
};
}

View file

@ -1,92 +0,0 @@
{ stdenv, mkYarnPackage, mkYarnModules, fetchFromGitHub, libsass, python, python3, pkg-config, libusb, fetchurl, nodejs, electron, writeText, makeWrapper, udev, nodePackages, libvips }:
let
version = "2.1.3";
source = fetchFromGitHub {
owner = "bitfocus";
repo = "companion";
# rev = "v${version}";
rev = "1cc51029a19d7263a09058f73922277ca53a1583";
sha256 = "0305wwdic3n20whzhh9zqcd3dwj7hc4fpycs645ncc3sk48azmj0";
};
nodeHeaders = fetchurl {
url = "https://nodejs.org/download/release/v${nodejs.version}/node-v${nodejs.version}-headers.tar.gz";
sha256 = "19b0dg8292cjx758wlrvpb3jf520bpyvjal2n7r4fyvk38x9flik";
};
webui = mkYarnPackage rec {
inherit version;
pname = "bitfocus-companion-webui";
src = "${source}/webui";
configurePhase = "
cp -r $node_modules node_modules
chmod -R u+w node_modules
";
buildPhase = "PUBLIC_URL=. yarn build";
installPhase = "mv build $out";
distPhase = "true";
yarnNix = ./yarn-webui.nix;
pkgConfig = {
node-sass = {
buildInputs = [ libsass python ];
postInstall = "node scripts/build.js --tarball=${nodeHeaders}";
};
};
};
yarnModulesNoWorkspace = args: (mkYarnModules args).overrideAttrs(old: {
buildPhase = builtins.replaceStrings [" ./package.json"] [" /dev/null; cp deps/*/package.json ."] old.buildPhase;
});
modules = yarnModulesNoWorkspace rec {
inherit version;
pname = "companion-modules";
name = "${pname}-${version}";
yarnNix = ./yarn.nix;
packageJSON = "${source}/package.json";
yarnLock = "${source}/yarn.lock";
pkgConfig = {
node-hid = {
buildInputs = [ udev libusb python3 pkg-config ];
postInstall = "${nodePackages.node-gyp}/bin/node-gyp rebuild --tarball=${nodeHeaders}";
};
sharp = {
buildInputs = [ libvips pkg-config ];
postInstall = ''
sed -i "s|<!(node -p \"require(\\\\'./lib/libvips\\\\').minimumLibvipsVersion\")|${libvips.version}|" binding.gyp
sed -i "s|<!(node -p \"require(\\\\'./lib/libvips\\\\').pkgConfigPath()\")||" binding.gyp
sed -i "s|<!(node -p \"Boolean(require(\\\\'./lib/libvips\\\\').useGlobalLibvips()).toString()\")|true|" binding.gyp
sed -i "s|PKG_CONFIG_PATH=\"<(pkg_config_path)\" ||" binding.gyp
${nodePackages.node-gyp}/bin/node-gyp rebuild --tarball=${nodeHeaders}
'';
};
};
};
in stdenv.mkDerivation rec {
inherit version webui modules;
pname = "bitfocus-companion";
src = source;
nativeBuildInputs = [ makeWrapper ];
configurePhase = "";
buildPhase = "";
installPhase = ''
mkdir -p $out/share
cp --no-preserve=mode -r $src "$out/share/companion"
echo "nixos-f00baa-0" > $out/share/companion/BUILD
ln -s '${webui}' "$out/share/companion/static"
cp -r '${modules}/node_modules' "$out/share/companion/node_modules"
sed -i "s|process.resourcesPath|\"$out/share/companion\"|" $out/share/companion/lib/server_http.js
sed -i "s|require('app-root-path')|\"$out/share/companion\"|" $out/share/companion/{app,lib/{schedule,help,instance}}.js
makeWrapper '${electron}/bin/electron' "$out/bin/companion" \
--add-flags "$out/share/companion"
'';
}

View file

@ -1,478 +0,0 @@
{
"name": "companion",
"version": "2.2.0",
"description": "Companion",
"main": "electron.js",
"build": {
"productName": "Companion",
"appId": "companion.bitfocus.no",
"remoteBuild": false,
"dmg": {
"artifactName": "companion-mac-${arch}.dmg",
"sign": true
},
"mac": {
"target": "dmg",
"category": "no.bitfocus.companion",
"extendInfo": {
"LSBackgroundOnly": 1,
"LSUIElement": 1
},
"extraFiles": [
{
"from": "./node_modules/sharp/vendor/8.10.6/lib",
"to": "Frameworks",
"filter": [
"!glib-2.0/**/*"
]
}
]
},
"win": {
"target": "nsis",
"extraFiles": [
{
"from": "./node_modules/sharp/build/Release",
"to": ".",
"filter": [
"lib*.dll"
]
}
]
},
"nsis": {
"artifactName": "companion-win64.exe",
"createStartMenuShortcut": true,
"perMachine": true,
"oneClick": false,
"allowElevation": true,
"allowToChangeInstallationDirectory": true,
"installerIcon": "icon.ico",
"installerSidebar": "compinst.bmp",
"uninstallerSidebar": "compinst.bmp"
},
"directories": {
"buildResources": "assets/",
"output": "electron-output/"
},
"linux": {
"target": "dir",
"extraFiles": [
{
"from": "./node_modules/sharp/vendor/8.10.6/lib",
"to": ".",
"filter": [
"libvips*.so.*"
]
}
]
},
"files": [
"**/*",
"assets/icon.png",
"assets/bitfocus-logo.png",
"assets/trayTemplate.png",
"assets/trayTemplate@2x.png",
"!webui/**/*",
"!font/*",
"!tools/*",
"!*.md",
"!node_modules/sharp/vendor/lib"
],
"extraResources": [
{
"from": "webui/build",
"to": "static"
}
]
},
"scripts": {
"prod": "./tools/build_writefile.sh && electron .",
"dev": "./tools/build_writefile.sh && cross-env DEVELOPER=1 electron .",
"update": "./tools/update.sh",
"pack": "electron-builder --dir",
"dist:webui": "yarn --cwd webui build",
"dist:prepare": "./tools/build_writefile.sh ; rm -rf electron-output && yarn dist:webui",
"dist": "yarn dist:prepare && yarn electron-rebuild && electron-builder",
"electron-rebuild": "yarn dist:prepare:sharp && electron-builder install-app-deps",
"testprod": "./node_modules/electron/cli.js .",
"macdist": "yarn dist:prepare && yarn dist:prepare:mac-x64 && electron-builder --publish=never --x64 --mac",
"macarmdist": "yarn dist:prepare && yarn dist:prepare:mac-arm64 && electron-builder --publish=never --arm64 --mac",
"windist": "yarn dist:prepare && yarn dist:prepare:win && electron-builder --publish=never --x64 --win",
"lindist": "yarn dist:prepare && yarn dist:prepare:linux && electron-builder --publish=never --x64 --linux",
"rpidist": "yarn dist:prepare && yarn dist:prepare:rpi && electron-builder --publish=never --armv7l --linux",
"dist:prepare:sharp": "cd node_modules/sharp && rimraf vendor && node install/libvips && node install/dll-copy",
"dist:prepare:win": "cross-env npm_config_platform=win32 npm_config_arch=x64 yarn dist:prepare:sharp",
"dist:prepare:mac-x64": "cross-env npm_config_platform=darwin npm_config_arch=x64 yarn dist:prepare:sharp",
"dist:prepare:mac-arm64": "cross-env npm_config_platform=darwin npm_config_arch=arm64 yarn dist:prepare:sharp",
"dist:prepare:linux": "cross-env npm_config_platform=linux npm_config_arch=x64 yarn dist:prepare:sharp",
"dist:prepare:rpi": "cross-env npm_config_platform=linux npm_config_arch=arm yarn dist:prepare:sharp",
"test": "mocha",
"postinstall": "./tools/build_writefile.sh",
"headless": "nodemon --ignore './webui/' headless.js",
"dev-headless": "./tools/build_writefile.sh && cross-env DEVELOPER=1 nodemon --ignore './webui/' headless.js",
"dev-webui": "yarn --cwd webui dev",
"format": "prettier --write ."
},
"repository": "https://github.com/bitfocus/companion",
"keywords": [
"bitfocus",
"companion"
],
"engines": {
"npm": "please-use-yarn",
"yarn": "^1.22",
"node": "^14.16"
},
"managed_node_version": "14",
"author": "Bitfocus AS",
"license": "MIT",
"devDependencies": {
"asar": "^3.0.3",
"aws-sdk": "^2.931.0",
"chai": "^4.3.4",
"chai-fs": "^2.0.0",
"cross-env": "^7.0.3",
"electron": "^13.1.2",
"electron-builder": "22.11.7",
"mocha": "^6.2.3",
"nodemon": "^2.0.7",
"p-all": "^3.0.0",
"prettier": "^2.3.1",
"rimraf": "^3.0.2",
"s3-upload-stream": "^1.0.7"
},
"dependencies": {
"@sentry/electron": "^2.5.0",
"app-root-path": "^3.0.0",
"binopsy": "^0.0.0",
"check-ip": "^1.1.1",
"companion-module-7thsensedesign-delta": "github:bitfocus/companion-module-7thsensedesign-delta#v1.0.1",
"companion-module-agf-characterworks": "github:bitfocus/companion-module-agf-characterworks#v1.0.3",
"companion-module-aja-helo": "github:bitfocus/companion-module-aja-helo#v1.0.2",
"companion-module-aja-kipro": "github:bitfocus/companion-module-aja-kipro#v2.0.11",
"companion-module-aja-kumo": "github:bitfocus/companion-module-aja-kumo#v1.0.5",
"companion-module-allenheath-dlive-ilive": "github:bitfocus/companion-module-allenheath-dlive-ilive#v1.3.7",
"companion-module-allenheath-qu": "github:bitfocus/companion-module-allenheath-qu#v1.0.7",
"companion-module-allenheath-sq": "github:bitfocus/companion-module-allenheath-sq#v1.3.8",
"companion-module-analogway-eks500": "github:bitfocus/companion-module-analogway-eks500#v1.0.1",
"companion-module-analogway-livecore": "github:bitfocus/companion-module-analogway-livecore#v1.1.1",
"companion-module-analogway-livepremier": "github:bitfocus/companion-module-analogway-livepremier#v1.0.2",
"companion-module-analogway-midra": "github:bitfocus/companion-module-analogway-midra#v1.0.2",
"companion-module-analogway-picturall": "github:bitfocus/companion-module-analogway-picturall#v1.2.1",
"companion-module-analogway-pls300": "github:bitfocus/companion-module-analogway-pls300#v1.0.3",
"companion-module-analogway-vertige": "github:bitfocus/companion-module-analogway-vertige#v1.0.0",
"companion-module-analogway-vio": "github:bitfocus/companion-module-analogway-vio#v1.0.1",
"companion-module-anomes-millumin": "github:bitfocus/companion-module-anomes-millumin#v1.0.6",
"companion-module-arkaos-mediamaster": "github:bitfocus/companion-module-arkaos-mediamaster#v1.0.1",
"companion-module-aten-matrix": "github:bitfocus/companion-module-aten-matrix#v1.0.0",
"companion-module-audiostrom-liveprofessor": "github:bitfocus/companion-module-audiostrom-liveprofessor#v1.0.0",
"companion-module-audivero-unityintercom-client": "github:bitfocus/companion-module-audivero-unityintercom-client#v1.0.2",
"companion-module-avishop-hdbaset-matrix": "github:bitfocus/companion-module-avishop-hdbaset-matrix#v1.0.1",
"companion-module-avolites-ai": "github:bitfocus/companion-module-avolites-ai#v1.0.1",
"companion-module-avolites-titan": "github:bitfocus/companion-module-avolites-titan#v1.1.0",
"companion-module-avproconnect-acmx1616-auhd": "github:bitfocus/companion-module-avproconnect-acmx1616-auhd#v1.0.0",
"companion-module-avstumpfl-pixera": "github:bitfocus/companion-module-avstumpfl-pixera#v1.0.2",
"companion-module-axis-ptz": "github:bitfocus/companion-module-axis-ptz#v1.0.1",
"companion-module-barco-dcs": "github:bitfocus/companion-module-barco-dcs#v1.0.4",
"companion-module-barco-dp": "github:bitfocus/companion-module-barco-dp#v1.1.2",
"companion-module-barco-encore": "github:bitfocus/companion-module-barco-encore#v1.0.1",
"companion-module-barco-eventmaster": "github:bitfocus/companion-module-barco-eventmaster#v1.3.6",
"companion-module-barco-eventmaster-xml": "github:bitfocus/companion-module-barco-eventmaster-xml#v1.2.4",
"companion-module-barco-hdx": "github:bitfocus/companion-module-barco-hdx#v1.1.5",
"companion-module-barco-imagepro": "github:bitfocus/companion-module-barco-imagepro#v1.0.1",
"companion-module-barco-matrixpro": "github:bitfocus/companion-module-barco-matrixpro#v1.1.0",
"companion-module-barco-pds": "github:bitfocus/companion-module-barco-pds#v1.1.5",
"companion-module-barco-pulse": "github:bitfocus/companion-module-barco-pulse#v1.1.2",
"companion-module-bbc-raven": "github:bitfocus/companion-module-bbc-raven#v1.0.1",
"companion-module-behringer-wing": "github:bitfocus/companion-module-behringer-wing#v1.0.5",
"companion-module-behringer-x32": "github:bitfocus/companion-module-behringer-x32#v2.7.0",
"companion-module-behringer-xair": "github:bitfocus/companion-module-behringer-xair#v1.6.7",
"companion-module-biamp-audia": "github:bitfocus/companion-module-biamp-audia#v1.0.1",
"companion-module-birddog-studio": "github:bitfocus/companion-module-birddog-studio#v1.0.0",
"companion-module-birddog-visca": "github:bitfocus/companion-module-birddog-visca#v1.0.4",
"companion-module-bitfocus-companion": "github:bitfocus/companion-module-bitfocus-companion#v1.5.3",
"companion-module-bitfocus-snapshot": "github:bitfocus/companion-module-bitfocus-snapshot#v0.0.4",
"companion-module-blackbox-boxilla": "github:bitfocus/companion-module-blackbox-boxilla#v1.0.2",
"companion-module-blackdiamondvideo-phantom800": "github:bitfocus/companion-module-blackdiamondvideo-phantom800#v1.0.0",
"companion-module-bmd-atem": "github:bitfocus/companion-module-bmd-atem#v2.13.0",
"companion-module-bmd-audiomonitor": "github:bitfocus/companion-module-bmd-audiomonitor#v1.0.0",
"companion-module-bmd-hyperdeck": "github:bitfocus/companion-module-bmd-hyperdeck#v1.2.2",
"companion-module-bmd-multiview16": "github:bitfocus/companion-module-bmd-multiview16#v1.0.1",
"companion-module-bmd-multiview4": "github:bitfocus/companion-module-bmd-multiview4#v1.3.2",
"companion-module-bmd-smartview": "github:bitfocus/companion-module-bmd-smartview#v1.1.3",
"companion-module-bmd-teranex": "github:bitfocus/companion-module-bmd-teranex#v1.0.4",
"companion-module-bmd-videohub": "github:bitfocus/companion-module-bmd-videohub#v1.3.0",
"companion-module-bmd-webpresenterhd": "github:bitfocus/companion-module-bmd-webpresenterhd#v1.0.1",
"companion-module-boinx-mimolive": "github:bitfocus/companion-module-boinx-mimolive#v1.0.1",
"companion-module-borealsystems-director": "github:bitfocus/companion-module-borealsystems-director#v1.0.0",
"companion-module-brightsign-player": "github:bitfocus/companion-module-brightsign-player#v1.1.1",
"companion-module-brompton-tessera": "github:bitfocus/companion-module-brompton-tessera#v1.0.0",
"companion-module-canon-xf": "github:bitfocus/companion-module-canon-xf#v1.0.0",
"companion-module-casparcg-server": "github:bitfocus/companion-module-casparcg-server#v1.0.2",
"companion-module-chamsys-magicq-osc": "github:bitfocus/companion-module-chamsys-magicq-osc#v1.0.1",
"companion-module-chamsys-magicq-udp": "github:bitfocus/companion-module-chamsys-magicq-udp#v1.0.2",
"companion-module-christie-pandorasbox": "github:bitfocus/companion-module-christie-pandorasbox#v2.0.2",
"companion-module-christie-projector": "github:bitfocus/companion-module-christie-projector#v2.0.3",
"companion-module-christie-spyder": "github:bitfocus/companion-module-christie-spyder#v1.0.0",
"companion-module-christie-wd": "github:bitfocus/companion-module-christie-wd#v1.0.6",
"companion-module-cisco-cms": "github:bitfocus/companion-module-cisco-cms#v1.0.1",
"companion-module-cisco-webex-websocket": "github:bitfocus/companion-module-cisco-webex-websocket#v1.1.0",
"companion-module-cockos-reaper": "github:bitfocus/companion-module-cockos-reaper#v1.1.0",
"companion-module-connect-webcaster": "github:bitfocus/companion-module-connect-webcaster#v1.0.0",
"companion-module-crystal-scte": "github:bitfocus/companion-module-crystal-scte#v1.0.0",
"companion-module-dahuasecurity-ptz": "github:bitfocus/companion-module-dahuasecurity-ptz#v1.0.1",
"companion-module-dalite-scb": "github:bitfocus/companion-module-dalite-scb#v1.0.0",
"companion-module-dashare-multiplay": "github:bitfocus/companion-module-dashare-multiplay#v1.0.1",
"companion-module-datapath-fx4": "github:bitfocus/companion-module-datapath-fx4#v1.0.0",
"companion-module-dataton-watchout": "github:bitfocus/companion-module-dataton-watchout#v1.2.0",
"companion-module-datavideo-dvip": "github:bitfocus/companion-module-datavideo-dvip#v1.0.0",
"companion-module-datavideo-visca": "github:bitfocus/companion-module-datavideo-visca#v1.0.3",
"companion-module-dcc-ex-commandstation": "github:bitfocus/companion-module-dcc-ex-commandstation#v1.0.0",
"companion-module-denon-dn-500bd-mkii": "github:bitfocus/companion-module-denon-dn-500bd-mkii#v1.0.2",
"companion-module-denon-receiver": "github:bitfocus/companion-module-denon-receiver#v1.0.1",
"companion-module-denon-recorder": "github:bitfocus/companion-module-denon-recorder#v1.0.1",
"companion-module-depili-clock-8001": "github:bitfocus/companion-module-depili-clock-8001#v5.1.1",
"companion-module-dexon-dimax": "github:bitfocus/companion-module-dexon-dimax#v1.0.3",
"companion-module-dexon-divip": "github:bitfocus/companion-module-dexon-divip#v1.0.2",
"companion-module-dexon-matrix": "github:bitfocus/companion-module-dexon-matrix#v1.0.1",
"companion-module-digico-osc": "github:bitfocus/companion-module-digico-osc#v1.0.2",
"companion-module-digitalprojection-highlight": "github:bitfocus/companion-module-digitalprojection-highlight#v1.0.2",
"companion-module-disguise": "github:bitfocus/companion-module-disguise#v1.1.0",
"companion-module-disguise-mtc": "github:bitfocus/companion-module-disguise-mtc#v1.0.2",
"companion-module-dolby-cinemaprocessor": "github:bitfocus/companion-module-dolby-cinemaprocessor#v1.1.0",
"companion-module-draco-tera": "github:bitfocus/companion-module-draco-tera#v1.0.4",
"companion-module-dsan-limitimer": "github:bitfocus/companion-module-dsan-limitimer#v1.1.1",
"companion-module-dsan-perfectcue": "github:bitfocus/companion-module-dsan-perfectcue#v1.0.0",
"companion-module-dtvideolabs-playbackproplus": "github:bitfocus/companion-module-dtvideolabs-playbackproplus#v1.0.2",
"companion-module-elgato-keylight": "github:bitfocus/companion-module-elgato-keylight#v1.2.2",
"companion-module-epiphan-pearl": "github:bitfocus/companion-module-epiphan-pearl#v1.0.7",
"companion-module-etc-eos": "github:bitfocus/companion-module-etc-eos#v1.2.1",
"companion-module-extron-dxp": "github:bitfocus/companion-module-extron-dxp#v1.0.8",
"companion-module-extron-in1604": "github:bitfocus/companion-module-extron-in1604#v1.0.3",
"companion-module-extron-ipl-t-pcs4": "github:bitfocus/companion-module-extron-ipl-t-pcs4#v1.0.2",
"companion-module-extron-smp111": "github:bitfocus/companion-module-extron-smp111#v1.0.4",
"companion-module-extron-smp351": "github:bitfocus/companion-module-extron-smp351#v1.2.0",
"companion-module-extron-smx": "github:bitfocus/companion-module-extron-smx#v1.0.4",
"companion-module-faithchapel-videoplayoutserver": "github:bitfocus/companion-module-faithchapel-videoplayoutserver#v1.0.1",
"companion-module-figure53-go-button": "github:bitfocus/companion-module-figure53-go-button#v1.2.4",
"companion-module-figure53-qlab": "github:bitfocus/companion-module-figure53-qlab#v1.2.5",
"companion-module-figure53-qlab-advance": "github:bitfocus/companion-module-figure53-qlab-advance#v1.3.8",
"companion-module-figure53-qview": "github:bitfocus/companion-module-figure53-qview#v1.0.0",
"companion-module-folivora-btt": "github:bitfocus/companion-module-folivora-btt#v1.0.2",
"companion-module-fora-hvs": "github:bitfocus/companion-module-fora-hvs#v1.2.4",
"companion-module-foscam-ptz": "github:bitfocus/companion-module-foscam-ptz#v1.0.1",
"companion-module-gallery-virtualvtrpro": "github:bitfocus/companion-module-gallery-virtualvtrpro#v1.0.1",
"companion-module-gammacontrol-gmaestro": "github:bitfocus/companion-module-gammacontrol-gmaestro#v1.0.2",
"companion-module-gefen-dvimatrix": "github:bitfocus/companion-module-gefen-dvimatrix#v1.0.1",
"companion-module-generic-artnet": "github:bitfocus/companion-module-generic-artnet#v1.0.2",
"companion-module-generic-emberplus": "github:bitfocus/companion-module-generic-emberplus#v1.1.1",
"companion-module-generic-http": "github:bitfocus/companion-module-generic-http#v1.0.8",
"companion-module-generic-mqtt": "github:bitfocus/companion-module-generic-mqtt#v1.2.0",
"companion-module-generic-osc": "github:bitfocus/companion-module-generic-osc#v1.0.4",
"companion-module-generic-pjlink": "github:bitfocus/companion-module-generic-pjlink#v1.0.5",
"companion-module-generic-sacn": "github:bitfocus/companion-module-generic-sacn#v1.0.0",
"companion-module-generic-swp08": "github:bitfocus/companion-module-generic-swp08#v1.0.3",
"companion-module-generic-tcp-serial": "github:bitfocus/companion-module-generic-tcp-serial#v1.0.2",
"companion-module-generic-tcp-udp": "github:bitfocus/companion-module-generic-tcp-udp#v1.0.6",
"companion-module-generic-wakeonlan": "github:bitfocus/companion-module-generic-wakeonlan#v1.0.4",
"companion-module-generic-websocket": "github:bitfocus/companion-module-generic-websocket#v1.0.0",
"companion-module-globalcache-itac-cc": "github:bitfocus/companion-module-globalcache-itac-cc#v1.0.1",
"companion-module-globalcache-itac-ir": "github:bitfocus/companion-module-globalcache-itac-ir#v1.0.5",
"companion-module-globalcache-itac-sl": "github:bitfocus/companion-module-globalcache-itac-sl#v1.0.3",
"companion-module-grassvalley-amp": "github:bitfocus/companion-module-grassvalley-amp#v1.1.3",
"companion-module-greenhippo-hippotizer": "github:bitfocus/companion-module-greenhippo-hippotizer#v1.0.2",
"companion-module-h2r-graphics": "github:bitfocus/companion-module-h2r-graphics#v1.1.2",
"companion-module-haivision-connectdvr": "github:bitfocus/companion-module-haivision-connectdvr#v1.0.9",
"companion-module-haivision-kbencoder": "github:bitfocus/companion-module-haivision-kbencoder#v1.0.0",
"companion-module-highend-hog4": "github:bitfocus/companion-module-highend-hog4#v1.1.0",
"companion-module-hologfx-holographics": "github:bitfocus/companion-module-hologfx-holographics#v1.0.0",
"companion-module-homeassistant-server": "github:bitfocus/companion-module-homeassistant-server#v0.6.1",
"companion-module-ifelseware-avkey": "github:bitfocus/companion-module-ifelseware-avkey#v1.0.0",
"companion-module-ifelseware-avplayback": "github:bitfocus/companion-module-ifelseware-avplayback#v1.0.2",
"companion-module-imimot-mitti": "github:bitfocus/companion-module-imimot-mitti#v1.0.8",
"companion-module-interactivetechnologies-cueserver": "github:bitfocus/companion-module-interactivetechnologies-cueserver#v1.0.1",
"companion-module-irisdown-countdowntimer": "github:bitfocus/companion-module-irisdown-countdowntimer#v1.1.3",
"companion-module-irisdown-remoteshowcontrol": "github:bitfocus/companion-module-irisdown-remoteshowcontrol#v1.0.2",
"companion-module-jamesholt-x32tc": "github:bitfocus/companion-module-jamesholt-x32tc#v1.0.6",
"companion-module-joy-playdeck": "github:bitfocus/companion-module-joy-playdeck#v1.0.1",
"companion-module-justmacros-lua": "github:bitfocus/companion-module-justmacros-lua#v1.0.1",
"companion-module-jvc-ptz": "github:bitfocus/companion-module-jvc-ptz#v1.0.9",
"companion-module-kiloview-ndi": "github:bitfocus/companion-module-kiloview-ndi#v1.0.0",
"companion-module-kramer-matrix": "github:bitfocus/companion-module-kramer-matrix#v1.2.1",
"companion-module-kramer-vp727": "github:bitfocus/companion-module-kramer-vp727#v1.0.1",
"companion-module-kramer-vp734": "github:bitfocus/companion-module-kramer-vp734#v1.0.0",
"companion-module-kramer-vp773a": "github:bitfocus/companion-module-kramer-vp773a#v1.0.0",
"companion-module-kramer-vs41h": "github:bitfocus/companion-module-kramer-vs41h#v1.0.0",
"companion-module-leafcoders-titler": "github:bitfocus/companion-module-leafcoders-titler#v1.0.0",
"companion-module-lectrosonics-aspen": "github:bitfocus/companion-module-lectrosonics-aspen#v1.0.0",
"companion-module-lightware-lw2": "github:bitfocus/companion-module-lightware-lw2#v1.0.2",
"companion-module-lightware-lw3": "github:bitfocus/companion-module-lightware-lw3#v1.0.1",
"companion-module-liminalet-zoomosc": "github:bitfocus/companion-module-liminalet-zoomosc#v1.0.8",
"companion-module-linkbox-remote": "github:bitfocus/companion-module-linkbox-remote#v1.2.1",
"companion-module-livingasone-decoders": "github:bitfocus/companion-module-livingasone-decoders#v1.1.2",
"companion-module-ltn-schedule": "github:bitfocus/companion-module-ltn-schedule#v1.0.0",
"companion-module-lumens-mediaprocessor": "github:bitfocus/companion-module-lumens-mediaprocessor#v1.0.0",
"companion-module-lumens-visca": "github:bitfocus/companion-module-lumens-visca#v1.0.2",
"companion-module-lyntec-rpc-breaker": "github:bitfocus/companion-module-lyntec-rpc-breaker#v1.0.3",
"companion-module-magewell-proconvert-decoder": "github:bitfocus/companion-module-magewell-proconvert-decoder#v1.0.0",
"companion-module-magewell-ultrastream": "github:bitfocus/companion-module-magewell-ultrastream#v0.0.3",
"companion-module-magicsoft-recorder": "github:bitfocus/companion-module-magicsoft-recorder#v1.0.0",
"companion-module-malighting-grandma2": "github:bitfocus/companion-module-malighting-grandma2#v1.0.10",
"companion-module-malighting-msc": "github:bitfocus/companion-module-malighting-msc#v0.2.1",
"companion-module-matrox-monarch": "github:bitfocus/companion-module-matrox-monarch#v1.0.0",
"companion-module-media-player-classic": "github:bitfocus/companion-module-media-player-classic#v1.0.0",
"companion-module-metus-ingest": "github:bitfocus/companion-module-metus-ingest#v1.2.1",
"companion-module-middleatlantic-racklink": "github:bitfocus/companion-module-middleatlantic-racklink#v1.0.0",
"companion-module-middlethings-middlecontrol": "github:bitfocus/companion-module-middlethings-middlecontrol#v1.0.1",
"companion-module-modelighting-edin": "github:bitfocus/companion-module-modelighting-edin#v1.0.0",
"companion-module-modulo": "github:bitfocus/companion-module-modulo#v1.0.1",
"companion-module-motu-avb": "github:bitfocus/companion-module-motu-avb#v1.0.2",
"companion-module-msc-router": "github:bitfocus/companion-module-msc-router#v1.0.2",
"companion-module-multicamsystems-multicamsuite": "github:bitfocus/companion-module-multicamsystems-multicamsuite#v1.0.1",
"companion-module-muxlab-kvm": "github:bitfocus/companion-module-muxlab-kvm#v1.0.0",
"companion-module-neodarque-stagetimer2": "github:bitfocus/companion-module-neodarque-stagetimer2#v1.2.6",
"companion-module-netio-powerbox": "github:bitfocus/companion-module-netio-powerbox#v1.0.0",
"companion-module-nevion-mrp": "github:bitfocus/companion-module-nevion-mrp#v2.0.2",
"companion-module-newbluefx-titler": "github:bitfocus/companion-module-newbluefx-titler#v1.0.1",
"companion-module-newtek-ndistudiomonitor": "github:bitfocus/companion-module-newtek-ndistudiomonitor#v1.0.1",
"companion-module-newtek-tricaster": "github:bitfocus/companion-module-newtek-tricaster#v1.1.4",
"companion-module-nexo-nxamp": "github:bitfocus/companion-module-nexo-nxamp#v1.0.0",
"companion-module-nobe-omniscope": "github:bitfocus/companion-module-nobe-omniscope#v1.0.0",
"companion-module-noismada-octopuslistener": "github:bitfocus/companion-module-noismada-octopuslistener#v1.0.2",
"companion-module-noismada-octopusshowcontrol": "github:bitfocus/companion-module-noismada-octopusshowcontrol#v1.2.0",
"companion-module-novastar-controller": "github:bitfocus/companion-module-novastar-controller#v1.0.6",
"companion-module-obs-studio": "github:bitfocus/companion-module-obs-studio#v1.0.24",
"companion-module-obsidiancontrol-onyx": "github:bitfocus/companion-module-obsidiancontrol-onyx#v1.0.3",
"companion-module-octava-pro-dsx": "github:bitfocus/companion-module-octava-pro-dsx#v0.0.1",
"companion-module-openlp-http": "github:bitfocus/companion-module-openlp-http#v0.1.1",
"companion-module-opensong-api": "github:bitfocus/companion-module-opensong-api#v1.0.1",
"companion-module-openweather-rest": "github:bitfocus/companion-module-openweather-rest#v1.0.2",
"companion-module-opticis-omm-1000": "github:bitfocus/companion-module-opticis-omm-1000#v1.0.2",
"companion-module-optoma-z28s": "github:bitfocus/companion-module-optoma-z28s#v1.0.2",
"companion-module-orfast-ndi": "github:bitfocus/companion-module-orfast-ndi#v1.0.0",
"companion-module-panasonic-avhs": "github:bitfocus/companion-module-panasonic-avhs#v1.0.4",
"companion-module-panasonic-camera-controller": "github:bitfocus/companion-module-panasonic-camera-controller#v1.0.6",
"companion-module-panasonic-projector": "github:bitfocus/companion-module-panasonic-projector#v1.0.1",
"companion-module-panasonic-ptz": "github:bitfocus/companion-module-panasonic-ptz#v1.0.19",
"companion-module-panasonic-tv-th": "github:bitfocus/companion-module-panasonic-tv-th#v0.0.1",
"companion-module-pangolin-beyond": "github:bitfocus/companion-module-pangolin-beyond#v1.0.2",
"companion-module-phillips-hue": "github:bitfocus/companion-module-phillips-hue#v0.0.4",
"companion-module-pixap-pixtimerpro": "github:bitfocus/companion-module-pixap-pixtimerpro#v1.0.6",
"companion-module-planningcenter-serviceslive": "github:bitfocus/companion-module-planningcenter-serviceslive#v1.0.5",
"companion-module-presentationtools-aps": "github:bitfocus/companion-module-presentationtools-aps#v1.1.0",
"companion-module-presentationtools-cuetimer": "github:bitfocus/companion-module-presentationtools-cuetimer#v1.0.0",
"companion-module-protopie-bridge": "github:bitfocus/companion-module-protopie-bridge#v1.0.2",
"companion-module-prsi-ipower": "github:bitfocus/companion-module-prsi-ipower#v1.0.2",
"companion-module-ptzoptics-visca": "github:bitfocus/companion-module-ptzoptics-visca#v1.1.6",
"companion-module-qsys-remote-control": "github:bitfocus/companion-module-qsys-remote-control#v1.0.3",
"companion-module-radiodj-rest": "github:bitfocus/companion-module-radiodj-rest#v1.0.0",
"companion-module-rationalacoustics-smaart3": "github:bitfocus/companion-module-rationalacoustics-smaart3#v1.0.3",
"companion-module-renewedvision-propresenter": "github:bitfocus/companion-module-renewedvision-propresenter#v2.4.0",
"companion-module-renewedvision-pvp": "github:bitfocus/companion-module-renewedvision-pvp#v1.0.7",
"companion-module-resolume-arena": "github:bitfocus/companion-module-resolume-arena#v1.0.5",
"companion-module-rocosoft-ptzjoy": "github:bitfocus/companion-module-rocosoft-ptzjoy#v1.0.1",
"companion-module-roku-tv": "github:bitfocus/companion-module-roku-tv#v1.0.1",
"companion-module-roland-m5000": "github:bitfocus/companion-module-roland-m5000#v1.0.2",
"companion-module-roland-v1200hd": "github:bitfocus/companion-module-roland-v1200hd#v1.0.0",
"companion-module-roland-v600uhd": "github:bitfocus/companion-module-roland-v600uhd#v1.0.1",
"companion-module-roland-v60hd": "github:bitfocus/companion-module-roland-v60hd#v1.0.10",
"companion-module-roland-vp42h": "github:bitfocus/companion-module-roland-vp42h#v1.0.0",
"companion-module-roland-vr50hd-mk2": "github:bitfocus/companion-module-roland-vr50hd-mk2#v1.0.0",
"companion-module-roland-xs42h": "github:bitfocus/companion-module-roland-xs42h#v1.0.0",
"companion-module-roland-xs62s": "github:bitfocus/companion-module-roland-xs62s#v1.0.1",
"companion-module-roland-xs84h": "github:bitfocus/companion-module-roland-xs84h#v1.0.0",
"companion-module-rossvideo-caprica": "github:bitfocus/companion-module-rossvideo-caprica#v1.0.0",
"companion-module-rossvideo-nkrouter": "github:bitfocus/companion-module-rossvideo-nkrouter#v1.0.2",
"companion-module-rossvideo-rosstalk": "github:bitfocus/companion-module-rossvideo-rosstalk#v1.2.8",
"companion-module-rossvideo-xpression": "github:bitfocus/companion-module-rossvideo-xpression#v1.0.2",
"companion-module-sain-smart-relay": "github:bitfocus/companion-module-sain-smart-relay#v1.0.0",
"companion-module-seervision-suite": "github:bitfocus/companion-module-seervision-suite#v1.1.0",
"companion-module-sharp-tv": "github:bitfocus/companion-module-sharp-tv#v1.0.0",
"companion-module-showcuesystems-scs": "github:bitfocus/companion-module-showcuesystems-scs#v1.0.1",
"companion-module-shure-dis-ccu": "github:bitfocus/companion-module-shure-dis-ccu#v1.0.1",
"companion-module-shure-psm1000": "github:bitfocus/companion-module-shure-psm1000#v1.0.0",
"companion-module-shure-scm820": "github:bitfocus/companion-module-shure-scm820#v1.0.0",
"companion-module-shure-wireless": "github:bitfocus/companion-module-shure-wireless#v1.2.0",
"companion-module-sienna-ndimonitor": "github:bitfocus/companion-module-sienna-ndimonitor#v1.0.0",
"companion-module-singularlive-studio": "github:bitfocus/companion-module-singularlive-studio#v1.0.7",
"companion-module-slack-webhooks": "github:bitfocus/companion-module-slack-webhooks#v1.0.1",
"companion-module-softron-movierecorder": "github:bitfocus/companion-module-softron-movierecorder#v1.0.1",
"companion-module-softron-ontheairvideo": "github:bitfocus/companion-module-softron-ontheairvideo#v1.0.0",
"companion-module-sononum-horae": "github:bitfocus/companion-module-sononum-horae#v1.0.1",
"companion-module-sonoran-coyote": "github:bitfocus/companion-module-sonoran-coyote#v1.0.0",
"companion-module-sonos-speakers": "github:bitfocus/companion-module-sonos-speakers#v0.2.0",
"companion-module-sony-bravia": "github:bitfocus/companion-module-sony-bravia#v1.0.0",
"companion-module-sony-visca": "github:bitfocus/companion-module-sony-visca#v1.2.8",
"companion-module-soundcraft-ui": "github:bitfocus/companion-module-soundcraft-ui#v2.0.3",
"companion-module-sounddevices-pixnet": "github:bitfocus/companion-module-sounddevices-pixnet#v1.0.0",
"companion-module-spotify-remote": "github:bitfocus/companion-module-spotify-remote#v1.0.7",
"companion-module-spx-gc": "github:bitfocus/companion-module-spx-gc#v1.0.2",
"companion-module-studiocoast-vmix": "github:bitfocus/companion-module-studiocoast-vmix#v1.2.22",
"companion-module-symetrix-dsp": "github:bitfocus/companion-module-symetrix-dsp#v1.3.0",
"companion-module-tallyma-wirelesstally": "github:bitfocus/companion-module-tallyma-wirelesstally#v1.0.1",
"companion-module-tascam-bdmp1": "github:bitfocus/companion-module-tascam-bdmp1#v0.1.5",
"companion-module-tascam-cd": "github:bitfocus/companion-module-tascam-cd#v1.0.2",
"companion-module-techministry-midirelay": "github:bitfocus/companion-module-techministry-midirelay#v2.0.4",
"companion-module-techministry-protally": "github:bitfocus/companion-module-techministry-protally#v1.0.0",
"companion-module-techministry-tallyarbiter": "github:bitfocus/companion-module-techministry-tallyarbiter#v1.0.2",
"companion-module-teracom-tcw181b": "github:bitfocus/companion-module-teracom-tcw181b#v1.0.2",
"companion-module-teradek-vidiu": "github:bitfocus/companion-module-teradek-vidiu#v1.0.2",
"companion-module-tesla-smart": "github:bitfocus/companion-module-tesla-smart#v1.0.3",
"companion-module-thelightingcontroller": "github:bitfocus/companion-module-thelightingcontroller#v1.1.2",
"companion-module-thingm-blink1": "github:bitfocus/companion-module-thingm-blink1#v1.2.3",
"companion-module-tplink-kasasmartplug": "github:bitfocus/companion-module-tplink-kasasmartplug#v1.0.1",
"companion-module-tslproducts-umd": "github:bitfocus/companion-module-tslproducts-umd#v1.2.1",
"companion-module-tvone-corio": "github:bitfocus/companion-module-tvone-corio#v1.0.0",
"companion-module-twitch-api": "github:bitfocus/companion-module-twitch-api#v1.0.0",
"companion-module-ubiquiti-unifi": "github:bitfocus/companion-module-ubiquiti-unifi#v1.0.1",
"companion-module-vaddio-ptz": "github:bitfocus/companion-module-vaddio-ptz#v1.0.1",
"companion-module-vicreo-hotkey": "github:bitfocus/companion-module-vicreo-hotkey#v2.0.5",
"companion-module-vicreo-variablelistener": "github:bitfocus/companion-module-vicreo-variablelistener#v1.0.7",
"companion-module-videolan-vlc": "github:bitfocus/companion-module-videolan-vlc#v1.1.12",
"companion-module-visualproductions-bstation2": "github:bitfocus/companion-module-visualproductions-bstation2#v1.0.6",
"companion-module-vivitek-projector": "github:bitfocus/companion-module-vivitek-projector#v1.0.3",
"companion-module-vizio-smartcast": "github:bitfocus/companion-module-vizio-smartcast#v1.1.4",
"companion-module-vyv-photon": "github:bitfocus/companion-module-vyv-photon#v1.0.4",
"companion-module-wyrestorm-sw0402mv": "github:bitfocus/companion-module-wyrestorm-sw0402mv#v1.0.1",
"companion-module-xiamen-sprolink-vd-series": "github:bitfocus/companion-module-xiamen-sprolink-vd-series#v1.0.1",
"companion-module-yamaha-rcp": "github:bitfocus/companion-module-yamaha-rcp#v1.6.0",
"companion-module-youtube-live": "github:bitfocus/companion-module-youtube-live#v1.1.2",
"companion-module-zenvideo-ndirouter": "github:bitfocus/companion-module-zenvideo-ndirouter#v1.0.1",
"debug": "^4.2.0",
"elgato-stream-deck": "^4.1.0",
"emberplus-connection": "^0.0.4",
"express": "^4.16.3",
"find-process": "1.4.4",
"fs-extra": "^10.0.0",
"infinitton-idisplay": "^1.0.5",
"lodash": "^4.17.20",
"mkdirp": "^1.0.4",
"moment": "^2.29.1",
"network": "^0.4.1",
"node-fetch": "^2.6.1",
"node-rest-client": "^3.1.0",
"osc": "^2.4.1",
"pngjs": "^3.3.3",
"sharp": "^0.28.3",
"shortid": "^2.2.16",
"socket.io": "^4.1.2",
"strip-ansi": "^5.2.0",
"websocket": "^1.0.34",
"node-hid": "^2.1.1",
"serialport": "^9.2.0",
"ws": "^7.4.6"
},
"collective": {
"type": "donorbox",
"url": "https://donorbox.org/bitfocus-opensource"
},
"optionalDependencies": {
"@julusian/jpeg-turbo": "^1.1.1"
},
"resolutions": {
"infinitton-idisplay/node-hid": "^2.1.1",
"**/osc/serialport": "^9.2.0",
"**/osc/ws": "^7.4.6"
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,48 +0,0 @@
{ stdenv, requireFile, fetchpatch, kernel, lib }:
stdenv.mkDerivation rec {
pname = "decklink";
version = "12.2.2";
src = requireFile {
name = "Blackmagic_Desktop_Video_Linux_12.2.2.tar.gz";
url = "https://www.blackmagicdesign.com/support/";
sha256 = "8bca946bd3f002d2d404a74210c881935351e1a0d03f750559b180fdb439ef35";
};
KERNELDIR = "${kernel.dev}/lib/modules/${kernel.modDirVersion}/build";
INSTALL_MOD_PATH = placeholder "out";
nativeBuildInputs = kernel.moduleBuildDependencies;
setSourceRoot = ''
tar xf Blackmagic_Desktop_Video_Linux_12.2.2/other/x86_64/desktopvideo-12.2.2a6-x86_64.tar.gz
sourceRoot=$NIX_BUILD_TOP/desktopvideo-12.2.2a6-x86_64/usr/src
'';
buildPhase = ''
runHook preBuild
make -C $sourceRoot/blackmagic-12.2.2a6 -j$NIX_BUILD_CORES
make -C $sourceRoot/blackmagic-io-12.2.2a6 -j$NIX_BUILD_CORES
runHook postBuild
'';
installPhase = ''
runHook preInstall
make -C $KERNELDIR M=$sourceRoot/blackmagic-12.2.2a6 modules_install
make -C $KERNELDIR M=$sourceRoot/blackmagic-io-12.2.2a6 modules_install
runHook postInstall
'';
meta = with lib; {
homepage = "https://www.blackmagicdesign.com/support/family/capture-and-playback";
maintainers = [ maintainers.hexchen ];
license = licenses.unfree;
description = "Kernel module for the Blackmagic Design Decklink cards";
platforms = platforms.linux;
};
}

View file

@ -1,68 +1,25 @@
{ config ? {}, system ? builtins.currentSystem, ... }@args:
{ nixpkgs ? <nixpkgs>, ... }:
let
sources = import ../nix/sources.nix;
pkgs = import sources.nixpkgs args;
unstable = import sources.nixpkgs-unstable args;
pkgs = import nixpkgs {};
callPackage = pkgs.lib.callPackageWith (pkgs // newpkgs);
newpkgs = {
alps = callPackage ./alps {};
companion = callPackage ./companion {};
libvips = callPackage ./libvips {};
docker = pkgs.docker.overrideAttrs (super: {
moby = super.moby.overrideAttrs (super: {
extraPath = super.extraPath + ":${pkgs.zfs}/bin";
});
});
linuxPackagesFor = kernel: (pkgs.linuxPackagesFor kernel).extend (_: ksuper: {
decklink = callPackage ./decklink { kernel = ksuper.kernel; };
});
blackmagicDesktopVideo = callPackage ./blackmagic-desktop-video { };
obs-studio = unstable.obs-studio.overrideAttrs (_: rec {
wrapLibraries = with (pkgs // newpkgs); [
xorg.libX11.out
libvlc
blackmagicDesktopVideo
libcxx
libcxxabi
];
postInstall = ''
wrapProgram $out/bin/obs \
--prefix "LD_LIBRARY_PATH" : "${pkgs.lib.makeLibraryPath wrapLibraries}"
'';
});
mattermost = callPackage ./mattermost {};
# a version of the lounge with some extra css that
# hides things the hacc-voc doesn't need
thelounge-hacked = pkgs.stdenv.mkDerivation {
name = "thelounge-hacked";
src = pkgs.thelounge;
phases = [ "buildPhase" "installPhase" ];
buildPhase = ''
cp $src/* -r .
chmod 777 lib/node_modules/thelounge/public/css/style.css
cat ${./thelounge/css-patch.css} >> lib/node_modules/thelounge/public/css/style.css
'';
installPhase = ''
mkdir -p $out
cp * -r $out
'';
};
uffd = callPackage ./uffd {};
inherit (unstable) bottom vaultwarden vaultwarden-vault;
wasiSrc = fetchGit {
url = "https://gitlab.infra4future.de/wasi/wasi-rust";
rev = "356dbc23a3683d134f13156af71baeaa06fb80d1";
};
in pkgs.extend(_: _: newpkgs)
immaeNix = fetchGit {
url = "https://git.immae.eu/perso/Immae/Config/Nix.git";
rev = "7ad4966f41db0669a77c7a6ee7f87f0d4e586b0c";
};
newpkgs = {
# package = callPackage ./package {};
wasi = import wasiSrc { inherit wasiSrc; pkgs = pkgs // newpkgs; };
peertube = callPackage ./peertube { mylibs = import "${immaeNix}/lib" { inherit pkgs; }; };
alps = callPackage ./alps {};
funkwhale = callPackage ./funkwhale {};
};
in newpkgs

View file

@ -0,0 +1,47 @@
{ stdenv, fetchurl, unzip }:
# Look for the correct urls for build_front and build_api artifacts on the tags page of the project : https://dev.funkwhale.audio/funkwhale/funkwhale/pipelines?scope=tags
# Attention : do not use the url "https://dev.funkwhale.audio/funkwhale/funkwhale/-/jobs/artifacts/${release}/download?job=" : it is not guaranteed to be stable
let
release = "1.0.1";
srcs = {
api = fetchurl {
url = https://dev.funkwhale.audio/funkwhale/funkwhale/-/jobs/56793/artifacts/download;
name = "api.zip";
sha256 = "0p21r8kbn7sr33chp7404fi9pm4yz6qhfz4z7gxf3vamg9fbsbsc";
};
frontend = fetchurl {
url = https://dev.funkwhale.audio/funkwhale/funkwhale/-/jobs/56790/artifacts/download;
name = "frontend.zip";
sha256 = "0hz4d59sva6zi5q53wj3f6yaw5didcl9z148s6rsy2m6gyr8566d";
};
};
in stdenv.mkDerivation {
name = "funkwhale";
version = "${release}";
src = srcs.api;
nativeBuildInputs = [ unzip ];
postPatch = ''
substituteInPlace requirements/base.txt \
--replace "django-cleanup==3.2.0" django-cleanup
'';
installPhase = ''
mkdir $out
cp -R ./* $out
unzip ${srcs.frontend} -d $out
mv $out/front/ $out/front_tmp
mv $out/front_tmp/dist $out/front
rmdir $out/front_tmp
'';
meta = with stdenv.lib; {
description = "A modern, convivial and free music server";
homepage = https://funkwhale.audio/;
license = licenses.agpl3;
platforms = platforms.linux;
maintainers = with maintainers; [ mmai ];
};
}

View file

@ -1,18 +0,0 @@
{
stdenv, fetchurl, pkg-config, glib, expat,
libjpeg_turbo, libexif, librsvg, libtiff, libpng
}:
stdenv.mkDerivation rec {
pname = "libvips";
version = "8.11.3";
src = fetchurl {
url = "https://github.com/libvips/libvips/releases/download/v${version}/vips-${version}.tar.gz";
sha256 = "00fz7h7vb0qqsc9i2smp3aljwjyb5cin2fiqillv8vvx8wpis2lv";
};
propagatedBuildInputs = [ glib ];
buildInputs = [ expat libjpeg_turbo libexif librsvg libtiff libpng ];
nativeBuildInputs = [ pkg-config ];
}

View file

@ -1,49 +0,0 @@
{ stdenv, fetchurl, fetchFromGitHub, buildGoPackage, buildEnv, lib }:
let
sources = import ../../nix/sources.nix;
version = sources.mattermost-webapp.version;
mattermost-server = buildGoPackage rec {
pname = "mattermost-server";
inherit version;
src = sources.mattermost-server.outPath;
goPackagePath = "github.com/mattermost/mattermost-server";
ldflags = [
"-X ${goPackagePath}/model.BuildNumber=nixpkgs-${version}"
];
};
mattermost-webapp = stdenv.mkDerivation {
pname = "mattermost-webapp";
inherit version;
src = sources.mattermost-webapp;
installPhase = ''
mkdir -p $out
cp -r client $out
cp -r i18n $out
cp -r fonts $out
cp -r templates $out
cp -r config $out
'';
};
in
buildEnv {
name = "mattermost-${version}";
paths = [ mattermost-server mattermost-webapp ];
meta = with lib; {
description = "Open-source, self-hosted Slack-alternative";
homepage = "https://www.mattermost.org";
license = with licenses; [ agpl3 asl20 ];
maintainers = with maintainers; [ fpletz ryantm ];
platforms = platforms.unix;
};
}

File diff suppressed because it is too large Load diff

207
pkgs/peertube/default.nix Normal file
View file

@ -0,0 +1,207 @@
{ ldap ? false, sendmail ? false, light ? null, syden ? false, runCommand, libsass
, lib, stdenv, rsync, fetchzip, youtube-dl, fetchurl, mylibs, python, nodejs, nodePackages, yarn2nix-moretea }:
let
nodeHeaders = fetchurl {
url = "https://nodejs.org/download/release/v${nodejs.version}/node-v${nodejs.version}-headers.tar.gz";
sha256 = "17kf05a92r4y4n1lj78265wr6zhkpzbr1k8nbwrl8sq71npd6n5j";
};
source = mylibs.fetchedGithub ./peertube.json;
patchedSource = stdenv.mkDerivation (source // rec {
phases = [ "unpackPhase" "patchPhase" "installPhase" ];
patches = [ ./yarn_fix_http_node.patch ]
++ lib.optionals ldap [ ./ldap.patch ]
++ lib.optionals sendmail [ ./sendmail.patch ]
++ lib.optionals syden [ ./syden.patch ];
installPhase = ''
mkdir $out
cp -a . $out/
'';
});
serverPatchedPackage = runCommand "server-package" {} ''
mkdir -p $out
cp ${patchedSource}/package.json $out/
cp ${patchedSource}/yarn.lock $out/
'';
clientPatchedPackage = runCommand "client-package" {} ''
mkdir -p $out
cp ${patchedSource}/client/package.json $out/
cp ${patchedSource}/client/yarn.lock $out/
'';
yarnModulesConfig = {
bcrypt = {
buildInputs = [ nodePackages.node-pre-gyp ];
postInstall = let
node_module_version = "72";
bcrypt_lib = fetchurl {
url = "https://github.com/kelektiv/node.bcrypt.js/releases/download/v3.0.7/bcrypt_lib-v3.0.7-node-v${node_module_version}-linux-x64-glibc.tar.gz";
sha256 = "0kpm9j0yc4lqsafldfsql3m72rr1fapljlb6ddxvy3zi13rb7ppx";
};
in
''
if [ "$(node -e "console.log(process.versions.modules)")" != "${node_module_version}" ]; then
echo "mismatching version with nodejs please update bcrypt derivation"
false
fi
mkdir lib && tar -C lib -xf ${bcrypt_lib}
patchShebangs ../node-pre-gyp
npm run install
'';
};
dtrace-provider = {
buildInputs = [ python nodePackages.node-gyp ];
postInstall = ''
npx node-gyp rebuild --tarball=${nodeHeaders}
'';
};
node-sass = {
buildInputs = [ libsass python ];
postInstall =
''
node scripts/build.js --tarball=${nodeHeaders}
'';
};
sharp = {
buildInputs = [ python nodePackages.node-gyp ];
postInstall =
let
tarball = fetchurl {
url = "https://github.com/lovell/sharp-libvips/releases/download/v8.8.1/libvips-8.8.1-linux-x64.tar.gz";
sha256 = "0xqv61g6s6rkvc31zq9a3bf8rp56ijnpw0xhr91hc88asqprd5yh";
};
in
''
mkdir vendor
tar -C vendor -xf ${tarball}
patchShebangs ../prebuild-install
npx node install/libvips
npx node install/dll-copy
npx prebuild-install || npx node-gyp rebuild --tarball=${nodeHeaders}
'';
};
utf-8-validate = {
buildInputs = [ nodePackages.node-gyp-build ];
};
youtube-dl = {
postInstall = ''
mkdir bin
ln -s ${youtube-dl}/bin/youtube-dl bin/youtube-dl
cat > bin/details <<EOF
{"version":"${youtube-dl.version}","path":null,"exec":"youtube-dl"}
EOF
'';
};
};
serverYarnModulesArg = rec {
pname = "peertube-server-yarn-modules";
version = source.version;
name = "${pname}-${version}";
packageJSON = "${serverPatchedPackage}/package.json";
yarnLock = "${serverPatchedPackage}/yarn.lock";
yarnNix = ./server-yarn-packages.nix;
pkgConfig = yarnModulesConfig;
};
clientYarnModulesArg = rec {
pname = "peertube-client-yarn-modules";
version = source.version;
name = "${pname}-${version}";
packageJSON = "${clientPatchedPackage}/package.json";
yarnLock = "${clientPatchedPackage}/yarn.lock";
yarnNix = ./client-yarn-packages.nix;
pkgConfig = yarnModulesConfig;
};
yarnModulesNoWorkspace = args: (yarn2nix-moretea.mkYarnModules args).overrideAttrs(old: {
buildPhase = builtins.replaceStrings [" ./package.json"] [" /dev/null; cp deps/*/package.json ."] old.buildPhase;
});
patchedPackages = stdenv.mkDerivation (source // rec {
patches = if ldap then [ ./ldap.patch ] else [ ./yarn_fix_http_node.patch ];
installPhase = ''
mkdir $out
cp package.json yarn.lock $out/
'';
});
serverYarnModules = yarnModulesNoWorkspace serverYarnModulesArg;
serverYarnModulesProd = yarnModulesNoWorkspace (serverYarnModulesArg // { yarnFlags = yarn2nix-moretea.defaultYarnFlags ++ [ "--production" ]; });
clientYarnModules = yarnModulesNoWorkspace clientYarnModulesArg;
server = stdenv.mkDerivation ({
pname = "peertube-server";
version = source.version;
src = patchedSource;
buildPhase = ''
ln -s ${serverYarnModules}/node_modules .
npm run build:server
'';
installPhase = ''
mkdir $out
cp -a dist $out
'';
buildInputs = [ nodejs serverYarnModules ];
});
client = stdenv.mkDerivation ({
pname = "peertube-client";
version = source.version;
src = patchedSource;
buildPhase = let
lightArg = if light == null then "" else if light == true then "--light" else "--light-language";
in ''
ln -s ${serverYarnModules}/node_modules .
cp -a ${clientYarnModules}/node_modules client/
chmod +w client/node_modules
patchShebangs .
npm run build:client -- ${lightArg}
'';
installPhase = ''
mkdir $out
cp -a client/dist $out
'';
buildInputs = [ nodejs clientYarnModules ];
});
package = stdenv.mkDerivation rec {
version = source.version;
pname = "peertube";
src = patchedSource;
buildPhase = ''
ln -s ${serverYarnModulesProd}/node_modules .
ln -s ${clientYarnModules}/node_modules client/
rm -rf dist && cp -a ${server}/dist dist
rm -rf client/dist && cp -a ${client}/dist client/
'';
installPhase = ''
mkdir $out
cp -a * $out
ln -s /tmp $out/.cache
'';
meta = {
description = "A free software to take back control of your videos";
longDescription = ''
PeerTube aspires to be a decentralized and free/libre alternative to video
broadcasting services.
PeerTube is not meant to become a huge platform that would centralize
videos from all around the world. Rather, it is a network of
inter-connected small videos hosters.
Anyone with a modicum of technical skills can host a PeerTube server, aka
an instance. Each instance hosts its users and their videos. In this way,
every instance is created, moderated and maintained independently by
various administrators.
You can still watch from your account videos hosted by other instances
though if the administrator of your instance had previously connected it
with other instances.
'';
license = stdenv.lib.licenses.agpl3Plus;
homepage = "https://joinpeertube.org/";
platforms = stdenv.lib.platforms.linux; # not sure here
maintainers = with stdenv.lib.maintainers; [ matthiasbeyer immae ];
};
};
in
package

597
pkgs/peertube/ldap.patch Normal file
View file

@ -0,0 +1,597 @@
commit ffb4a59047a014d6bb050b67a2fc7bc116be4682
Author: Ismaël Bouya <ismael.bouya@normalesup.org>
Date: Tue Feb 12 18:47:53 2019 +0100
Add LDAP authentication
diff --git a/config/default.yaml b/config/default.yaml
index 3260c62fc..dcce721b9 100644
--- a/config/default.yaml
+++ b/config/default.yaml
@@ -51,6 +51,19 @@ redis:
auth: null
db: 0
+auth:
+ local:
+ enabled: true
+ ldap:
+ enabled: true
+ url: ldap://localhost:389/dc=example,dc=com
+ insecure_tls: false
+ bind_dn: cn=admin,dc=example,dc=com
+ bind_password: adminPass
+ base: dc=example,dc=com
+ mail_entry: "mail"
+ user_filter: "(|(email=%username%)(uid=%username%))"
+
smtp:
hostname: null
port: 465
diff --git a/config/production.yaml.example b/config/production.yaml.example
index 30cd2ffe0..c56691bf4 100644
--- a/config/production.yaml.example
+++ b/config/production.yaml.example
@@ -51,6 +51,19 @@ redis:
auth: null
db: 0
+auth:
+ local:
+ enabled: true
+ ldap:
+ enabled: true
+ url: ldap://localhost:389/dc=example,dc=com
+ insecure_tls: false
+ bind_dn: cn=admin,dc=example,dc=com
+ bind_password: adminPass
+ base: dc=example,dc=com
+ mail_entry: "mail"
+ user_filter: "(|(email=%username%)(uid=%username%))"
+
# SMTP server to send emails
smtp:
hostname: null
diff --git a/package.json b/package.json
index 49d9faf97..31eccf797 100644
--- a/package.json
+++ b/package.json
@@ -112,6 +112,7 @@
"iso-639-3": "^1.0.1",
"js-yaml": "^3.5.4",
"jsonld": "~2.0.1",
+ "ldapjs": "^1.0.2",
"lodash": "^4.17.10",
"lru-cache": "^5.1.1",
"magnet-uri": "^5.1.4",
diff --git a/server/initializers/config.ts b/server/initializers/config.ts
index 7fd77f3e8..45a667826 100644
--- a/server/initializers/config.ts
+++ b/server/initializers/config.ts
@@ -34,6 +34,21 @@ const CONFIG = {
AUTH: config.has('redis.auth') ? config.get<string>('redis.auth') : null,
DB: config.has('redis.db') ? config.get<number>('redis.db') : null
},
+ AUTH: {
+ LOCAL: {
+ ENABLED: config.has('auth.local.enabled') ? config.get<boolean>('auth.local.enabled') : true,
+ },
+ LDAP: {
+ ENABLED: config.has('auth.ldap.enabled') ? config.get<boolean>('auth.ldap.enabled') : false,
+ URL: config.has('auth.ldap.url') ? config.get<string>('auth.ldap.url') : null,
+ INSECURE_TLS: config.has('auth.ldap.insecure_tls') ? config.get<boolean>('auth.ldap.insecure_tls') : false,
+ BIND_DN: config.has('auth.ldap.bind_dn') ? config.get<string>('auth.ldap.bind_dn') : null,
+ BIND_PASSWORD: config.has('auth.ldap.bind_password') ? config.get<string>('auth.ldap.bind_password') : null,
+ BASE: config.has('auth.ldap.base') ? config.get<string>('auth.ldap.base') : null,
+ MAIL_ENTRY: config.has('auth.ldap.mail_entry') ? config.get<string>('auth.ldap.mail_entry') : 'mail',
+ USER_FILTER: config.has('auth.ldap.user_filter') ? config.get<string>('auth.ldap.user_filter') : null
+ },
+ },
SMTP: {
HOSTNAME: config.get<string>('smtp.hostname'),
PORT: config.get<number>('smtp.port'),
diff --git a/server/initializers/migrations/0375-user-ldap-dn.ts b/server/initializers/migrations/0375-user-ldap-dn.ts
new file mode 100644
index 000000000..a9d68124b
--- /dev/null
+++ b/server/initializers/migrations/0375-user-ldap-dn.ts
@@ -0,0 +1,26 @@
+import * as Sequelize from 'sequelize'
+
+async function up (utils: {
+ transaction: Sequelize.Transaction,
+ queryInterface: Sequelize.QueryInterface,
+ sequelize: Sequelize.Sequelize
+}): Promise<void> {
+
+ {
+ const data = {
+ type: Sequelize.STRING,
+ allowNull: true,
+ defaultValue: null
+ }
+ await utils.queryInterface.addColumn('user', 'ldapDn', data)
+ }
+}
+
+function down (options) {
+ throw new Error('Not implemented.')
+}
+
+export {
+ up,
+ down
+}
diff --git a/server/lib/ldap.ts b/server/lib/ldap.ts
new file mode 100644
index 000000000..e6601e5cb
--- /dev/null
+++ b/server/lib/ldap.ts
@@ -0,0 +1,89 @@
+import * as express from 'express'
+import { createClient, Client, parseFilter } from 'ldapjs'
+import { logger } from '../helpers/logger'
+import { CONFIG } from '../initializers/config'
+
+class Ldap {
+
+ private static instance: Ldap
+ private initialized = false
+ private client: Client
+ private prefix: string
+
+ private constructor () {}
+
+ init () {
+ // Already initialized
+ if (this.initialized === true) return
+ this.initialized = true
+
+ this.client = createClient(Ldap.getLdapClientOptions())
+ }
+
+ static getLdapClientOptions () {
+ return Object.assign({}, {
+ url: CONFIG.AUTH.LDAP.URL,
+ reconnect: true,
+ tlsOptions: { rejectUnauthorized: !CONFIG.AUTH.LDAP.INSECURE_TLS }
+ })
+ }
+
+ getClient () {
+ this.init()
+ return this.client
+ }
+
+ findUser (username: string) {
+ const filter = parseFilter(CONFIG.AUTH.LDAP.USER_FILTER)
+ filter.forEach(function (element) {
+ if (element.value === '%username%') element.value = username
+ })
+ const opts = {
+ filter,
+ scope: 'sub',
+ attributes: [ CONFIG.AUTH.LDAP.MAIL_ENTRY, 'dn' ]
+ }
+
+ const client = this.getClient()
+
+ return new Promise(function (resolve, reject) {
+ client.bind(CONFIG.AUTH.LDAP.BIND_DN, CONFIG.AUTH.LDAP.BIND_PASSWORD, function (err) {
+ if (err) reject(err)
+ let entries = []
+ client.search(CONFIG.AUTH.LDAP.BASE, opts, function (err, search) {
+ if (err) reject(err)
+ search.on('searchEntry', function (entry) {
+ entries.push(entry.object)
+ })
+ search.on('end', function (result) {
+ if (entries.length === 1) {
+ resolve(entries[0])
+ } else {
+ reject("No user found corresponding to this username")
+ }
+ })
+ })
+ })
+ })
+ }
+
+ checkUser (dn: string, password: string) {
+ const client = this.getClient()
+ return new Promise(function (resolve, reject) {
+ client.bind(dn, password, function (err) {
+ resolve(!err)
+ })
+ })
+ }
+
+
+ static get Instance () {
+ return this.instance || (this.instance = new this())
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+ Ldap
+}
diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts
index 086856f41..ab10effd0 100644
--- a/server/lib/oauth-model.ts
+++ b/server/lib/oauth-model.ts
@@ -9,6 +9,7 @@ import { Transaction } from 'sequelize'
import { CONFIG } from '../initializers/config'
import * as LRUCache from 'lru-cache'
import { MOAuthTokenUser } from '@server/typings/models/oauth/oauth-token'
+import { MUserDefault } from '@server/typings/models'
type TokenInfo = { accessToken: string, refreshToken: string, accessTokenExpiresAt: Date, refreshTokenExpiresAt: Date }
@@ -74,7 +75,13 @@ function getRefreshToken (refreshToken: string) {
async function getUser (usernameOrEmail: string, password: string) {
logger.debug('Getting User (username/email: ' + usernameOrEmail + ', password: ******).')
- const user = await UserModel.loadByUsernameOrEmail(usernameOrEmail)
+ let user : MUserDefault
+ if (CONFIG.AUTH.LDAP.ENABLED) {
+ user = await UserModel.findOrCreateLDAPUser(usernameOrEmail)
+ }
+ if (!user && CONFIG.AUTH.LOCAL.ENABLED) {
+ user = await UserModel.loadByUsernameOrEmail(usernameOrEmail)
+ }
if (!user) return null
const passwordMatch = await user.isPasswordMatch(password)
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 4c2c5e278..0b38f7cb2 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -1,4 +1,5 @@
import { FindOptions, literal, Op, QueryTypes, where, fn, col } from 'sequelize'
+import { Ldap } from '../../lib/ldap'
import {
AfterDestroy,
AfterUpdate,
@@ -50,7 +51,9 @@ import { AccountModel } from './account'
import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type'
import { values } from 'lodash'
import { DEFAULT_THEME_NAME, DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants'
+import { CONFIG } from '../../initializers/config'
import { clearCacheByUserId } from '../../lib/oauth-model'
+import { createUserAccountAndChannelAndPlaylist } from '../../lib/user'
import { UserNotificationSettingModel } from './user-notification-setting'
import { VideoModel } from '../video/video'
import { ActorModel } from '../activitypub/actor'
@@ -149,6 +152,11 @@ export class UserModel extends Model<UserModel> {
@Column(DataType.STRING(400))
pendingEmail: string
+ @AllowNull(true)
+ @Default(null)
+ @Column
+ ldapDn: string
+
@AllowNull(true)
@Default(null)
@Is('UserEmailVerified', value => throwIfNotValid(value, isUserEmailVerifiedValid, 'email verified boolean', true))
@@ -440,6 +448,48 @@ export class UserModel extends Model<UserModel> {
return UserModel.findOne(query)
}
+ static loadByLdapDn (ldapDn: string) {
+ const query = {
+ where: {
+ ldapDn
+ }
+ }
+
+ return UserModel.findOne(query)
+ }
+
+ static async findOrCreateLDAPUser (username: string) {
+ try {
+ const userInfos = await Ldap.Instance.findUser(username)
+ const user = await UserModel.loadByLdapDn(userInfos['dn'])
+ if (user) {
+ return user
+ } else {
+ return await UserModel.createLDAPUser(username, userInfos)
+ }
+ } catch (e) {
+ return null
+ }
+ }
+
+ static async createLDAPUser (username: string, userInfos: {}) {
+ const userToCreate = new UserModel({
+ username,
+ password: 'SomeInvalidPassword',
+ email: userInfos[CONFIG.AUTH.LDAP.MAIL_ENTRY],
+ ldapDn: userInfos['dn'],
+ nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
+ autoPlayVideo: true,
+ role: UserRole.USER,
+ videoQuota: CONFIG.USER.VIDEO_QUOTA,
+ videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY,
+ emailVerified: true,
+ adminFlags: UserAdminFlag.NONE
+ })
+ const { user } = await createUserAccountAndChannelAndPlaylist({ userToCreate })
+ return user
+ }
+
static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> {
const query = {
where: {
@@ -627,7 +677,11 @@ export class UserModel extends Model<UserModel> {
}
isPasswordMatch (password: string) {
- return comparePassword(password, this.password)
+ if (this.ldapDn === null) {
+ return comparePassword(password, this.password)
+ } else {
+ return Ldap.Instance.checkUser(this.ldapDn, password)
+ }
}
toFormattedJSON (this: MUserFormattable, parameters: { withAdminFlags?: boolean } = {}): User {
diff --git a/yarn.lock b/yarn.lock
index 76ce7ed27..f087746df 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -616,6 +616,11 @@ arraybuffer.slice@~0.0.7:
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==
+asn1@0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+ integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=
+
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
@@ -623,6 +628,11 @@ asn1@~0.2.3:
dependencies:
safer-buffer "~2.1.0"
+assert-plus@0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160"
+ integrity sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=
+
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
@@ -692,6 +702,13 @@ backo2@1.0.2:
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
+backoff@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f"
+ integrity sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=
+ dependencies:
+ precond "0.2"
+
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
@@ -1001,6 +1018,16 @@ bull@^3.4.2:
util.promisify "^1.0.0"
uuid "^3.3.3"
+bunyan@^1.8.3:
+ version "1.8.12"
+ resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.12.tgz#f150f0f6748abdd72aeae84f04403be2ef113797"
+ integrity sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=
+ optionalDependencies:
+ dtrace-provider "~0.8"
+ moment "^2.10.6"
+ mv "~2"
+ safe-json-stringify "~1"
+
busboy@^0.2.11:
version "0.2.14"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
@@ -1619,7 +1646,7 @@ d@1, d@^1.0.1:
es5-ext "^0.10.50"
type "^1.0.1"
-dashdash@^1.12.0:
+dashdash@^1.12.0, dashdash@^1.14.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
@@ -1845,6 +1872,13 @@ double-ended-queue@^2.1.0-0:
resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=
+dtrace-provider@~0.8:
+ version "0.8.8"
+ resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.8.tgz#2996d5490c37e1347be263b423ed7b297fb0d97e"
+ integrity sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==
+ dependencies:
+ nan "^2.14.0"
+
duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
@@ -2228,6 +2262,11 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.2:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+extsprintf@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.2.0.tgz#5ad946c22f5b32ba7f8cd7426711c6e8a3fc2529"
+ integrity sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk=
+
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@@ -2567,6 +2606,17 @@ glob@7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
+glob@^6.0.1:
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
+ integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=
+ dependencies:
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "2 || 3"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
glob@^7.0.3, glob@^7.1.1, glob@^7.1.3:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
@@ -3356,6 +3406,30 @@ latest-version@^3.0.0:
dependencies:
package-json "^4.0.0"
+ldap-filter@0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/ldap-filter/-/ldap-filter-0.2.2.tgz#f2b842be0b86da3352798505b31ebcae590d77d0"
+ integrity sha1-8rhCvguG2jNSeYUFsx68rlkNd9A=
+ dependencies:
+ assert-plus "0.1.5"
+
+ldapjs@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/ldapjs/-/ldapjs-1.0.2.tgz#544ff7032b7b83c68f0701328d9297aa694340f9"
+ integrity sha1-VE/3Ayt7g8aPBwEyjZKXqmlDQPk=
+ dependencies:
+ asn1 "0.2.3"
+ assert-plus "^1.0.0"
+ backoff "^2.5.0"
+ bunyan "^1.8.3"
+ dashdash "^1.14.0"
+ ldap-filter "0.2.2"
+ once "^1.4.0"
+ vasync "^1.6.4"
+ verror "^1.8.1"
+ optionalDependencies:
+ dtrace-provider "~0.8"
+
libxmljs@0.19.7:
version "0.19.7"
resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.7.tgz#96c2151b0b73f33dd29917edec82902587004e5a"
@@ -3724,7 +3798,7 @@ mimic-response@^2.0.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46"
integrity sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ==
-minimatch@3.0.4, minimatch@^3.0.4:
+"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -3825,7 +3899,7 @@ moment-timezone@^0.5.21, moment-timezone@^0.5.25:
dependencies:
moment ">= 2.9.0"
-"moment@>= 2.9.0", moment@^2.24.0:
+"moment@>= 2.9.0", moment@^2.10.6, moment@^2.24.0:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
@@ -3898,6 +3972,15 @@ mute-stream@~0.0.4:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
+mv@~2:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2"
+ integrity sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=
+ dependencies:
+ mkdirp "~0.5.1"
+ ncp "~2.0.0"
+ rimraf "~2.4.0"
+
nan@2.14.0, nan@^2.14.0, nan@~2.14.0:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
@@ -3913,6 +3996,11 @@ ncp@1.0.x:
resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246"
integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=
+ncp@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
+ integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
+
needle@^2.2.1:
version "2.4.0"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
@@ -4597,6 +4685,11 @@ prebuild-install@^5.3.3:
tunnel-agent "^0.6.0"
which-pm-runs "^1.0.0"
+precond@0.2:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac"
+ integrity sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=
+
prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@@ -5032,6 +5125,13 @@ rimraf@^3.0.0:
dependencies:
glob "^7.1.3"
+rimraf@~2.4.0:
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da"
+ integrity sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=
+ dependencies:
+ glob "^6.0.1"
+
run-parallel-limit@^1.0.3:
version "1.0.5"
resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7"
@@ -5069,6 +5169,11 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2,
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+safe-json-stringify@~1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd"
+ integrity sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==
+
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
@@ -6337,7 +6442,14 @@ vary@^1, vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
-verror@1.10.0:
+vasync@^1.6.4:
+ version "1.6.4"
+ resolved "https://registry.yarnpkg.com/vasync/-/vasync-1.6.4.tgz#dfe93616ad0e7ae801b332a9d88bfc5cdc8e1d1f"
+ integrity sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8=
+ dependencies:
+ verror "1.6.0"
+
+verror@1.10.0, verror@^1.8.1:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
@@ -6346,6 +6458,13 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
+verror@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/verror/-/verror-1.6.0.tgz#7d13b27b1facc2e2da90405eb5ea6e5bdd252ea5"
+ integrity sha1-fROyex+swuLakEBetepuW90lLqU=
+ dependencies:
+ extsprintf "1.2.0"
+
videostream@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/videostream/-/videostream-3.2.1.tgz#643688ad4bfbf37570d421e3196b7e0ad38eeebc"

View file

@ -0,0 +1,15 @@
{
"tag": "v2.1.1",
"meta": {
"name": "peertube",
"url": "https://github.com/Chocobozzz/PeerTube",
"branch": "refs/tags/v2.1.1"
},
"github": {
"owner": "Chocobozzz",
"repo": "PeerTube",
"rev": "76f7b571c04c03ba422bd5790944fe80dbb24067",
"sha256": "147gm1j657fkpv2ix1bmkhl7ld5h224q7hgdj9ffj3z14mqgk8hj",
"fetchSubmodules": true
}
}

View file

@ -0,0 +1,121 @@
commit 486964fad93334a52fb05e7d0497ecac3eb684fe
Author: Ismaël Bouya <ismael.bouya@normalesup.org>
Date: Wed Feb 13 12:16:27 2019 +0100
Add sendmail
diff --git a/config/production.yaml.example b/config/production.yaml.example
index c56691bf4..8abdfb2a7 100644
--- a/config/production.yaml.example
+++ b/config/production.yaml.example
@@ -66,6 +66,8 @@ auth:
# SMTP server to send emails
smtp:
+ transport: smtp
+ sendmail: null
hostname: null
port: 465 # If you use StartTLS: 587
username: null
diff --git a/server/initializers/config.ts b/server/initializers/config.ts
index 45a667826..c1c15f05b 100644
--- a/server/initializers/config.ts
+++ b/server/initializers/config.ts
@@ -50,6 +50,8 @@ const CONFIG = {
},
},
SMTP: {
+ TRANSPORT: config.has('smtp.transport') ? config.get<string>('smtp.transport') : 'smtp',
+ SENDMAIL: config.has('smtp.sendmail') ? config.get<string>('smtp.sendmail') : null,
HOSTNAME: config.get<string>('smtp.hostname'),
PORT: config.get<number>('smtp.port'),
USERNAME: config.get<string>('smtp.username'),
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts
index 7484524a4..512c5c068 100644
--- a/server/lib/emailer.ts
+++ b/server/lib/emailer.ts
@@ -40,33 +40,41 @@ class Emailer {
this.initialized = true
if (Emailer.isEnabled()) {
- logger.info('Using %s:%s as SMTP server.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT)
-
- let tls
- if (CONFIG.SMTP.CA_FILE) {
- tls = {
- ca: [ readFileSync(CONFIG.SMTP.CA_FILE) ]
+ if (CONFIG.SMTP.TRANSPORT === 'smtp') {
+ logger.info('Using %s:%s as SMTP server.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT)
+
+ let tls
+ if (CONFIG.SMTP.CA_FILE) {
+ tls = {
+ ca: [ readFileSync(CONFIG.SMTP.CA_FILE) ]
+ }
}
- }
- let auth
- if (CONFIG.SMTP.USERNAME && CONFIG.SMTP.PASSWORD) {
- auth = {
- user: CONFIG.SMTP.USERNAME,
- pass: CONFIG.SMTP.PASSWORD
+ let auth
+ if (CONFIG.SMTP.USERNAME && CONFIG.SMTP.PASSWORD) {
+ auth = {
+ user: CONFIG.SMTP.USERNAME,
+ pass: CONFIG.SMTP.PASSWORD
+ }
}
- }
- this.transporter = createTransport({
- host: CONFIG.SMTP.HOSTNAME,
- port: CONFIG.SMTP.PORT,
- secure: CONFIG.SMTP.TLS,
- debug: CONFIG.LOG.LEVEL === 'debug',
- logger: bunyanLogger as any,
- ignoreTLS: CONFIG.SMTP.DISABLE_STARTTLS,
- tls,
- auth
- })
+ this.transporter = createTransport({
+ host: CONFIG.SMTP.HOSTNAME,
+ port: CONFIG.SMTP.PORT,
+ secure: CONFIG.SMTP.TLS,
+ debug: CONFIG.LOG.LEVEL === 'debug',
+ logger: bunyanLogger as any,
+ ignoreTLS: CONFIG.SMTP.DISABLE_STARTTLS,
+ tls,
+ auth
+ })
+ } else { // sendmail
+ this.transporter = createTransport({
+ sendmail: true,
+ newline: 'unix',
+ path: CONFIG.SMTP.SENDMAIL,
+ })
+ }
} else {
if (!isTestInstance()) {
logger.error('Cannot use SMTP server because of lack of configuration. PeerTube will not be able to send mails!')
@@ -75,11 +83,17 @@ class Emailer {
}
static isEnabled () {
- return !!CONFIG.SMTP.HOSTNAME && !!CONFIG.SMTP.PORT
+ if (CONFIG.SMTP.TRANSPORT === 'sendmail') {
+ return !!CONFIG.SMTP.SENDMAIL
+ } else if (CONFIG.SMTP.TRANSPORT === 'smtp') {
+ return !!CONFIG.SMTP.HOSTNAME && !!CONFIG.SMTP.PORT
+ } else {
+ return false
+ }
}
async checkConnectionOrDie () {
- if (!this.transporter) return
+ if (!this.transporter || CONFIG.SMTP.TRANSPORT !== 'smtp') return
logger.info('Testing SMTP server...')

File diff suppressed because it is too large Load diff

211
pkgs/peertube/syden.patch Normal file
View file

@ -0,0 +1,211 @@
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
index b07b9c1a6..2e69c1de3 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
@@ -16,22 +16,10 @@
#videosSelection
>
<ng-template ptTemplate="globalButtons">
- <span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
- <my-global-icon iconName="delete"></my-global-icon>
- <ng-container i18n>Delete</ng-container>
- </span>
</ng-template>
<ng-template ptTemplate="rowButtons" let-video>
- <my-delete-button (click)="deleteVideo(video)"></my-delete-button>
-
<my-edit-button [routerLink]="[ '/videos', 'update', video.uuid ]"></my-edit-button>
-
- <my-button i18n-label label="Change ownership"
- className="action-button-change-ownership grey-button"
- icon="im-with-her"
- (click)="changeOwnership($event, video)"
- ></my-button>
</ng-template>
</my-videos-selection>
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index 9ae008e39..58366de41 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -147,6 +147,7 @@ export class AuthService {
login (username: string, password: string) {
// Form url encoded
+ if (this.isLoggedIn()) this.logout()
const body = {
client_id: this.clientId,
client_secret: this.clientSecret,
diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts
index 580f28822..1d2d1873c 100644
--- a/client/src/app/login/login.component.ts
+++ b/client/src/app/login/login.component.ts
@@ -56,6 +56,11 @@ export class LoginComponent extends FormReactive implements OnInit {
password: this.loginValidatorsService.LOGIN_PASSWORD
})
+ if (!this.authService.isLoggedIn()) {
+ this.form.controls.username.setValue("invite")
+ this.form.controls.password.setValue("invite")
+ this.login()
+ }
this.input.nativeElement.focus()
}
diff --git a/client/src/app/shared/video/video-actions-dropdown.component.ts b/client/src/app/shared/video/video-actions-dropdown.component.ts
index afdeab18d..ee8a5929b 100644
--- a/client/src/app/shared/video/video-actions-dropdown.component.ts
+++ b/client/src/app/shared/video/video-actions-dropdown.component.ts
@@ -141,7 +141,7 @@ export class VideoActionsDropdownComponent implements OnChanges {
}
isVideoDownloadable () {
- return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled
+ return this.video && this.video instanceof VideoDetails && this.video.isDownloadableBy(this.user)
}
/* Action handlers */
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts
index fb98d5382..3098fc831 100644
--- a/client/src/app/shared/video/video.model.ts
+++ b/client/src/app/shared/video/video.model.ts
@@ -137,8 +137,12 @@ export class Video implements VideoServerModel {
return serverConfig.instance.defaultNSFWPolicy !== 'display'
}
+ isDownloadableBy (user: AuthUser) {
+ return user && this.isLocal === true && user.hasRight(UserRight.SEE_ALL_VIDEOS)
+ }
+
isRemovableBy (user: AuthUser) {
- return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO))
+ return user && this.isLocal === true && user.hasRight(UserRight.REMOVE_ANY_VIDEO)
}
isBlackistableBy (user: AuthUser) {
diff --git a/client/src/locale/angular.en-US.xlf b/client/src/locale/angular.en-US.xlf
index a87278e88..d4ad8522f 100644
--- a/client/src/locale/angular.en-US.xlf
+++ b/client/src/locale/angular.en-US.xlf
@@ -1071,7 +1071,7 @@
<source>
If you are looking for an account…
</source><target state="final">
- If you are looking for an account…
+ Open instance
</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/login/login.component.html</context>
@@ -1086,12 +1086,7 @@
Find yours among multiple instances at <x id="START_LINK" ctype="x-a" equiv-text="&lt;a>"/>https://joinpeertube.org/instances<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a>"/>.
</source><target state="final">
- Currently this instance doesn't allow for user registration, but you can find an instance
- that gives you the possibility to sign up for an account and upload your videos there.
-
- <x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/>"/>
-
- Find yours among multiple instances at <x id="START_LINK" ctype="x-a" equiv-text="&lt;a>"/>https://joinpeertube.org/instances<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a>"/>.
+ This instance doesn't allow for user registration, but it is open. You may connect with login "invite" and any password.
</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/login/login.component.html</context>
diff --git a/client/src/locale/angular.fr-FR.xlf b/client/src/locale/angular.fr-FR.xlf
index 6b58a1e1e..77ccc44fc 100644
--- a/client/src/locale/angular.fr-FR.xlf
+++ b/client/src/locale/angular.fr-FR.xlf
@@ -1074,7 +1074,7 @@
<trans-unit id="d780b02074a6317126378e0365e1066c890a3570" datatype="html">
<source>If you are looking for an account…</source>
<target state="new">
- If you are looking for an account…
+ Instance ouverte
</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/login/login.component.html</context>
@@ -1084,12 +1084,7 @@
<trans-unit id="79dacac459775e2cf163bce6c3f05ed814f82ba2" datatype="html">
<source>Currently this instance doesn't allow for user registration, but you can find an instance that gives you the possibility to sign up for an account and upload your videos there. <x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Find yours among multiple instances at <x id="START_LINK" ctype="x-a" equiv-text="&lt;a&gt;"/>https://joinpeertube.org/instances<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. </source>
<target state="new">
- Currently this instance doesn't allow for user registration, but you can find an instance
- that gives you the possibility to sign up for an account and upload your videos there.
-
- <x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/>
-
- Find yours among multiple instances at <x id="START_LINK" ctype="x-a" equiv-text="&lt;a&gt;"/>https://joinpeertube.org/instances<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>.
+ Cette instance ne permet pas de créer un compte, mais elle est ouverte. Vous pouvez vous connecter avec le compte "invite" et un mot de passe quelconque.
</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/login/login.component.html</context>
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 8d4ff07eb..4eb9354c3 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -26,6 +26,7 @@ import {
asyncMiddleware,
asyncRetryTransactionMiddleware,
authenticate,
+ ensureUserHasRight,
checkVideoFollowConstraints,
commonVideosFiltersValidator,
optionalAuthenticate,
@@ -39,6 +40,7 @@ import {
videosSortValidator,
videosUpdateValidator
} from '../../../middlewares'
+import { UserRight } from '../../../../shared'
import { TagModel } from '../../../models/video/tag'
import { VideoModel } from '../../../models/video/video'
import { VideoFileModel } from '../../../models/video/video-file'
@@ -141,6 +143,7 @@ videosRouter.post('/:id/views',
videosRouter.delete('/:id',
authenticate,
+ ensureUserHasRight(UserRight.REMOVE_ANY_VIDEO),
asyncMiddleware(videosRemoveValidator),
asyncRetryTransactionMiddleware(removeVideo)
)
diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts
index 086856f41..945f478dc 100644
--- a/server/lib/oauth-model.ts
+++ b/server/lib/oauth-model.ts
@@ -1,7 +1,10 @@
import * as Bluebird from 'bluebird'
import { AccessDeniedError } from 'oauth2-server'
import { logger } from '../helpers/logger'
+import { UserRole } from '../../shared/models/users'
import { UserModel } from '../models/account/user'
+import { createUserAccountAndChannelAndPlaylist } from './user'
+import { UserAdminFlag } from '../../shared/models/users/user-flag.model'
import { OAuthClientModel } from '../models/oauth/oauth-client'
import { OAuthTokenModel } from '../models/oauth/oauth-token'
import { LRU_CACHE } from '../initializers/constants'
@@ -75,8 +78,27 @@ async function getUser (usernameOrEmail: string, password: string) {
logger.debug('Getting User (username/email: ' + usernameOrEmail + ', password: ******).')
const user = await UserModel.loadByUsernameOrEmail(usernameOrEmail)
+ if (!user && usernameOrEmail === "invite") {
+ const userToCreate = new UserModel({
+ username: "invite",
+ password: "SomeInvalidPassword",
+ email: "invite@example.com",
+ nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
+ autoPlayVideo: true,
+ role: UserRole.USER,
+ videoQuota: CONFIG.USER.VIDEO_QUOTA,
+ videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY,
+ emailVerified: true,
+ adminFlags: UserAdminFlag.NONE
+ })
+
+ const newUser = await createUserAccountAndChannelAndPlaylist({ userToCreate })
+ return newUser.user
+ }
if (!user) return null
+ if (user.username === "invite") return user
+
const passwordMatch = await user.isPasswordMatch(password)
if (passwordMatch === false) return null

View file

@ -0,0 +1,26 @@
diff --git a/yarn.lock b/yarn.lock
index 76ce7ed27..f087746df 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2787,7 +2837,7 @@ http-errors@~1.7.2:
"http-node@github:feross/http-node#webtorrent":
version "1.2.0"
- resolved "https://codeload.github.com/feross/http-node/tar.gz/342ef8624495343ffd050bd0808b3750cf0e3974"
+ resolved "https://codeload.github.com/feross/http-node/tar.gz/342ef8624495343ffd050bd0808b3750cf0e3974#33fa312d37f0000b17acdb1a5086565400419a13"
dependencies:
chrome-net "^3.3.3"
freelist "^1.0.3"
diff --git a/client/yarn.lock b/client/yarn.lock
index 0855a2570..50f592f76 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -5164,7 +5164,7 @@ http-errors@~1.7.2:
"http-node@github:feross/http-node#webtorrent":
version "1.2.0"
- resolved "https://codeload.github.com/feross/http-node/tar.gz/342ef8624495343ffd050bd0808b3750cf0e3974"
+ resolved "https://codeload.github.com/feross/http-node/tar.gz/342ef8624495343ffd050bd0808b3750cf0e3974#33fa312d37f0000b17acdb1a5086565400419a13"
dependencies:
chrome-net "^3.3.3"
freelist "^1.0.3"

View file

@ -1,24 +0,0 @@
/* Hides extra fields on connect screen */
.connect-row:nth-of-type(4) {
display: none !important;
}
.connect-row:nth-of-type(2) {
display: none !important;
}
.connect-row:nth-of-type(5) {
display: none !important;
}
/* Hides side panel button */
.header > button:first-child {
display: none !important;
}
/* Hides channel options button (includes leave option) */
.header > button:nth-last-child(2) {
display: none !important;
}

View file

@ -1,34 +0,0 @@
{ stdenv, lib, python3Packages, fetchzip }:
python3Packages.buildPythonPackage rec {
pname = "uffd";
version = "2.0.1";
src = fetchzip {
url = "https://git.cccv.de/uffd/uffd/-/archive/v${version}/uffd-v${version}.tar.gz";
hash = "sha256-KP4J1bw5u7MklaPu2SBFRNyGgkKOBOpft5MMH+em5M4=";
};
patches = [ ./gitea-magic.patch ./fix-setuppy.patch ./fix-userinfo.patch ];
propagatedBuildInputs = with python3Packages; [
flask
flask_sqlalchemy
flask_migrate
qrcode
fido2
oauthlib
flask-babel
argon2_cffi
itsdangerous
alembic
Mako
];
postPatch = ''
sed -i -e 's/==[0-9.]\+//g' setup.py
'';
doCheck = false;
doInstallCheck = false;
}

View file

@ -1,34 +0,0 @@
--- a/setup.py 2022-04-30 13:12:45.564651955 +0000
+++ b/setup.py 2022-04-30 13:17:02.545809513 +0000
@@ -41,31 +41,5 @@
'Flask-Babel==0.11.2',
'alembic==1.0.0',
'argon2-cffi==18.3.0',
-
- # The main dependencies on their own lead to version collisions and pip is
- # not very good at resolving them, so we pin the versions from Debian Buster
- # for all dependencies.
- 'certifi==2018.8.24',
- #cffi==1.12.2'
- 'cffi # v1.12.2 no longer works with python3.9. Newer versions seem to work fine.',
- 'chardet==3.0.4',
- 'click==7.0',
- 'cryptography==2.6.1',
- 'idna==2.6',
- 'itsdangerous==0.24',
- 'Jinja2==2.10',
- 'MarkupSafe==1.1.0',
- 'oauthlib==2.1.0',
- 'pyasn1==0.4.2',
- 'pycparser==2.19',
- 'requests==2.21.0',
- 'requests-oauthlib==1.0.0',
- 'six==1.12.0',
- 'SQLAlchemy==1.2.18',
- 'urllib3==1.24.1',
- 'Werkzeug==0.14.1',
- 'python-dateutil==2.7.3',
- #editor==1.0.3
- 'Mako==1.0.7',
],
)

View file

@ -1,10 +0,0 @@
--- a/uffd/oauth2/views.py 2022-04-30 20:39:53.825474990 +0000
+++ b/uffd/oauth2/views.py 2022-04-30 20:40:12.632389377 +0000
@@ -234,6 +234,7 @@
id=user.unix_uid,
name=user.displayname,
nickname=user.loginname,
+ username=user.loginname,
email=user.mail,
groups=[group.name for group in user.groups]
)

View file

@ -1,32 +0,0 @@
From e3c0995160a653ef6cd8784b255036585b273b82 Mon Sep 17 00:00:00 2001
From: stuebinm <stuebinm@disroot.org>
Date: Wed, 20 Jul 2022 18:02:15 +0200
Subject: [PATCH] magic gitea patch
---
uffd/oauth2/views.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/uffd/oauth2/views.py b/uffd/oauth2/views.py
index d13fd42..94352be 100644
--- a/uffd/oauth2/views.py
+++ b/uffd/oauth2/views.py
@@ -230,6 +230,15 @@ def oauth_required(*scopes):
@oauth_required('profile')
def userinfo():
user = request.oauth.user
+ client = request.oauth.client_id
+ if client == "gitea":
+ return jsonify(
+ id=user.unix_uid,
+ full_name=user.displayname,
+ login=user.loginname,
+ email=user.mail,
+ groups=[group.name for group in user.groups]
+ )
return jsonify(
id=user.unix_uid,
name=user.displayname,
--
2.36.0

View file

@ -1,133 +0,0 @@
{ config, lib, pkgs, profiles, modules, evalConfig, sources, ... }:
{
containers.gitea = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.10";
autoStart = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/gitea";
isReadOnly = false;
};
};
path = (evalConfig {
hosts = { };
groups = { };
} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
imports = [ ((import sources.nix-hexchen) { }).profiles.nopersist ];
environment.systemPackages = [ pkgs.gitea ];
hexchen.bindmounts."/var/lib/gitea" = "/persist/gitea";
nixpkgs.config.allowUnfree = true;
networking.firewall.enable = false;
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
services.gitea = {
enable = true;
appName = "0x0: git for all creatures";
rootUrl = "https://git.infra4future.de/";
httpAddress = "0.0.0.0";
httpPort = 3000;
lfs.enable = true;
disableRegistration = true;
database.type = "postgres";
cookieSecure = true;
log.level = "Info";
# mailerPasswordFile =
# "/var/lib/secrets/noreply"; # see below for access permissions
settings = {
# mailer = {
# ENABLED = true;
# HOST = "0x0.rip:465";
# FROM = "noreply@0x0.rip";
# ENVELOPE_FROM = "noreply@0x0.rip";
# USER = "noreply@0x0.rip";
# };
repository = {
DEFAULT_PRIVATE = "public";
PREFERRED_LICENSES = "Unlicense";
DEFAULT_BRANCH = "main";
};
oauth2_client = {
ACCOUNT_LINKING = "auto";
ENABLE_AUTO_REGISTRATION = true;
};
"repository.pull-requests" = {
DEFAULT_MERGE_STYLE = "merge";
DEFAULT_MERGE_MESSAGE_ALL_AUTHORS = true;
};
"repository.upload".FILE_MAX_SIZE = 1024;
server = {
LANDING_PAGE = "explore";
OFFLINE_MODE = true;
};
security = { INSTALL_LOCK = true; };
other = {
SHOW_FOOTER_VERSION = false;
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
};
cron = {
ENABLED = true;
NOTICE_ON_SUCCESS = true;
};
"cron.update_mirrors" = {
SCHEDULE = "@every 12h";
PULL_LIMIT = "-1";
PUSH_LIMIT = "-1";
};
"cron.git_gc_repos".ENABLED = true;
"cron.delete_old_actions".ENABLED = true;
};
};
services.postgresqlBackup = {
enable = true;
databases = [ "gitea" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
services.openssh = {
enable = true;
passwordAuthentication = false;
listenAddresses = [ {
addr = "192.168.100.10";
port = 22;
} ];
extraConfig = ''
AcceptEnv GIT_PROTOCOL
'';
};
})).config.system.build.toplevel;
};
services.nginx.virtualHosts."git.infra4future.de" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://${config.containers.gitea.localAddress}:3000";
};
};
hexchen.nftables.nat.forwardPorts = [{
ports = [ 22 ];
destination = "${config.containers.gitea.localAddress}:22";
proto = "tcp";
}];
}

View file

@ -1,113 +0,0 @@
{ config, lib, pkgs, profiles, modules, evalConfig, sources, ... }:
{
containers.pad-hacc = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.5";
autoStart = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/pad-hacc";
isReadOnly = false;
};
};
path = (evalConfig {hosts = {}; groups = {};} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
imports = [
((import sources.nix-hexchen) {}).profiles.nopersist
];
nixpkgs.config.allowUnfree = true;
networking.firewall.enable = false;
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
services.hedgedoc = {
enable = true;
configuration = {
allowAnonymous = true;
allowFreeURL = true;
allowGravatar = false;
allowOrigin = [ "localhost" "pad.hacc.space" "fff-muc.de" ];
db = {
host = "/run/postgresql";
username = "codimd";
dialect = "postgres";
database = "codimd";
};
defaultPermission = "limited";
domain = "pad.hacc.space";
host = "0.0.0.0";
protocolUseSSL = true;
hsts.preload = false;
email = false;
oauth2 = {
authorizationURL = "https://login.infra4future.de/oauth2/authorize";
tokenURL = "https://login.infra4future.de/oauth2/token";
clientID = "hedgedoc";
clientSecret = "1a730af1-4d6e-4c1d-8f7e-72375c9b8d62";
};
};
};
systemd.services.hedgedoc.environment = {
"CMD_LOGLEVEL" = "warn";
"CMD_OAUTH2_USER_PROFILE_URL" = "https://login.infra4future.de/oauth2/userinfo";
"CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR" = "nickname";
"CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR" = "name";
"CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR" = "email";
"CMD_OAUTH2_PROVIDERNAME" = "Infra4Future";
};
services.postgresql = {
enable = true;
ensureDatabases = [ "codimd" ];
ensureUsers = [{
name = "codimd";
ensurePermissions = {
"DATABASE codimd" = "ALL PRIVILEGES";
};
}];
authentication = ''
local all all trust
host codimd codimd 127.0.0.1/32 trust
'';
package = pkgs.postgresql_11;
};
services.postgresqlBackup = {
enable = true;
databases = [ "codimd" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
})).config.system.build.toplevel;
};
services.nginx.virtualHosts."pad.hacc.earth" = {
enableACME = true;
forceSSL = true;
globalRedirect = "pad.hacc.space";
};
services.nginx.virtualHosts."pad.hacc.space" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://${config.containers.pad-hacc.localAddress}:3000";
extraConfig = ''
add_header Access-Control-Allow-Origin "*";
proxy_buffering off;
'';
};
};
}

View file

@ -1,96 +0,0 @@
{ config, lib, pkgs, modules, evalConfig, sources, ... }:
{
containers.pad-i4f = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.6";
autoStart = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/pad-i4f";
isReadOnly = false;
};
};
path = (evalConfig {hosts = {}; groups = {};} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
imports = [
((import sources.nix-hexchen) {}).profiles.nopersist
];
nixpkgs.config.allowUnfree = true;
networking.firewall.enable = false;
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
services.hedgedoc = {
enable = true;
configuration = {
allowAnonymous = true;
allowFreeURL = true;
allowGravatar = false;
allowOrigin = [ "localhost" "pad.infra4future.de" "fff-muc.de" ];
db = {
host = "/run/postgresql";
dialect = "postgres";
database = "hedgedoc";
};
defaultPermission = "freely";
domain = "pad.infra4future.de";
host = "0.0.0.0";
protocolUseSSL = true;
hsts.preload = false;
email = false;
};
};
systemd.services.hedgedoc.environment = {
"CMD_LOGLEVEL" = "warn";
};
services.postgresql = {
enable = true;
package = pkgs.postgresql_11;
authentication = ''
local all all trust
host hedgedoc hedgedoc 127.0.0.1/32 trust
'';
ensureDatabases = [ "hedgedoc" ];
ensureUsers = [{
name = "hedgedoc";
ensurePermissions = {
"DATABASE hedgedoc" = "ALL PRIVILEGES";
};
}];
};
services.postgresqlBackup = {
enable = true;
databases = [ "hedgedoc" ];
startAt = "*-*-* 23:45:00";
location = "/persist/backups/postgres";
};
})).config.system.build.toplevel;
};
services.nginx.virtualHosts."pad.infra4future.de" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://${config.containers.pad-i4f.localAddress}:3000";
extraConfig = ''
add_header Access-Control-Allow-Origin "*";
proxy_buffering off;
'';
};
};
}

View file

@ -1,115 +0,0 @@
{ config, lib, pkgs, profiles, modules, evalConfig, ... }:
{
containers.lantifa = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.8";
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/lantifa";
isReadOnly = false;
};
};
path = (evalConfig {hosts = {}; groups = {};} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
hexchen.bindmounts."/var/lib/mediawiki" = "/persist/var/lib/mediawiki";
imports = [
((import sources.nix-hexchen) {}).profiles.nopersist
];
networking.hosts."127.0.0.1" = [ "wiki.lantifa.org" ];
users.users.mediawiki.extraGroups = [ "keys" ];
nixpkgs.config.allowUnfree = true;
networking.firewall.enable = false;
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
services.mediawiki = {
enable = true;
name = "LANtifa";
database.createLocally = true;
passwordFile = "/var/lib/mediawiki/mediawiki-password";
extraConfig = let
wikidb = pkgs.fetchzip {
url = "https://www.kennel17.co.uk/uploads/testwiki/e/e9/WikiDB.zip";
sha256 = "sha256-8pMNQwmGEsbIoSV1s4RL5Xqq4+f+GNOaCB8VlVnbweY=";
};
in ''
// Configure short URLs
$wgScriptPath = "";
$wgArticlePath = "/wiki/$1";
$wgUsePathInfo = true;
require_once('${wikidb}/WikiDB.php');
$wgExtraNamespaces = array( 100 => "Table", 101 => "Table_Talk",);
$wgWikiDBNamespaces = 100;
$wgGroupPermissions['user']['writeapi'] = true;
$wgDefaultUserOptions['visualeditor-enable'] = 1;
$wgLogo = "images/c/c5/LantifaLogoFem0.3.png";
// PageForms config
$wgGroupPermissions['*']['viewedittab'] = false;
$wgGroupPermissions['user']['viewedittab'] = true;
// Moderation setting
$wgModerationNotificationEnable = true;
$wgModerationEmail = "wiki_mod@lantifa.org";
$wgLogRestrictions["newusers"] = 'moderation';
// intersection / DynamicPageList config
$wgDLPMaxCacheTime = 5 * 60;
'';
extensions = {
TemplateData = null;
VisualEditor = null;
InputBox = null;
Moderation = pkgs.fetchzip {
url = "https://github.com/edwardspec/mediawiki-moderation/archive/v1.4.20.tar.gz";
sha256 = "1k0z44jfqsxzwy6jjz3yfibiq8wi845d5iwwh8j3yijn2854fj0i";
};
intersection = pkgs.fetchzip { # This is the DynamicPageList extension
url = "https://extdist.wmflabs.org/dist/extensions/intersection-REL1_36-82eb087.tar.gz";
sha256 = "sha256-TD58DvJ4CFASP4rIc94jeB4SN4zktLe33xZtz/Qg2dk=";
};
PageForms = pkgs.fetchzip {
url = "https://github.com/wikimedia/mediawiki-extensions-PageForms/archive/5.0.1.zip";
sha256 = "172m7p941fbkl29h5bhanx3dn42jfmzgyvgmgm2lgdbmkawwly96";
};
};
virtualHost = {
hostName = "wiki.lantifa.org";
listen = [ { port = 80; } ];
adminAddr = "admin@hacc.space";
extraConfig = ''
RewriteEngine On
RewriteRule ^/?wiki(/.*)?$ %{DOCUMENT_ROOT}/index.php [L]
RewriteRule ^/*$ %{DOCUMENT_ROOT}/index.php [L]
'';
};
};
services.mysql.dataDir = "/persist/mysql";
services.mysqlBackup = {
enable = true;
databases = [ "mediawiki" ];
calendar = "*-*-* 23:45:00";
};
})).config.system.build.toplevel;
};
services.nginx.virtualHosts."wiki.lantifa.org" = {
locations."/".proxyPass = "http://" + config.containers.lantifa.localAddress + "";
forceSSL = true;
enableACME = true;
};
}

View file

@ -1,177 +0,0 @@
{ config, pkgs, lib, sources, ... }:
{
imports = [ sources.nixos-mailserver.outPath ];
# reduce log spam
systemd.services.rspamd.serviceConfig.LogLevelMax =
3; # this is set to error because rspamd regularly complains about not enough learns
systemd.services.postfix.serviceConfig.LogLevelMax = 5; # = notice
systemd.services.dovecot2.serviceConfig.LogLevelMax = 5; # = notice
# stop postfix from dying if rspamd hiccups
systemd.services.postfix.unitConfig = {
Requires = lib.mkForce "dovecot2.service opendkim.service";
};
mailserver = {
mailDirectory = "/persist/mail";
enable = true;
fqdn = "mail.hacc.space";
monitoring = {
enable = true;
alertAddress = "admin@hacc.space";
};
domains = [
"hacc.space"
"muc.hacc.space"
"hacc.earth"
"4future.dev"
"4futu.re"
"infra4future.de"
];
loginAccounts = {
"hexchen@hacc.space".hashedPassword =
"$6$x9skYtRp4dgxC$1y8gPC2BuVqG3kJVSMGgzZv0Bg1T9qxcnBWLIDbANy1d//SQ23Y7s3IMYcEPd1/l/MYWD9Y/Qse6HbT5w5Xwq/";
"octycs@hacc.space".hashedPassword =
"$6$KceTivtJ$58jxhYF6ULfivNsb3Z0J7PnGea0Hs2wTWh3c9FrKRIAmuOD96u2IDgZRCn6P5NrXA0BL.n6HC2RS3r.4JnOmg.";
"octycs@hacc.space".aliases = [ "markus@hacc.space" ];
"raphael@hacc.space".hashedPassword =
"$6$QveHpwMcp9mkFVAU$EFuahOrJIxPg.c.WGFHtrP3.onwJYwvP7fiBHHGb9jhosewZ2tEUP.2D3uyDLhd9Cfny6Yp4jDk/Hkjk7/ME1/";
"moira@hacc.space".hashedPassword =
"$6$BpYhwcZNrkLhVqK$6FMqA/vUkdV4GBlHLSqS5DRCb/CaLDNeIsBcZ8G30heytS/tJj2Ag7b1ovSltTA4PUfhee3pJrz1BkwkA93vN1";
"zauberberg@hacc.space".hashedPassword =
"$6$ISAaU8X6D$oGKe9WXDWrRpGzHUTdxrxdtg9zuGOlBMuDc82IZhegpsv1bqd550FhZZrI40IjZTA5Hy2MZ8j/0efpnQ4fOQH0";
"zauberberg@hacc.space".aliases = [ "lukas@hacc.space" ];
"stuebinm@hacc.space".hashedPassword =
"$6$mjrMQG5smqLRlm$WzmbiZnGlEXGT7hj/n2qz0nvVzGyZfMToCyLRi0wErfVEHI7y7jtWoHqIWnpcHAM29UocsIFFsUCb3XqQCwwB.";
"lenny@hacc.space".hashedPassword =
"$6$EZpv9XImv5F3$p2NSoo5gLxh6NnB3/C6wF8knRTuMHqDXYF3BEscaQuk7qok2Z13xKT/6mFvvSKKBnFCuYptgnfGswmoqIzm/1/";
"lenny@hacc.space".aliases = [ "rinderhacc@hacc.space" ];
"finance@muc.hacc.space".hashedPassword =
"$6$R3GRmvXwqnMM6q.R$Y9mrUAmMnCScsM6pKjxo2a2XPM7lHrV8FIgK0PzhYvZbxWczo7.O4dk1onYeV1mRx/nXZfkZNjqNCruCn0S2m.";
"noreply@hacc.space" = {
hashedPassword =
"$6$YsqMoItITZUzI5wo$5Lejf8XBHRx4LW4VuZ9wJCiBbT4kOV/EZaCdWQ07eVIrkRTZwXWZ5zfsh.olXEFwvpNWN.DBnU.dQc.cC0/ra/";
sendOnly = true;
};
"noreply@infra4future.de" = {
hashedPassword =
"$6$uaD8bRcT1$gFqhFyu5RUsyUUOG5b.kN.JAJ1rVHvaYhpeRHoMvrERAMgBu1FHu2oDnjTsy.5NKoLc5xpI5uv4Gpy4YbmDmV.";
sendOnly = true;
};
};
extraVirtualAliases = {
# address = forward address;
# -- International --
# info/contact: main entrypoint, anyone can read or reply to this.
"info@hacc.space" = [
"hexchen@hacc.space"
"octycs@hacc.space"
"raphael@hacc.space"
"moira@hacc.space"
"zauberberg@hacc.space"
"stuebinm@hacc.space"
"lenny@hacc.space"
];
# admin: current people with access to the mail server and knowledge on how to use it™
"admin@hacc.space" =
[ "hexchen@hacc.space" "moira@hacc.space" "zauberberg@hacc.space" ];
# voc: hacc video operation center, various streaming-related things
"voc@hacc.space" = [
"hexchen@hacc.space"
"moira@hacc.space"
"octycs@hacc.space"
"stuebinm@hacc.space"
"zauberberg@hacc.space"
"lenny@hacc.space"
"raphael@hacc.space"
];
# -- Regional: Germany --
# board of hacc e.V.
"vorstand@hacc.space" =
[ "raphael@hacc.space" "moira@hacc.space" "zauberberg@hacc.space" ];
# members of hacc e.V.
"mitglieder@hacc.space" = [
"hexchen@hacc.space"
"raphael@hacc.space"
"moira@hacc.space"
"zauberberg@hacc.space"
"lenny@hacc.space"
"octycs@hacc.space"
"stuebinm@hacc.space"
];
# -- Regional: Munich --
"muc@hacc.space" = [
"hexchen@hacc.space"
"octycs@hacc.space"
"raphael@hacc.space"
"moira@hacc.space"
"zauberberg@hacc.space"
"stuebinm@hacc.space"
"lenny@hacc.space"
];
};
# Use Let's Encrypt certificates. Note that this needs to set up a stripped
# down nginx and opens port 80.
certificateScheme = 3;
# Only allow implict TLS
enableImap = false;
enablePop3 = false;
# Enable the ManageSieve protocol
enableManageSieve = true;
};
services.postfix.submissionOptions.smtpd_sender_restrictions =
lib.mkForce "reject_non_fqdn_sender,reject_unknown_sender_domain,permit";
services.postfix.submissionsOptions.smtpd_sender_restrictions =
lib.mkForce "reject_non_fqdn_sender,reject_unknown_sender_domain,permit";
services.postfix.virtual = ''
postmaster@hacc.space admin@hacc.space
abuse@hacc.space admin@hacc.space
contact@hacc.space info@hacc.space
hello@hacc.space info@hacc.space
haccvoc@hacc.space voc@hacc.space
@4future.dev @hacc.space
@4futu.re @hacc.space
@hacc.earth @hacc.space
@infra4future.de @hacc.space
'';
systemd.services.alps = {
enable = true;
script =
"${pkgs.alps}/bin/alps -theme alps imaps://mail.hacc.space:993 smtps://mail.hacc.space:465";
serviceConfig.WorkingDirectory = "${pkgs.alps}/share/alps";
serviceConfig.Restart = "always";
requiredBy = [ "multi-user.target" ];
};
services.nginx.virtualHosts."mail.hacc.space" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://[::1]:1323";
};
}

View file

@ -1,246 +0,0 @@
{config, pkgs, lib, profiles, modules, evalConfig, sources, ...}:
let
mattermost = pkgs.mattermost;
in {
containers.mattermost = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.3";
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/mattermost";
isReadOnly = false;
};
};
path = (evalConfig {hosts = {}; groups = {};} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
imports = [
../modules/mattermost.nix
((import sources.nix-hexchen) {}).profiles.nopersist
];
nixpkgs.overlays = [ (self: super: { inherit mattermost; }) ];
nixpkgs.config.allowUnfree = true;
networking.firewall.enable = false;
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
# couldn't figure out how to actually overwrite modules, so now
# there's two mattermost modules ...
services.mattermost-patched = {
enable = true;
siteUrl = "https://mattermost.infra4future.de";
siteName = "Mattermost for Future";
listenAddress = "0.0.0.0:3000";
mutableConfig = false;
secretConfig = "/persist/mattermost/secrets.json";
statePath = "/persist/mattermost";
extraConfig = {
ServiceSettings = {
TrustedProxyIPHeader = [ "X-Forwarded-For" "X-Real-Ip" ];
ReadTimeout = 300;
WriteTimeout = 600;
IdleTimeout = 60;
MaximumLoginAttempts = 10;
AllowCorsFrom = "*.infra4future.de/*";
WebserverMode = "gzip";
EnableCustomEmoji = true;
EnableEmojiPicker = true;
EnableGifPicker = false;
RestrictCustomEmojiCreation = "all";
RestrictPostDelete = "all";
AllowEditPost = "always";
PostEditTimeout = -1;
EnableTutorial = false;
ExperimentalChannelSidebarOrganization = "default_on";
ExperimentalChannelOrganization = true;
ExperimentalDataPrefetch = true;
EnableEmailInvitations = true;
DisableLegacyMFA = true;
EnableSVGs = true;
EnableLaTeX = true;
ThreadAutoFollow = true;
EnableSecurityFixAlert = false;
CollapsedThreads = "default_on";
};
TeamSettings = {
EnableTeamCreation = true;
EnableUserCreation = true;
MaxUsersPerTeam = 250;
EnableOpenServer = false;
EnableUserDeactivation = true;
ExperimentalViewArchivedChannels = true;
ExperimentalEnableAutomaticReplies = true;
};
LogSettings = {
EnableConsole = true;
ConsoleLevel = "ERROR";
EnableDiagnostics = false;
EnableWebhookDebugging = false;
};
NotificationLogSettings = {
EnableConsole = true;
ConsoleLevel = "INFO";
};
PasswordSettings = {
MinimumLength = 10;
# turn of all the bullshit requirements
Lowercase = false;
Number = false;
Uppercase = false;
Symbol = false;
};
FileSettings = {
EnableFileAttachments = true;
MaxFileSize = 52428800;
DriverName = "local";
Directory = "/persist/mattermost/upload-storage";
EnablePublicLink = true;
PublicLinkSalt = "3k7p3yxdhz6798b3b9openfr9rn3ymwu";
};
EmailSettings = {
EnableSignUpWithEmail = false;
EnableSignInWithEmail = false;
EnableSignInWithUsername = false;
SendEmailNotifications = true;
FeedbackName = "mattermost";
FeedbackEmail = "mattermost@infra4future.de";
ReplyToAddress = "mattermost@infra4future.de";
FeedbackOrganization = "infra4future.de";
EnableSMTPAuth = true;
SMTPUsername = "noreply@infra4future.de";
SMTPServer = "mail.hacc.space";
};
RateLimitSettings.Enable = false;
PrivacySettings = {
ShowEmailAddress = false;
ShowFullName = true;
};
SupportSettings = {
TermsOfServiceLink = "https://infra4future.de/nutzungsbedingungen.html";
PrivacyPolicyLink = "https://infra4future.de/nutzungsbedingungen.html";
AboutLink = "https://infra4future.de";
SupportEmail = "info@infra4future.de";
CustomTermsOfServiceEnabled = false;
EnableAskCommunityLink = true;
};
AnnouncementSettings.EnableBanner = false;
GitLabSettings = {
Enable = true;
Id = "mattermost";
Scope = "";
AuthEndpoint = "https://login.infra4future.de/oauth2/authorize";
TokenEndpoint = "https://login.infra4future.de/oauth2/token";
UserApiEndpoint = "https://login.infra4future.de/oauth2/userinfo";
};
# for some reason, these don't appear to be working; the startup
# process complaines and sets these back to en
LocalizationSettings = {
DefaultServerLocale = "de";
DefaultClientLocale = "de";
AvailableLocales = "de,en";
};
MessageExportSettings.EnableExport = false;
# plugins appear to have trouble with the read-only filesystem; it may
# be necessary to manually change their paths etc.
PluginSettings = {
Enable = true;
EnableUploads = true;
Plugins = {
bigbluebutton = {
adminonly = false;
base_url = "https://bbb.infra4future.de/bigbluebutton/api";
salt = "zKCsNeaEniC115ynHOsZopgA4iTiJjzgeiPNoCEc";
};
"com.github.matterpoll.matterpoll" = {
experimentalui = true;
trigger = "poll";
};
};
PluginStates = {
bigbluebutton.Enable = true;
"com.github.matterpoll.matterpoll".Enable = true;
};
};
ComplianceSettings.Enable = false;
ClusterSettings.Enable = false;
MetricsSettings.Enable = false;
GuestAccountsSettings.Enable = false;
FeatureFlags.CollapsedThreads = true;
};
# turn of the weirder parts of this module (which insist on passwords
# in nix files, instead of just using socket-based authentication)
#
# It will still attempt to use its default password, but postgres will
# just let it in regardless of that.
localDatabaseCreate = false;
};
services.mysql = {
enable = true;
ensureDatabases = [ "mattermost" ];
ensureUsers = [ {
name = "mattermost";
ensurePermissions = { "mattermost.*" = "ALL PRIVILEGES"; };
} ];
package = pkgs.mysql80;
dataDir = "/persist/mysql";
};
services.postgresql = {
enable = lib.mkForce true; # mattermost sets this to false. wtf.
package = pkgs.postgresql_11;
ensureDatabases = [ "mattermost" ];
ensureUsers = [ {
name = "mattermost";
ensurePermissions = { "DATABASE mattermost" = "ALL PRIVILEGES"; };
} ];
authentication = lib.mkForce ''
# Generated file; do not edit!
local all all trust
host mattermost mattermost ::1/128 trust
'';
};
networking.firewall.allowedTCPPorts = [ 3000 ];
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
})).config.system.build.toplevel;
};
services.nginx.virtualHosts."mattermost.infra4future.de" = {
locations."/" = {
proxyPass = "http://${config.containers.mattermost.localAddress}:3000";
proxyWebsockets = true;
extraConfig = ''
# Mattermost CSR Patch
proxy_hide_header Content-Security-Policy;
proxy_hide_header X-Frame-Options;
proxy_redirect off;
'';
};
forceSSL = true;
enableACME = true;
};
}

View file

@ -1,23 +0,0 @@
{ config, lib, pkgs, sources, ... }:
{
hexchen.bindmounts."/var/lib/murmur" = "/persist/var/lib/murmur";
services.murmur = {
enable = true;
logDays = -1;
welcometext = "Welcome to mumble4future! Brought to you by infra4future. The server is now reachable under mumble.hacc.space, please update your bookmarks.";
sslKey = "/var/lib/acme/mumble.hacc.space/key.pem";
sslCert = "/var/lib/acme/mumble.hacc.space/fullchain.pem";
bandwidth = 128000;
};
networking.firewall.allowedTCPPorts = [ config.services.murmur.port ];
networking.firewall.allowedUDPPorts = [ config.services.murmur.port ];
# the mumble cert has its own group so that both nginx and murmur can read it
users.groups.mumblecert = {};
security.acme.certs."mumble.hacc.space".group = "mumblecert";
users.users.nginx.extraGroups = [ "mumblecert" ];
users.users.murmur.extraGroups = [ "mumblecert" ];
}

View file

@ -1,116 +0,0 @@
{ config, lib, pkgs, profiles, modules, evalConfig, ... }:
{
containers.nextcloud = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.2";
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/nextcloud";
isReadOnly = false;
};
};
path = (evalConfig {hosts = {}; groups = {};} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
imports = [
((import sources.nix-hexchen) {}).profiles.nopersist
../../modules/nextcloud.nix
];
nixpkgs.config.allowUnfree = true;
networking.firewall.enable = false;
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
environment.systemPackages = [ pkgs.htop ];
services.nextcloud-patched = {
enable = true;
# must be set manually; may not be incremented by more than one at
# a time, otherwise nextcloud WILL break
package = pkgs.nextcloud24;
home = "/persist/nextcloud";
https = true;
hostName = "cloud.infra4future.de";
config = {
dbtype = "pgsql";
dbuser = "nextcloud";
dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
dbname = "nextcloud";
adminpassFile = "/persist/nextcloud/config/admin_pw";
adminuser = "root";
defaultapp = "apporder";
};
# multiple pools may be doable using services.phpfpm.pools,
# but i have not tried this yet. The nextcloud module defines a
# pool "nextcloud"
poolSettings = {
pm = "dynamic";
"pm.max_children" = "32";
"pm.max_requests" = "500";
"pm.max_spare_servers" = "4";
"pm.min_spare_servers" = "2";
"pm.start_servers" = "2";
};
extraOptions = {
instanceid = "ocxlphb7fbju";
datadirectory = "/persist/data/ncdata";
loglevel = 0;
"overwrite.cli.url" = "https://cloud.infra4future.de";
};
};
services.postgresql = {
enable = true;
package = pkgs.postgresql_11;
ensureDatabases = [ "nextcloud" ];
ensureUsers = [
{ # by default, postgres has unix sockets enabled, and allows a
# system user `nextcloud` to log in without other authentication
name = "nextcloud";
ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
}
];
};
# ensure that postgres is running *before* running the setup
systemd.services."nextcloud-setup" = {
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
})).config.system.build.toplevel;
};
services.nginx.virtualHosts."cloud.infra4future.de" = {
locations."/".proxyPass = "http://${config.containers.nextcloud.localAddress}:80";
enableACME = true;
forceSSL = true;
extraConfig = ''
proxy_buffering off;
client_max_body_size 0;
add_header Cache-Control "no-store, no-cache, must-revalidate";
'';
};
}

View file

@ -1,9 +0,0 @@
{ config, pkgs, ... }:
{
hacc.websites = {
enable = true;
directory = ../websites;
};
}

View file

@ -1,39 +0,0 @@
{ config, lib, pkgs, ... }:
{
services.syncthing = {
enable = true;
relay.enable = false;
openDefaultPorts = true;
configDir = "/persist/var/lib/syncthing/";
dataDir = "/persist/data/syncthing/";
devices = {
raphael-laptop = {
addresses = []; # empty = dynamic
id = "72B3T74-NOMJV3X-EVJXTJF-5GGAEZB-ZDKBHXQ-VQNRYEU-YCPA2JP-L6NGAAG";
};
# zauberberg
conway = {
addresses = []; # empty = dynamic
id = "HV7IU2N-Q4W3A7F-BSASR43-OB575SM-47FY2UW-7N5GMFM-PX3LWRN-HXBXMQF";
};
};
folders = {
"/persist/data/syncthing/hacc/" = {
id = "qt2ly-xvvvs";
devices = [ "conway" "raphael-laptop"];
type = "receiveonly";
versioning = {
type = "simple";
params.keep = "10";
};
};
"/persist/data/syncthing/hacc_eV_vorstand/" = {
id = "twwt7-fxrsr";
devices = [ "conway" "raphael-laptop"];
# type = "receiveencrypted"; # no yet implemented
};
};
overrideFolders = false; # enables workaround for recieveencrypted
};
}

View file

@ -1,86 +0,0 @@
{ config, lib, pkgs, evalConfig, ... }:
let
# necessary since overlays won't propagate into the
# container's config
thelounge = pkgs.thelounge-hacked;
in
{
containers.thelounge = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.4";
path = (evalConfig {hosts = {}; groups = {};} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
nixpkgs.config.allowUnfree = true;
networking.firewall.enable = false;
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
services.thelounge = {
enable = true;
extraConfig = {
public = true;
# respect X-Forwarded-For
reverseProxy = true;
defaults = {
name = "libera chat";
host = "irc.eu.libera.chat";
port = 6697;
# encrypt things!
tls = true;
# yes, please do actually check the cert …
rejectUnauthorized = true;
nick = "haccGuest%%%%";
join = "#hacc-webchat";
};
lockNetwork = true;
# don't log messages (default is text / sqlite)
messageStorage = [];
# darker theme
#theme = "morning";
# these three should result in having link previews
# which are fetched only by the server, then proxied
# (i.e. clients won't directly connect to arbitrary
# domains to get previews)
prefetch = true;
prefetchStorage = true;
disableMediaPreview = true;
leaveMessage = "happy haccing";
};
};
# override the package we use
systemd.services.thelounge.serviceConfig.ExecStart =
pkgs.lib.mkForce "${thelounge}/bin/thelounge start";
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
})).config.system.build.toplevel;
};
services.nginx.virtualHosts."webchat.voc.hacc.space" = {
locations."/".proxyPass =
"http://${config.containers.thelounge.localAddress}:9000";
enableACME = true;
forceSSL = true;
};
}

View file

@ -1,84 +0,0 @@
{ config, lib, pkgs, profiles, modules, evalConfig, sources, ... }:
let
uffd = pkgs.uffd;
in {
containers.uffd = {
privateNetwork = true;
hostAddress = "192.168.100.1";
localAddress = "192.168.100.9";
autoStart = true;
bindMounts = {
"/persist" = {
hostPath = "/persist/containers/uffd";
isReadOnly = false;
};
};
path = (evalConfig {hosts = {}; groups = {};} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
imports = [
((import sources.nix-hexchen) {}).profiles.nopersist
];
nixpkgs.config.allowUnfree = true;
networking.firewall.enable = false;
networking.defaultGateway = {
address = "192.168.100.1";
interface = "eth0";
};
services.coredns = {
enable = true;
config = ''
.:53 {
forward . 1.1.1.1
}
'';
};
services.uwsgi = {
enable = true;
plugins = [ "python3" ];
instance = {
type = "normal";
pythonPackages = self: with self; [ uffd ];
module = "uffd:create_app()";
# socket = "${config.services.uwsgi.runDir}/uwsgi.sock";
http = ":8080";
env = [
"CONFIG_PATH=/persist/uffd/uffd.conf"
];
hook-pre-app = "exec:FLASK_APP=${uffd}/lib/python3.9/site-packages/uffd flask db upgrade";
};
};
})).config.system.build.toplevel;
};
services.nginx.virtualHosts."login.infra4future.de" = {
enableACME = true;
forceSSL = true;
locations = {
"/".proxyPass = "http://${config.containers.uffd.localAddress}:8080";
"/static".root = "${uffd}/lib/python3.9/site-packages/uffd";
"/static/hacc.png".return = "302 https://infra4future.de/assets/img/logo_vernetzung.png";
"/static/infra4future.svg".return = "302 https://infra4future.de/assets/img/infra4future.svg";
"/static/hedgedoc.svg".return = "302 https://infra4future.de/assets/img/icons/hedgedoc.svg";
"/static/mattermost.svg".return = "302 https://infra4future.de/assets/img/icons/mattermost.svg";
"/static/nextcloud.svg".return = "302 https://infra4future.de/assets/img/icons/nextcloud.svg";
"/static/hot_shit.svg".return = "302 https://infra4future.de/assets/img/icons/hot_shit.svg";
};
};
systemd.services.auamost = {
enable = true;
description = "mattermost aua gruppensync";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig.Type = "simple";
path = [ pkgs.curl pkgs.jq ];
script = "${pkgs.fish}/bin/fish /persist/magic/mattermost-groupsync.fish";
startAt = "*:0/15";
};
}

View file

@ -1,51 +0,0 @@
{ config, lib, pkgs, ... }:
{
services.vaultwarden = {
enable = true;
config = {
DATA_FOLDER="/persist/var/lib/vaultwarden/data";
LOG_LEVEL="error";
SIGNUPS_ALLOWED=false;
SIGNUPS_VERIFY=true;
SIGNUPS_DOMAINS_WHITELIST="hacc.space";
ORG_CREATION_USERS="admin@hacc.space";
INVITATIONS_ALLOWED=true;
INVITATION_ORG_NAME="haccwarden";
TRASH_AUTO_DELETE_DAYS=90;
DOMAIN="https://pw.hacc.space";
ROCKET_ADDRESS="127.0.0.1";
ROCKET_PORT=5354;
ROCKET_WORKERS=2;
SMTP_HOST="mail.hacc.space";
SMTP_FROM="vaultwarden@hacc.space";
SMTP_FROM_NAME="haccwarden";
SMTP_PORT=587;
SMTP_USERNAME="noreply@infra4future.de";
};
environmentFile = "/persist/var/lib/vaultwarden/vaultwarden.env"; #contains SMTP_PASSWORD
dbBackend = "sqlite";
backupDir = "/persist/data/vaultwarden_backups/";
};
#work around ProtectSystem=strict, cleanup
systemd.services.vaultwarden.serviceConfig = {
ReadWritePaths = [ "/persist/var/lib/vaultwarden" ];
StateDirectory = lib.mkForce "";
};
systemd.services.backup-vaultwarden.environment.DATA_FOLDER =
lib.mkForce "/persist/var/lib/vaultwarden/data";
services.nginx.virtualHosts."pw.hacc.space" = {
locations."/" = {
proxyPass = "http://127.0.0.1:5354";
proxyWebsockets = true;
};
forceSSL = true;
enableACME = true;
};
}

View file

@ -1,87 +0,0 @@
{ config, lib, pkgs, modules, profiles, evalConfig, sources, ... }:
let
wapkgs = "${sources.workadventure}/wapkgs.nix";
in
{
services.coturn = {
enable = true;
realm = "void.hacc.space";
no-cli = true;
lt-cred-mech = true;
extraConfig = ''
user=turn:a4c9ad080dc51146611eabd15a27b07fc92850a9ae90c53e7745fce6c5a2c457
fingerprint
external-ip=135.181.215.233
server-name=void.hacc.space
prometheus
'';
cert = config.security.acme.certs."void.hacc.space".directory + "full.pem";
pkey = config.security.acme.certs."void.hacc.space".directory + "key.pem";
};
networking.firewall = with config.services.coturn;
let
ports = [ listening-port tls-listening-port ];
in {
allowedTCPPorts = ports ++ [ 9641 ]; # 9641 is the port for the prometheus endpoint
allowedUDPPorts = ports;
allowedUDPPortRanges = [
{ from = min-port; to = max-port; }
];
};
services.nginx.virtualHosts."void.hacc.space" = {
locations."/" = {
proxyPass = "http://192.168.150.3";
proxyWebsockets = true;
};
enableACME = true;
forceSSL = true;
};
containers.wa-void = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.150.1";
localAddress = "192.168.150.3";
path = (evalConfig {hosts = {}; groups = {};} ({ config, lib, pkgs, profiles, modules, sources, ... }: {
boot.isContainer = true;
networking.useDHCP = false;
users.users.root.hashedPassword = "";
imports = [
"${sources.workadventure.outPath}/default.nix"
((import sources.nix-hexchen) {}).profiles.nopersist
];
services.workadventure."void" = {
packageset = (import wapkgs {inherit pkgs;}).workadventure-xce;
nginx = {
default = true;
domain = "https://void.hacc.space";
maps.path = "${sources.haccmap.outPath}/";
maps.serve = true;
};
frontend.startRoomUrl = "/_/global/void.hacc.space/maps/main.json";
commonConfig = {
webrtc.stun.url = "stun:void.hacc.space:3478";
webrtc.turn = {
url = "turn:135.181.215.233";
user = "turn";
password = "a4c9ad080dc51146611eabd15a27b07fc92850a9ae90c53e7745fce6c5a2c457";
};
jitsi.url = "meet.ffmuc.net";
};
};
})).config.system.build.toplevel;
};
}

View file

@ -1,25 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 111 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

Some files were not shown because too many files have changed in this diff Show more