caesium: accounts and yubikey
This commit is contained in:
+141
-7
@@ -1,26 +1,160 @@
|
|||||||
{ config, pkgs, ... }: {
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
# Wraps the interactive pamu2fcfg ceremony (touch required, can't be
|
||||||
|
# scripted away) so the repo's yubikey.u2f-mappings file always ends up
|
||||||
|
# well-formed: one line per user, credentials colon-separated. See
|
||||||
|
# module.yubikey.nix for how the file is consumed.
|
||||||
|
yubikeyEnroll = pkgs.writeShellApplication {
|
||||||
|
name = "yubikey-enroll";
|
||||||
|
runtimeInputs = [ pkgs.pam_u2f pkgs.gawk pkgs.gnugrep ];
|
||||||
|
text = ''
|
||||||
|
REPO="''${YUBIKEY_REPO:-$HOME/nixos}"
|
||||||
|
MAP_FILE="$REPO/yubikey.u2f-mappings"
|
||||||
|
USERNAME="''${1:-$(whoami)}"
|
||||||
|
|
||||||
|
if [[ ! -f "$MAP_FILE" ]]; then
|
||||||
|
echo "error: $MAP_FILE not found (expected the nixos repo checkout at $REPO)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
existing_line="$(grep "^''${USERNAME}:" "$MAP_FILE" || true)"
|
||||||
|
|
||||||
|
echo "Insert the YubiKey to enroll, then touch it when it blinks."
|
||||||
|
if [[ -z "$existing_line" ]]; then
|
||||||
|
new_line="$(pamu2fcfg -u "$USERNAME" -o pam://mbessette -i pam://mbessette)"
|
||||||
|
else
|
||||||
|
cred="$(pamu2fcfg -n -o pam://mbessette -i pam://mbessette)"
|
||||||
|
new_line="''${existing_line}:''${cred}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$(printf '%s\n' "$new_line" | wc -l)" -ne 1 ]]; then
|
||||||
|
echo "error: unexpected multi-line credential output, aborting without writing" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
if [[ -z "$existing_line" ]]; then
|
||||||
|
{ grep -v "^''${USERNAME}:" "$MAP_FILE" || true; printf '%s\n' "$new_line"; } > "$tmp"
|
||||||
|
else
|
||||||
|
awk -F: -v u="$USERNAME" -v line="$new_line" 'BEGIN{OFS=":"} $1==u {print line; next} {print}' "$MAP_FILE" > "$tmp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
n=$(grep -c "^''${USERNAME}:" "$tmp")
|
||||||
|
if [[ "$n" -ne 1 ]]; then
|
||||||
|
echo "error: expected exactly one line for $USERNAME, got $n; not writing" >&2
|
||||||
|
rm -f "$tmp"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv "$tmp" "$MAP_FILE"
|
||||||
|
count=$(awk -F: -v u="$USERNAME" '$1==u{print NF-1}' "$MAP_FILE")
|
||||||
|
echo "Enrolled. $USERNAME now has $count credential(s) in $MAP_FILE."
|
||||||
|
echo "Review the diff, then run nix-update to install it to /etc/u2f_mappings."
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
yubikeyUnenroll = pkgs.writeShellApplication {
|
||||||
|
name = "yubikey-unenroll";
|
||||||
|
runtimeInputs = [ pkgs.gawk pkgs.gnugrep pkgs.coreutils ];
|
||||||
|
text = ''
|
||||||
|
REPO="''${YUBIKEY_REPO:-$HOME/nixos}"
|
||||||
|
MAP_FILE="$REPO/yubikey.u2f-mappings"
|
||||||
|
|
||||||
|
if [[ ! -f "$MAP_FILE" ]]; then
|
||||||
|
echo "error: $MAP_FILE not found (expected the nixos repo checkout at $REPO)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
list_credentials() {
|
||||||
|
local user="$1" line
|
||||||
|
line="$(grep "^''${user}:" "$MAP_FILE" || true)"
|
||||||
|
if [[ -z "$line" ]]; then
|
||||||
|
echo "$user: no credentials enrolled"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
awk -F: -v u="$user" '$1==u {
|
||||||
|
for (i=2;i<=NF;i++) { split($i, f, ","); printf " %d: %s...\n", i-1, substr(f[1],1,16) }
|
||||||
|
}' <<<"$line"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
echo "usage: yubikey-unenroll <index> [username] (no args: list credentials)"
|
||||||
|
while IFS= read -r user; do
|
||||||
|
list_credentials "$user"
|
||||||
|
done < <(awk -F: '{print $1}' "$MAP_FILE" | sort -u)
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
INDEX="$1"
|
||||||
|
USERNAME="''${2:-$(whoami)}"
|
||||||
|
|
||||||
|
if ! [[ "$INDEX" =~ ^[0-9]+$ ]]; then
|
||||||
|
echo "error: index must be a positive integer" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
line="$(grep "^''${USERNAME}:" "$MAP_FILE" || true)"
|
||||||
|
if [[ -z "$line" ]]; then
|
||||||
|
echo "error: no entry for $USERNAME in $MAP_FILE" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
count=$(( $(awk -F: '{print NF}' <<<"$line") - 1 ))
|
||||||
|
if [[ "$INDEX" -lt 1 || "$INDEX" -gt "$count" ]]; then
|
||||||
|
echo "error: $USERNAME has $count credential(s); index must be 1..$count" >&2
|
||||||
|
list_credentials "$USERNAME"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
new_line="$(awk -F: -v OFS=: -v idx="$INDEX" '{ out=$1; for (i=2;i<=NF;i++) if (i-1!=idx) out=out OFS $i; print out }' <<<"$line")"
|
||||||
|
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
if [[ "$count" -eq 1 ]]; then
|
||||||
|
awk -F: -v u="$USERNAME" '$1!=u' "$MAP_FILE" > "$tmp"
|
||||||
|
else
|
||||||
|
awk -F: -v u="$USERNAME" -v line="$new_line" 'BEGIN{OFS=":"} $1==u {print line; next} {print}' "$MAP_FILE" > "$tmp"
|
||||||
|
fi
|
||||||
|
mv "$tmp" "$MAP_FILE"
|
||||||
|
|
||||||
|
echo "Removed credential #$INDEX for $USERNAME. $((count - 1)) credential(s) remain."
|
||||||
|
if [[ "$count" -eq 1 ]]; then
|
||||||
|
echo "Note: $USERNAME now has zero credentials -- pam_u2f falls through to password (control=sufficient), not a lockout."
|
||||||
|
fi
|
||||||
|
echo "Review the diff in $MAP_FILE, then run nix-update to apply it."
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./programs.vscode.nix
|
./programs.vscode.nix
|
||||||
./programs.thunderbird.nix
|
./programs.thunderbird.nix
|
||||||
|
./module.accounts.nix
|
||||||
|
./module.evolution.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
programs.firefox.enable = true;
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
firefox
|
|
||||||
wowup-cf
|
wowup-cf
|
||||||
faugus-launcher
|
faugus-launcher
|
||||||
|
yubikeyEnroll
|
||||||
|
yubikeyUnenroll
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.user.sessionVariables = {
|
|
||||||
## Required to fix firefox unrendered addressbar and tabs
|
|
||||||
XDG_DATA_DIRS = "${config.home.homeDirectory}/.nix-profile/share:/usr/local/share:/usr/share";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.flatpak = {
|
services.flatpak = {
|
||||||
|
# nix-flatpak's home-manager module always manages the "user" flatpak
|
||||||
|
# installation, independent of NixOS's services.flatpak.enable (system
|
||||||
|
# scope) below in caesium.nixos.nix. Standalone home-manager has no
|
||||||
|
# osConfig to inherit from, so this must be set explicitly.
|
||||||
enable = true;
|
enable = true;
|
||||||
|
uninstallUnmanaged = true;
|
||||||
packages = [
|
packages = [
|
||||||
"com.spotify.Client"
|
"com.spotify.Client"
|
||||||
"com.discordapp.Discord"
|
"com.discordapp.Discord"
|
||||||
|
"org.signal.Signal"
|
||||||
|
"io.openrct2.OpenRCT2"
|
||||||
|
"io.github.enginkirmaci.lumux"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
imports = [
|
imports = [
|
||||||
./caesium.hardware.nix # Crucial: Imports your UUIDs
|
./caesium.hardware.nix # Crucial: Imports your UUIDs
|
||||||
./module.firewall.nix
|
./module.firewall.nix
|
||||||
|
./module.yubikey.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
time.timeZone = "America/New_York";
|
time.timeZone = "America/New_York";
|
||||||
@@ -161,9 +162,25 @@
|
|||||||
services.displayManager.sddm.enable = true;
|
services.displayManager.sddm.enable = true;
|
||||||
services.desktopManager.plasma6.enable = true;
|
services.desktopManager.plasma6.enable = true;
|
||||||
|
|
||||||
|
# Registers the evolution-data-server D-Bus services/systemd user units so
|
||||||
|
# GNOME Calendar, GNOME Contacts and Planify can share calendars/contacts
|
||||||
|
# (see module.evolution.nix). Deliberately NOT programs.evolution.enable,
|
||||||
|
# which force-enables services.gnome.gnome-keyring and would fight kwallet
|
||||||
|
# for ownership of org.freedesktop.secrets.
|
||||||
|
services.gnome.evolution-data-server.enable = true;
|
||||||
|
|
||||||
# Tell SDDM to use Wayland for the login screen itself (Ultra Modern)
|
# Tell SDDM to use Wayland for the login screen itself (Ultra Modern)
|
||||||
services.displayManager.sddm.wayland.enable = true;
|
services.displayManager.sddm.wayland.enable = true;
|
||||||
|
|
||||||
|
# GTK apps (Firefox, Thunderbird) read their theme through GtkSettings, which needs the
|
||||||
|
# org.gtk.Settings.* / org.gnome.desktop.interface GSettings schemas. Plasma is Qt-based so
|
||||||
|
# nothing pulls them into the system profile, and the Mozilla wrappers don't add them
|
||||||
|
# themselves — without this their chrome renders black.
|
||||||
|
environment.sessionVariables.XDG_DATA_DIRS = [
|
||||||
|
"${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}"
|
||||||
|
"${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}"
|
||||||
|
];
|
||||||
|
|
||||||
fonts.packages = with pkgs; [
|
fonts.packages = with pkgs; [
|
||||||
noto-fonts
|
noto-fonts
|
||||||
noto-fonts-cjk-sans
|
noto-fonts-cjk-sans
|
||||||
@@ -219,6 +236,7 @@
|
|||||||
python3
|
python3
|
||||||
nodejs_26
|
nodejs_26
|
||||||
home-manager
|
home-manager
|
||||||
|
glib
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.appimage = {
|
programs.appimage = {
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
{ ... }:
|
||||||
|
let
|
||||||
|
davHost = "cloud.thiccdata.io";
|
||||||
|
davUser = "mbessette";
|
||||||
|
|
||||||
|
mkGmailAccount = address: realName: {
|
||||||
|
inherit address realName;
|
||||||
|
flavor = "gmail.com";
|
||||||
|
thunderbird.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkCalendar = collection: {
|
||||||
|
remote = {
|
||||||
|
type = "caldav";
|
||||||
|
url = "https://${davHost}/remote.php/dav/calendars/${davUser}/${collection}/";
|
||||||
|
userName = davUser;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkAddressBook = book: {
|
||||||
|
remote = {
|
||||||
|
type = "carddav";
|
||||||
|
url = "https://${davHost}/remote.php/dav/addressbooks/users/${davUser}/${book}/";
|
||||||
|
userName = davUser;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
accounts.calendar.basePath = ".calendars";
|
||||||
|
accounts.contact.basePath = ".contacts";
|
||||||
|
|
||||||
|
accounts.email.accounts = {
|
||||||
|
personal = mkGmailAccount "blade30912@gmail.com" "Matthew Bessette" // {
|
||||||
|
primary = true;
|
||||||
|
};
|
||||||
|
bessette = mkGmailAccount "bessette.matthew94@gmail.com" "Matthew Bessette";
|
||||||
|
house = mkGmailAccount "mbessette.house@gmail.com" "Matthew Bessette";
|
||||||
|
joseph = mkGmailAccount "joseph.lamothe55@gmail.com" "Joseph Lamothe";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Calendars and the address book are consumed via evolution-data-server
|
||||||
|
# (see module.evolution.nix) rather than Thunderbird's own calendar/address
|
||||||
|
# book code. Only email accounts opt in to Thunderbird.
|
||||||
|
accounts.calendar.accounts = {
|
||||||
|
family = mkCalendar "test";
|
||||||
|
matt = mkCalendar "matt-calendar" // {
|
||||||
|
primary = true;
|
||||||
|
};
|
||||||
|
joseph-cal = mkCalendar "joseph-calendar";
|
||||||
|
};
|
||||||
|
|
||||||
|
accounts.contact.accounts = {
|
||||||
|
contacts = mkAddressBook "contacts";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
calendarAccounts = config.accounts.calendar.accounts;
|
||||||
|
contactAccounts = config.accounts.contact.accounts;
|
||||||
|
|
||||||
|
# Nextcloud stores VTODOs in the same CalDAV collections as VEVENTs, so a
|
||||||
|
# calendar account can also be exposed to task-list clients (Planify) by
|
||||||
|
# emitting a second EDS source against the same collection.
|
||||||
|
tasksFrom = [ "matt" ];
|
||||||
|
|
||||||
|
# Per-calendar accent colors, previously set on the (now removed)
|
||||||
|
# `thunderbird.color` attrs in module.accounts.nix.
|
||||||
|
calendarColors = {
|
||||||
|
family = "#FED3D9";
|
||||||
|
matt = "#FDF0D7";
|
||||||
|
joseph-cal = "#CEF4F8";
|
||||||
|
};
|
||||||
|
|
||||||
|
splitUrl = url:
|
||||||
|
let
|
||||||
|
stripped = lib.removePrefix "https://" url;
|
||||||
|
host = lib.head (lib.splitString "/" stripped);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit host;
|
||||||
|
resourcePath = lib.removePrefix host stripped;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkAuth = remote:
|
||||||
|
let
|
||||||
|
s = splitUrl remote.url;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"Security" = {
|
||||||
|
Method = "tls";
|
||||||
|
};
|
||||||
|
"Authentication" = {
|
||||||
|
Host = s.host;
|
||||||
|
Port = "443";
|
||||||
|
User = remote.userName;
|
||||||
|
Method = "plain/password";
|
||||||
|
RememberPassword = "true";
|
||||||
|
};
|
||||||
|
"WebDAV Backend" = {
|
||||||
|
ResourcePath = s.resourcePath;
|
||||||
|
};
|
||||||
|
"Offline" = {
|
||||||
|
StaySynchronized = "true";
|
||||||
|
};
|
||||||
|
"Refresh" = {
|
||||||
|
Enabled = "true";
|
||||||
|
IntervalMinutes = "30";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
toIni = sections:
|
||||||
|
lib.concatStringsSep "\n" (
|
||||||
|
lib.mapAttrsToList
|
||||||
|
(section: keys: ''
|
||||||
|
[${section}]
|
||||||
|
${lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k}=${v}") keys)}
|
||||||
|
'')
|
||||||
|
sections
|
||||||
|
);
|
||||||
|
|
||||||
|
mkCalendarSource = name: account:
|
||||||
|
let
|
||||||
|
uid = "nextcloud-${name}";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit uid;
|
||||||
|
text = toIni ({
|
||||||
|
"Data Source" = {
|
||||||
|
DisplayName = name;
|
||||||
|
Enabled = "true";
|
||||||
|
Parent = "caldav-stub";
|
||||||
|
};
|
||||||
|
"Calendar" = {
|
||||||
|
BackendName = "caldav";
|
||||||
|
Color = calendarColors.${name} or "#3584E4";
|
||||||
|
Selected = "true";
|
||||||
|
};
|
||||||
|
} // mkAuth account.remote);
|
||||||
|
};
|
||||||
|
|
||||||
|
mkTaskListSource = name: account:
|
||||||
|
let
|
||||||
|
uid = "nextcloud-${name}-tasks";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit uid;
|
||||||
|
text = toIni ({
|
||||||
|
"Data Source" = {
|
||||||
|
DisplayName = "${name} (Tasks)";
|
||||||
|
Enabled = "true";
|
||||||
|
Parent = "caldav-stub";
|
||||||
|
};
|
||||||
|
"Task List" = {
|
||||||
|
BackendName = "caldav";
|
||||||
|
Color = calendarColors.${name} or "#3584E4";
|
||||||
|
Selected = "true";
|
||||||
|
};
|
||||||
|
} // mkAuth account.remote);
|
||||||
|
};
|
||||||
|
|
||||||
|
mkContactSource = name: account:
|
||||||
|
let
|
||||||
|
uid = "nextcloud-${name}";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit uid;
|
||||||
|
text = toIni ({
|
||||||
|
"Data Source" = {
|
||||||
|
DisplayName = name;
|
||||||
|
Enabled = "true";
|
||||||
|
Parent = "carddav-stub";
|
||||||
|
};
|
||||||
|
"Address Book" = {
|
||||||
|
BackendName = "carddav";
|
||||||
|
};
|
||||||
|
} // mkAuth account.remote);
|
||||||
|
};
|
||||||
|
|
||||||
|
calendarSources = lib.mapAttrsToList mkCalendarSource calendarAccounts;
|
||||||
|
taskListSources = lib.mapAttrsToList mkTaskListSource
|
||||||
|
(lib.filterAttrs (name: _: builtins.elem name tasksFrom) calendarAccounts);
|
||||||
|
contactSources = lib.mapAttrsToList mkContactSource contactAccounts;
|
||||||
|
|
||||||
|
allSources = calendarSources ++ taskListSources ++ contactSources;
|
||||||
|
|
||||||
|
sourceFile = src: pkgs.writeText "${src.uid}.source" src.text;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
gnome-calendar
|
||||||
|
gnome-contacts
|
||||||
|
planify
|
||||||
|
libsecret
|
||||||
|
];
|
||||||
|
|
||||||
|
# evolution-data-server treats files under ~/.config/evolution/sources/ as
|
||||||
|
# writable/removable and rewrites them on connect and on any in-app tweak
|
||||||
|
# (color, visibility, ...). A /nix/store symlink can't be written back to,
|
||||||
|
# so these are copied into place as real files on every activation instead
|
||||||
|
# of managed via xdg.configFile.
|
||||||
|
home.activation.evolutionSources = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
||||||
|
lib.concatMapStringsSep "\n"
|
||||||
|
(src: ''
|
||||||
|
install -Dm644 ${sourceFile src} "$HOME/.config/evolution/sources/${src.uid}.source"
|
||||||
|
'')
|
||||||
|
allSources
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# YubiKey (FIDO2/U2F) login via pam_u2f.
|
||||||
|
#
|
||||||
|
# `security.pam.u2f.enable = true` defaults every PAM service's `u2fAuth` to
|
||||||
|
# true, so this covers sudo, sddm/sddm-greeter, the Plasma lock screen (the
|
||||||
|
# `kde` service, added by services.desktopManager.plasma6), login, and su
|
||||||
|
# without listing them individually. `control = "sufficient"` means a touch
|
||||||
|
# skips the password, but the password always still works — losing both
|
||||||
|
# enrolled keys can never lock this account out.
|
||||||
|
#
|
||||||
|
# /etc/u2f_mappings starts empty. Enroll keys after the first switch with the
|
||||||
|
# `yubikey-enroll` / `yubikey-unenroll` scripts (defined in caesium.home.nix),
|
||||||
|
# which wrap the interactive pamu2fcfg touch ceremony and keep
|
||||||
|
# yubikey.u2f-mappings well-formed; then re-run nix-update. An empty/missing
|
||||||
|
# mapping just falls through to the password, so this is safe to deploy
|
||||||
|
# before enrollment.
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.pcscd.enable = true;
|
||||||
|
services.udev.packages = [
|
||||||
|
pkgs.yubikey-personalization
|
||||||
|
pkgs.libfido2
|
||||||
|
];
|
||||||
|
|
||||||
|
security.pam.u2f = {
|
||||||
|
enable = true;
|
||||||
|
control = "sufficient";
|
||||||
|
settings = {
|
||||||
|
cue = true;
|
||||||
|
authfile = "/etc/u2f_mappings";
|
||||||
|
origin = "pam://mbessette";
|
||||||
|
appid = "pam://mbessette";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.etc."u2f_mappings".source = ./yubikey.u2f-mappings;
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
pam_u2f
|
||||||
|
yubikey-manager
|
||||||
|
libfido2
|
||||||
|
];
|
||||||
|
}
|
||||||
+19
-63
@@ -1,31 +1,12 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
let
|
||||||
tbPkg = if pkgs.stdenv.isDarwin then pkgs.thunderbird-bin else pkgs.thunderbird;
|
tbPkg = if pkgs.stdenv.isDarwin then pkgs.thunderbird-bin else pkgs.thunderbird;
|
||||||
|
|
||||||
mkGmailAccount = address: realName: {
|
|
||||||
inherit address realName;
|
|
||||||
flavor = "gmail.com";
|
|
||||||
thunderbird.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
mkCalendar = collection: {
|
|
||||||
remote = {
|
|
||||||
type = "caldav";
|
|
||||||
url = "https://cloud.thiccdata.io/remote.php/dav/calendars/mbessette/${collection}/";
|
|
||||||
userName = "mbessette";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
mkAddressBook = book: {
|
|
||||||
remote = {
|
|
||||||
type = "carddav";
|
|
||||||
url = "https://cloud.thiccdata.io/remote.php/dav/addressbooks/users/mbessette/${book}/";
|
|
||||||
userName = "mbessette";
|
|
||||||
};
|
|
||||||
thunderbird.enable = true;
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
# Account definitions (email/calendar/contact) live in module.accounts.nix,
|
||||||
|
# shared with evolution-data-server (module.evolution.nix). Only email
|
||||||
|
# accounts opt in to Thunderbird; calendars and the address book are
|
||||||
|
# consumed via GNOME/EDS instead, so Thunderbird is mail-only.
|
||||||
programs.thunderbird = {
|
programs.thunderbird = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = tbPkg;
|
package = tbPkg;
|
||||||
@@ -33,48 +14,23 @@ in
|
|||||||
profiles.default = {
|
profiles.default = {
|
||||||
isDefault = true;
|
isDefault = true;
|
||||||
accountsOrder = [ "personal" ];
|
accountsOrder = [ "personal" ];
|
||||||
};
|
|
||||||
|
settings = {
|
||||||
|
"mail.chat.enabled" = false;
|
||||||
|
"calendar.itip.showImipBar" = false;
|
||||||
|
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
accounts.calendar.basePath = ".calendars";
|
# Hide the calendar/tasks/chat spaces so Thunderbird presents as an
|
||||||
accounts.contact.basePath = ".contacts";
|
# email-only client. The address book space stays (local/collected
|
||||||
|
# addresses + autocomplete still live there).
|
||||||
accounts.email.accounts = {
|
userChrome = ''
|
||||||
personal = mkGmailAccount "blade30912@gmail.com" "Matthew Bessette" // {
|
#calendarButton,
|
||||||
primary = true;
|
#tasksButton,
|
||||||
|
#chatButton {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
bessette = mkGmailAccount "bessette.matthew94@gmail.com" "Matthew Bessette";
|
|
||||||
house = mkGmailAccount "mbessette.house@gmail.com" "Matthew Bessette";
|
|
||||||
joseph = mkGmailAccount "joseph.lamothe55@gmail.com" "Joseph Lamothe";
|
|
||||||
};
|
|
||||||
|
|
||||||
accounts.calendar.accounts = {
|
|
||||||
family = mkCalendar "test" // {
|
|
||||||
thunderbird = {
|
|
||||||
enable = true;
|
|
||||||
color = "#FED3D9";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
matt = mkCalendar "matt-calendar" // {
|
|
||||||
primary = true;
|
|
||||||
thunderbird = {
|
|
||||||
enable = true;
|
|
||||||
color = "#FDF0D7";
|
|
||||||
settings = id: {
|
|
||||||
"calendar.registry.${id}.imip.identity.key" =
|
|
||||||
"id_${builtins.hashString "sha256" "personal"}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
joseph-cal = mkCalendar "joseph-calendar" // {
|
|
||||||
thunderbird = {
|
|
||||||
enable = true;
|
|
||||||
color = "#CEF4F8";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
accounts.contact.accounts = {
|
|
||||||
contacts = mkAddressBook "contacts";
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
{ config, pkgs, ... }: {
|
{ config, pkgs, ... }: {
|
||||||
|
|
||||||
xdg.configFile."oxlint/oxlintrc.json".source =
|
xdg.configFile."oxlint/oxlintrc.json".source =
|
||||||
config.lib.file.mkOutOfStoreSymlink "/Users/matthew.bessette/nixos/config.oxlintrc.json";
|
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/nixos/config.oxlintrc.json";
|
||||||
xdg.configFile."biome/biome.json".source =
|
xdg.configFile."biome/biome.json".source =
|
||||||
config.lib.file.mkOutOfStoreSymlink "/Users/matthew.bessette/nixos/config.biome.json";
|
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/nixos/config.biome.json";
|
||||||
|
|
||||||
programs.vscode = {
|
programs.vscode = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
mbessette:PusBTtTXC1flzOLV/pqIiz0xoiYLfbd8sMiLPdMuqbvg/IM0pylvB1kNYYJYadlivlshkITYB41h6yv2ouiPHw==,wkf3QAvo+NMZecX4KZO2urNeKB2086cYx0k5vGzvwYxFAS4SD92POq3uBjNg8kMwLlqgQbyJS0aEAdClyvzchQ==,es256,+presence::ttMJESYFH+swvoq3DXA23U9gnvKi12yleSz3GoKZ1sb/+pusgz6rc2B2LE3AJ5o9L/Pj5eEMjFFv0VUjfBuv4w==,m/SxBY1LuX//kxIA3RcnfjX7cnfVkQMRyNGbplhtUnHVfivx4zGLdIqWPUWVXJHV/pXax1IGxwVZeyz2EuQr/A==,es256,+presence
|
||||||
Reference in New Issue
Block a user