Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ dist-ssr
*.db-shm
*.db-wal

src-tauri/gen/

.direnv
.envrc
.aider*

src-tauri/gen/
# nix stuff
result
12 changes: 6 additions & 6 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 16 additions & 55 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
nixpkgs.url = "nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay.url = "github:oxalica/rust-overlay";

# include git submodules
# self.submodules = true;
};

outputs = {
Expand All @@ -12,65 +15,23 @@
rust-overlay,
}:
flake-utils.lib.eachDefaultSystem (system: let
# add rust overlay
pkgs = import nixpkgs {
inherit system;
overlays = [rust-overlay.overlays.default];
};

toolchain = pkgs.rust-bin.stable.latest.default.override {
extensions = ["rust-analyzer" "rust-src" "rustfmt" "clippy"];
targets = ["wasm32-unknown-unknown" "x86_64-apple-darwin" "aarch64-apple-darwin" "x86_64-pc-windows-gnu"];
};
packages = with pkgs; [
cargo
cargo-tauri
toolchain
rust-analyzer-unwrapped
nodejs_20
nodePackages.pnpm
trunk
sqlx-cli
vtsls
];
nativeBuildPackages = with pkgs; [
pkg-config
dbus
openssl
glib
gtk3
libsoup_2_4
webkitgtk_4_0
librsvg
protobuf
libayatana-appindicator
];
libraries = with pkgs; [
gtk3
cairo
gdk-pixbuf
glib
dbus
openssl
librsvg
libsoup_3
webkitgtk_4_0
libayatana-appindicator
];
in {
devShells.default = pkgs.mkShell {
buildInputs = packages;
nativeBuildInputs = nativeBuildPackages;
shellHook = with pkgs; ''
export LD_LIBRARY_PATH="${
lib.makeLibraryPath libraries
}:$LD_LIBRARY_PATH"
export OPENSSL_INCLUDE_DIR="${openssl.dev}/include/openssl"
export OPENSSL_LIB_DIR="${openssl.out}/lib"
export OPENSSL_ROOT_DIR="${openssl.out}"
# https://discourse.nixos.org/t/which-package-includes-org-gtk-gtk4-settings-filechooser/38063/12
export XDG_DATA_DIRS="${gtk3}/share/gsettings-schemas/gtk+3-${gtk3.dev.version}:$XDG_DATA_DIRS"
export RUST_SRC_PATH="${toolchain}/lib/rustlib/src/rust/library"
'';
devShells.default = import ./nix/shell.nix {
inherit pkgs;
};
});

packages.default = pkgs.callPackage ./nix/package.nix {
inherit pkgs;
};

formatter = pkgs.alejandra;
})
// {
nixosModules.default = import ./nix/nixos-module.nix;
};
}
75 changes: 75 additions & 0 deletions nix/nixos-module.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
defguard-client = pkgs.callPackage ./package.nix {};
cfg = config.programs.defguard-client;
in {
options.programs.defguard-client = {
enable = mkEnableOption "Defguard VPN client and service";

package = mkOption {
type = types.package;
default = defguard-client;
description = "defguard-client package to use";
};

logLevel = mkOption {
type = types.str;
default = "info";
description = "Log level for defguard-service";
};

statsPeriod = mkOption {
type = types.int;
default = 30;
description = "Interval in seconds for interface statistics updates";
};
};

config = mkIf cfg.enable {
environment.systemPackages = [cfg.package];

systemd.services.defguard-service = {
description = "Defguard VPN Service";
wantedBy = ["multi-user.target"];
wants = ["network-online.target"];
after = ["network-online.target"];
serviceConfig = {
ExecStart = "${cfg.package}/bin/defguard-service --log-level ${cfg.logLevel} --stats-period ${toString cfg.statsPeriod}";
Restart = "on-failure";
RestartSec = 5;
User = "defguard";
Group = "defguard";
StateDirectory = "defguard";
LogsDirectory = "defguard";
# Add capabilities to manage network interfaces
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE";
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE";
# Allow access to /dev/net/tun for TUN/TAP devices
DeviceAllow = "/dev/net/tun rw";
# Access to /sys for network configuration
BindReadOnlyPaths = [
"/sys"
"/proc"
];
# Protect the system while giving necessary access
ProtectSystem = "strict";
ProtectHome = true;
NoNewPrivileges = true;
# Allow the service to manage network namespaces
PrivateNetwork = false;
};
};

users.users.defguard = {
isSystemUser = true;
group = "defguard";
};

users.groups.defguard = {};
};
}
122 changes: 122 additions & 0 deletions nix/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
pkgs,
lib,
stdenv,
rustPlatform,
makeDesktopItem,
}: let
pname = "defguard-client";
version = "1.5.1"; # TODO: Get this from Cargo.toml or git

desktopItem = makeDesktopItem {
name = pname;
exec = pname;
icon = pname;
desktopName = "Defguard";
genericName = "Defguard VPN Client";
categories = ["Network" "Security"];
};

rustToolchain = pkgs.rust-bin.stable.latest.default;

buildInputs = with pkgs; [
at-spi2-atk
atkmm
cairo
dbus
gdk-pixbuf
glib
glib-networking
gtk4
harfbuzz
librsvg
libsoup_3
pango
webkitgtk_4_1
openssl
libayatana-appindicator
mesa
libGL
libGLU
];

nativeBuildInputs = with pkgs; [
rustToolchain
pkg-config
gobject-introspection
cargo-tauri
nodejs_24
protobuf
pnpm
# configures pnpm to use pre-fetched dependencies
pnpm.configHook
# configures cargo to use pre-fetched dependencies
rustPlatform.cargoSetupHook
perl
wrapGAppsHook
# helper to add dynamic library paths
makeWrapper
];
in
stdenv.mkDerivation (finalAttrs: rec {
inherit pname version buildInputs nativeBuildInputs;

src = ../.;

# prefetch cargo dependencies
cargoRoot = "src-tauri";
buildAndTestSubdir = "src-tauri";

cargoDeps = rustPlatform.importCargoLock {
lockFile = ../src-tauri/Cargo.lock;
# specify hashes for git dependencies
# outputHashes = {
# "defguard_wireguard_rs-0.7.5" = "sha256-pxwN43BntOEYtp+TlpQFX78gg1ko4zuXEGctZIfSrhg=";
# "tauri-plugin-log-0.0.0" = "sha256-jGzlN/T29Hya4bKe9Dwl2mRRFLXMywrHk+32zgwrpJ0=";
# };
};

# prefetch pnpm dependencies
pnpmDeps = pkgs.pnpm.fetchDeps {
inherit
(finalAttrs)
pname
version
src
;

fetcherVersion = 2;
hash = "sha256-ccSwlPY3sOnUJoYfB4MWs0gU8/Aq/CiCrLWouQ7PqhY=";
};

buildPhase = ''
pnpm tauri build
'';

postInstall = ''
# copy client binary
mkdir -p $out/bin
cp src-tauri/target/release/${pname} $out/bin/
# copy service binary
mkdir -p $out/bin
cp src-tauri/target/release/defguard-service $out/bin/
# copy cli binary
mkdir -p $out/bin
cp src-tauri/target/release/dg $out/bin/

# add required library to client binary RPATH
wrapProgram $out/bin/${pname} \
--prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [pkgs.libayatana-appindicator]}

mkdir -p $out/share/applications
cp ${desktopItem}/share/applications/* $out/share/applications/
'';

meta = with lib; {
description = "Defguard VPN Client";
homepage = "https://defguard.net";
# license = licenses.gpl3Only;
maintainers = with maintainers; [];
platforms = platforms.linux;
};
})
37 changes: 37 additions & 0 deletions nix/shell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{pkgs ? import <nixpkgs> {}}: let
# add development-related cargo tooling
rustToolchain = pkgs.rust-bin.stable.latest.default.override {
extensions = ["rust-analyzer" "rust-src" "rustfmt" "clippy"];
targets = ["x86_64-apple-darwin" "aarch64-apple-darwin" "x86_64-pc-windows-gnu"];
};

defguard-client = pkgs.callPackage ./package.nix {};

# runtime libraries needed to run the dev server
libraries = with pkgs; [
libayatana-appindicator
];
in
pkgs.mkShell {
# inherit build inputs from the package
inputsFrom = [defguard-client];

# add additional dev tools
packages = with pkgs; [
trunk
sqlx-cli
vtsls
];

shellHook = with pkgs; ''
export LD_LIBRARY_PATH="${
lib.makeLibraryPath libraries
}:$LD_LIBRARY_PATH"
export OPENSSL_INCLUDE_DIR="${pkgs.openssl.dev}/include/openssl"
export OPENSSL_LIB_DIR="${pkgs.openssl.out}/lib"
export OPENSSL_ROOT_DIR="${pkgs.openssl.out}"
# https://discourse.nixos.org/t/which-package-includes-org-gtk-gtk4-settings-filechooser/38063/12
export XDG_DATA_DIRS="${pkgs.gtk3}/share/gsettings-schemas/gtk+3-${pkgs.gtk3.dev.version}:$XDG_DATA_DIRS"
export RUST_SRC_PATH="${rustToolchain}/lib/rustlib/src/rust/library"
'';
}