This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

configs.radicale: add calino web client on calendar.lassul.us

+132 -5
+75 -5
configs/radicale.nix
··· 2 2 config, 3 3 lib, 4 4 pkgs, 5 + self, 5 6 ... 6 7 }: 7 8 let ··· 42 43 assembleHtpasswd = pkgs.writeShellScript "radicale-htpasswd" ( 43 44 lib.concatMapStringsSep "\n" (user: "cat \${CREDENTIALS_DIRECTORY}/radicale-${user}-htpasswd") users 44 45 ); 46 + 47 + # Calino (static, local-first CalDAV web client) on its own origin; accounts 48 + # and settings stay in the browser, so nothing is stored server-side. Log in 49 + # with server https://cal.lassul.us/ and a radicale user. 50 + webClient = "calendar.lassul.us"; 51 + calino = self.packages.${pkgs.stdenv.hostPlatform.system}.calino; 52 + 53 + proxyHeaders = '' 54 + proxy_set_header X-Script-Name /; 55 + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 56 + proxy_set_header Host $host; 57 + ''; 58 + 59 + # CORS for the web client; see the maps in appendHttpConfig below. 60 + cors = '' 61 + add_header Access-Control-Allow-Origin $radicale_cors_origin always; 62 + add_header Access-Control-Allow-Methods "GET, PUT, DELETE, PROPFIND, PROPPATCH, REPORT, OPTIONS, MKCOL, MKCALENDAR, MOVE" always; 63 + add_header Access-Control-Allow-Headers "Authorization, Content-Type, Depth, Prefer, If-Match, If-None-Match" always; 64 + add_header Access-Control-Expose-Headers "ETag, Location, DAV, Allow, X-Sync-Token" always; 65 + add_header Access-Control-Max-Age 86400 always; 66 + add_header Vary Origin always; 67 + if ($radicale_cors_preflight) { 68 + return 204; 69 + } 70 + ''; 45 71 in 46 72 { 47 73 services.radicale = { ··· 74 100 75 101 clan.core.vars.generators = userGenerators; 76 102 103 + # Let the web client's origin talk CalDAV to radicale. Preflights carry no 104 + # credentials and are answered here; a plain DAV OPTIONS (no 105 + # Access-Control-Request-Method) still reaches radicale. 106 + services.nginx.appendHttpConfig = '' 107 + map $http_origin $radicale_cors_origin { 108 + default ""; 109 + "https://${webClient}" $http_origin; 110 + } 111 + map "$request_method:$http_access_control_request_method" $radicale_cors_preflight { 112 + default 0; 113 + "~^OPTIONS:." 1; 114 + } 115 + # Top-level navigations send no Origin; the web client's GET / probes 116 + # (CalDAV discovery via /.well-known/caldav) do and must reach radicale. 117 + map "$request_method:$http_origin" $radicale_root_redirect { 118 + default 0; 119 + "GET:" 1; 120 + } 121 + ''; 122 + 77 123 services.nginx.virtualHosts."cal.lassul.us" = { 78 124 forceSSL = true; 79 125 enableACME = true; 126 + # Browsers opening the bare domain get the web client; CalDAV discovery 127 + # (PROPFIND /, or the web client's cross-origin GET /) still reaches 128 + # radicale. 129 + locations."= /" = { 130 + proxyPass = "http://127.0.0.1:5232"; 131 + extraConfig = 132 + cors 133 + + '' 134 + if ($radicale_root_redirect) { 135 + return 302 https://${webClient}/; 136 + } 137 + '' 138 + + proxyHeaders; 139 + }; 80 140 locations."/" = { 81 141 proxyPass = "http://127.0.0.1:5232"; 82 - extraConfig = '' 83 - proxy_set_header X-Script-Name /; 84 - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 85 - proxy_set_header Host $host; 86 - ''; 142 + extraConfig = cors + proxyHeaders; 87 143 }; 144 + }; 145 + 146 + services.nginx.virtualHosts.${webClient} = { 147 + forceSSL = true; 148 + enableACME = true; 149 + root = calino; 150 + locations."/".extraConfig = '' 151 + try_files $uri /index.html; 152 + add_header Cache-Control no-cache; 153 + ''; 154 + # Vite puts content-hashed bundles here. 155 + locations."/assets/".extraConfig = '' 156 + add_header Cache-Control "public, max-age=31536000, immutable"; 157 + ''; 88 158 }; 89 159 }
+57
pkgs/calino/package.nix
··· 1 + { 2 + lib, 3 + stdenv, 4 + fetchFromGitHub, 5 + nodejs, 6 + pnpm_10, 7 + fetchPnpmDeps, 8 + pnpmConfigHook, 9 + }: 10 + 11 + # Calino: a static, local-first CalDAV web client. Accounts, settings and the 12 + # event cache live in the browser; there is no backend. The CalDAV server has 13 + # to allow the origin Calino is served from via CORS. 14 + stdenv.mkDerivation (finalAttrs: { 15 + pname = "calino"; 16 + version = "0.38.0"; 17 + 18 + src = fetchFromGitHub { 19 + owner = "Ivan-Malinovski"; 20 + repo = "calino"; 21 + tag = "v${finalAttrs.version}"; 22 + hash = "sha256-DaT4vJB1/zTPwWnoDvHHQT7XlhmctHVLMIoedgs/1B4="; 23 + }; 24 + 25 + pnpmDeps = fetchPnpmDeps { 26 + inherit (finalAttrs) pname version src; 27 + pnpm = pnpm_10; 28 + fetcherVersion = 4; 29 + hash = "sha256-7V/Ej1xiVu8b4sLiADulSZtZ0kb3nRzTqqYfIGTPxGc="; 30 + }; 31 + 32 + nativeBuildInputs = [ 33 + nodejs 34 + pnpm_10 35 + pnpmConfigHook 36 + ]; 37 + 38 + buildPhase = '' 39 + runHook preBuild 40 + pnpm run build 41 + runHook postBuild 42 + ''; 43 + 44 + installPhase = '' 45 + runHook preInstall 46 + cp -r dist $out 47 + runHook postInstall 48 + ''; 49 + 50 + meta = { 51 + description = "Local-first CalDAV calendar web client (static files)"; 52 + homepage = "https://github.com/Ivan-Malinovski/calino"; 53 + changelog = "https://github.com/Ivan-Malinovski/calino/blob/v${finalAttrs.version}/CHANGELOG.md"; 54 + license = lib.licenses.mit; 55 + platforms = lib.platforms.all; 56 + }; 57 + })