Skip to content

Instantly share code, notes, and snippets.

@teh
Created August 13, 2024 10:22
Show Gist options
  • Save teh/e6d12f942b17788a44138712c13615d0 to your computer and use it in GitHub Desktop.
Save teh/e6d12f942b17788a44138712c13615d0 to your computer and use it in GitHub Desktop.
{ fetchzip
, electron-bin
, input-fonts
, fetchurl
, fetchFromGitHub
, stdenv
, pkgs
, buildNpmPackage
, lib
, asar
, autoPatchelfHook
, git
, gnused
, makeShellWrapper
, python3
, wrapGAppsHook
, alsa-lib
, at-spi2-atk
, at-spi2-core
, atk
, cups
, electron
, flac
, gdk-pixbuf
, gtk3
, libpulseaudio
, libwebp
, libxslt
, mesa # for libgbm
, nspr
, nss
, pango
, xdg-utils
, gitUpdater
}:
let
input-fonts = input-fonts.overrideAttrs (_old: {
src = fetchzip {
# This URL is too long for fetchzip, and returns non-reproducible zips with new sha256 every time ☹️
# url = "https://input.djr.com/build/?customize&fontSelection=fourStyleFamily&regular=InputMonoNarrow-Regular&italic=InputMonoNarrow-Italic&bold=InputMonoNarrow-Bold&boldItalic=InputMonoNarrow-BoldItalic&a=0&g=0&i=serifs_round&l=serifs_round&zero=slash&asterisk=height&braces=0&preset=default&line-height=1.1&accept=I+do&email=";
url = "https://maximbaz.com/input-fonts.zip";
sha256 = "09qfb3h2s1dlf6kn8d4f5an6jhfpihn02zl02sjj26zgclrp6blc";
stripRoot = false;
};
});
wldash = wldash.override (old: {
rustPlatform = old.rustPlatform // {
buildRustPackage = args: old.rustPlatform.buildRustPackage (args // {
src = fetchFromGitHub {
owner = "cyrinux";
repo = "wldash";
rev = "9cc29f2507a746ef6359dd081d9f2fe2f43c2a23";
hash = "sha256-aATJIHETQDX1UXkn5/1jVESgdQFbTFySYuL01NvP54s=";
};
cargoSha256 = "sha256-Ot+GnnbFFS6e86uhNDoujlX/oQX9Ckp+M467sXJOD60=";
cargoPatches = [ ];
});
};
});
# it was never meant to be packaged with --libnotify by default ☹️
yubikey-touch-detector = yubikey-touch-detector.overrideAttrs (old: {
postInstall = old.postInstall + ''
substituteInPlace $out/lib/systemd/user/*.service --replace "--libnotify" ""
'';
});
joypixels = joypixels.overrideAttrs (_old: {
version = "9.0.0";
src = fetchurl {
name = "joypixels-android.ttf";
url = "https://maximbaz.com/joypixels-emoji.ttf";
sha256 = "0ghh5s4ri4lpf43nnpjck9g3y6s4cl9mwkjq78wzfaqj0rbaqqd6";
};
});
maximbaz-scripts = pkgs.stdenv.mkDerivation {
pname = "maximbaz-scripts";
version = "1.0.0";
src = ./bin;
dontUnpack = true;
nativeBuildInputs = [ pkgs.makeWrapper ];
installPhase = ''
install -Dm755 $src/* -t $out/bin/
install -Dm755 $src/dmenu $out/bin/dmenu-wl
'';
postFixup = ''
for script in $out/bin/*; do
wrapProgram $script \
--suffix PATH : /run/wrappers/bin/ \
--suffix PATH : /etc/profiles/per-user/maximbaz/bin/ \
--suffix PATH : /run/current-system/sw/bin/ \
;
done
'';
};
version = "7.16.0";
ringrtcPrebuild = fetchurl {
# version is found in signal-desktop's package.json as "@signalapp/ringrtc"
url = "https://build-artifacts.signal.org/libraries/ringrtc-desktop-build-v2.44.0.tar.gz";
hash = "sha256-pxfwfEpz6kOlvNcAmnCcwUncKAql8dDPnWUcDV6rWag=";
};
sqlcipherTarball = fetchurl {
# this is a dependency of better-sqlite3.
# version/url is found in <repo:https://github.com/signalapp/better-sqlite3:deps/download.js>
# - checkout the better-sqlite3 tag which matches signal-dekstop's package.json "@signalapp/better-sqlite3" key.
url = "https://build-artifacts.signal.org/desktop/sqlcipher-4.5.5-fts5-fix--3.0.7--0.2.1-ef53ea45ed92b928ecfd33c552d8d405263e86e63dec38e1ec63e1b0193b630b.tar.gz";
hash = "sha256-71PqRe2SuSjs/TPFUtjUBSY+huY97Djh7GPhsBk7Yws=";
};
# signal-fts5-extension = callPackage ./fts5-extension { };
# bettersqlitePatch = substituteAll {
# # this patch does more than just use the system sqlcipher.
# # it also tells bettersqlite to link against its needed runtime dependencies,
# # since there's a few statically linked things which aren't called out.
# # it also tells bettersqlite not to download sqlcipher when we `npm rebuild`
# src = ./bettersqlite-use-system-sqlcipher.patch;
# inherit sqlcipher;
# inherit (nodejs') libv8;
# signal_fts5_extension = signal-fts5-extension;
# };
src = fetchFromGitHub {
owner = "signalapp";
repo = "Signal-Desktop";
leaveDotGit = true; # signal calculates the release date via `git`
rev = "v${version}";
hash = "sha256-5retGy21FLcfrJSWyE4VoZgUqd/cTlBHTUwsk8Ou+cQ=";
};
# note that `package.json` locks the electron version, but we seem to not be strictly beholden to that.
# prefer to use the same electron version as everywhere else, and a `-bin` version to avoid 4hr rebuilds.
# the non-bin varieties *seem* to ship the wrong `electron.headers` property.
# - maybe they can work if i manually DL and ship the corresponding headers
electron' = electron-bin;
buildNpmArch = if stdenv.buildPlatform.isAarch64 then "arm64" else "x64";
hostNpmArch = if stdenv.hostPlatform.isAarch64 then "arm64" else "x64";
crossNpmArchExt = "-${hostNpmArch}";
in
buildNpmPackage rec {
pname = "signal-desktop-from-src";
inherit src version;
npmDepsHash = "sha256-CJTTLjP3eiJSa/ZWoeBP/9S1Krtb7ozsutRdH2HGfe8=";
patches = [
# ./debug.patch
# fix bug that signal launches in the background on wayland
# - <https://github.com/signalapp/Signal-Desktop/issues/6368>
# - without this, signal can be started with `signal-desktop & ; sleep 5; signal-desktop`
# - the second instance wakes the first one, and then exits
./show-on-launch.patch
# ./signal-desktop/no-mac-screen-share.patch
];
postPatch = ''
# unpin nodejs. i should probably *try* to keep these vaguely in sync, but it seems to work decently with these out of sync too (at least, if the major versions match?)
sed -i 's/"node": .*/"node": "*"/' package.json
# don't populate fallback DNS mappings, and don't try to install electron-builder deps during build:
substituteInPlace package.json \
--replace-fail \
'"build:dns-fallback": "node ts/scripts/generate-dns-fallback.js"' \
'"build:dns-fallback": "true"' \
--replace-fail \
'"electron:install-app-deps": "electron-builder install-app-deps"' \
'"electron:install-app-deps": "true"'
# fixes build failure:
# > Fusing electron at /build/source/release/linux-unpacked/signal-desktop inspect-arguments=false
# > ⨯ EACCES: permission denied, open '/build/source/release/linux-unpacked/signal-desktop' failedTask=build stackTrace=Error: EACCES: permission denied, open '/build/source/release/linux-unpacked/signal-desktop'
# electron "fusing" (electron.flipFuses) seems to be configuring which functionality electron will support at runtime.
# notably: ELECTRON_RUN_AS_NODE, cookie encryption, NODE_OPTIONS env var, --inspect-* CLI args, app.asar validation
# skipping the fuse process seems relatively inconsequential
substituteInPlace ts/scripts/after-pack.ts \
--replace-fail 'await fuseElectron' '//await fuseElectron'
'';
nativeBuildInputs = [
asar # used during fixup
autoPatchelfHook
git # to calculate build date
gnused
makeShellWrapper
python3
wrapGAppsHook
];
buildInputs = [
alsa-lib
at-spi2-atk
at-spi2-core
atk
cups
electron'
flac
gdk-pixbuf
gtk3
libpulseaudio
libwebp
libxslt
mesa # for libgbm
nspr
nss
pango
# so that bettersqlite may link against sqlcipher (see patch)
# but i don't know if it actually needs to. just copied this from alpine.
# sqlcipher
];
strictDeps = true;
# disallowedReferences = [ buildPackages.nodejs ]; #< TODO: set when cross compiling
# env.SIGNAL_ENV = "production";
# env.NODE_ENV = "production"; #< XXX setting this causes `node_modules/protobufjs-cli/bin/pbjs` to not be fetched...
# env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
# env.npm_config_arch = buildNpmArch;
# env.npm_config_target_arch = hostNpmArch;
dontWrapGApps = true;
# dontStrip = false;
# makeCacheWritable = true;
npmRebuildFlags = [
# "--offline"
"--ignore-scripts"
];
# NIX_DEBUG = 6;
postConfigure = ''
# XXX: Signal does not let clients connect if they're running a version that's > 90d old.
# to calculate the build date, it uses SOURCE_DATE_EPOCH (if set), else `git log`.
# nixpkgs sets SOURCE_DATE_EPOCH to 1980/01/01 by default, so unset it so Signal falls back to git date.
# see: Signal-Desktop/ts/scripts/get-expire-time.ts
export SOURCE_DATE_EPOCH=
# apparently electron projects aren't "stock" node.
# so subprojects which want to use node internals (i.e. call C functions provided by node)
# need to build against electron's versions of the node headers, or something.
# without patching this, Signal can build, but will fail with `undefined symbol: ...` errors at runtime.
# see: <https://www.electronjs.org/docs/latest/tutorial/using-native-node-modules>
tar xzf ${electron'.headers}
export npm_config_nodedir=$(pwd)/node_headers
# patchShebangs --build --update node_modules/{bufferutil/node_modules/node-gyp-build/,node-gyp-build,utf-8-validate/node_modules/node-gyp-build}
# patch these out to remove a runtime reference back to the build bash
# (better, perhaps, would be for these build scripts to not be included in the asar...)
sed -i 's:#!.*/bin/bash:#!/bin/sh:g' node_modules/@swc/helpers/scripts/gen.sh
sed -i 's:#!.*/bin/bash:#!/bin/sh:g' node_modules/@swc/helpers/scripts/generator.sh
substituteInPlace node_modules/dashdash/etc/dashdash.bash_completion.in --replace-fail '#!/bin/bash' '#!/bin/sh'
# provide necessities which were skipped as part of --ignore-scripts
tar -xzf ${ringrtcPrebuild} --directory node_modules/@signalapp/ringrtc/
cp ${sqlcipherTarball} node_modules/@signalapp/better-sqlite3/deps/sqlcipher.tar.gz
# pushd node_modules/@signalapp/better-sqlite3
# # node-gyp isn't consistently linked into better-sqlite's `node_modules` (maybe due to version mismatch with signal-desktop's node-gyp?)
# PATH="$PATH:$(pwd)/../../.bin" npm --offline run build-release
# popd
# pushd node_modules/@signalapp/libsignal-client
# npx node-gyp rebuild
# popd
# run signal's own `postinstall`:
# - npm run build:acknowledgments
# - npm exec patch-package
# - npm run electron:install-app-deps
npm run postinstall
'';
# excerpts from package.json:
# - "build": "run-s --print-label generate build:esbuild:prod build:release"
# - "generate": "npm-run-all build-protobuf build:esbuild build:dns-fallback build:icu-types build:compact-locales sass get-expire-time copy-components",
# - "build-protobuf": "npm run build-module-protobuf",
# - "build-module-protobuf": "pbjs --target static-module --force-long --no-typeurl --no-verify --no-create --no-convert --wrap commonjs --out ts/protobuf/compiled.js protos/*.proto && pbts --no-comments --out ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
# - "build:esbuild": "node scripts/esbuild.js",
# - "build:dns-fallback": "node ts/scripts/generate-dns-fallback.js",
# - "build:icu-types": "node ts/scripts/generate-icu-types.js",
# - "build:compact-locales": "node ts/scripts/generate-compact-locales.js",
# - "sass": "sass stylesheets/manifest.scss:stylesheets/manifest.css stylesheets/manifest_bridge.scss:stylesheets/manifest_bridge.css",
# - "get-expire-time": "node ts/scripts/get-expire-time.js",
# - "copy-components": "node ts/scripts/copy.js",
# - "build:esbuild:prod": "node scripts/esbuild.js --prod",
# - "build:release": "cross-env SIGNAL_ENV=production npm run build:electron -- --config.directories.output=release",
# - "build:electron": "electron-builder --config.extraMetadata.environment=$SIGNAL_ENV",
#
# i can't call toplevel `build` because some steps fail (e.g. dns-fallback) and can be skipped instead,
# while other steps fail (electron-builder) and need patching, but npm doesn't plumb the necessary flags through.
# so instead i call each step individually.
buildPhase = ''
runHook preBuild
npm run generate
npm run build:esbuild:prod --offline --frozen-lockfile
npm run build:release -- \
--${hostNpmArch} \
--config.electronDist=${electron'}/libexec/electron \
--config.electronVersion=${electron'.version} \
--dir
runHook postBuild
'';
installPhase = ''
runHook preInstall
# directory structure follows the original `signal-desktop` nix package
mkdir -p $out/lib
cp -R release/linux${crossNpmArchExt}-unpacked $out/lib/Signal
# cp -R release/linux-unpacked/resources $out/lib/Signal/resources
# cp -R release/linux-unpacked/locales $out/lib/Signal/locales
mkdir $out/bin
runHook postInstall
'';
preFixup = ''
# fixup the app.asar to use host nodejs
asar extract $out/lib/Signal/resources/app.asar unpacked
rm $out/lib/Signal/resources/app.asar
patchShebangs --host --update unpacked
asar pack unpacked $out/lib/Signal/resources/app.asar
# XXX: add --ozone-platform-hint=auto to make it so that NIXOS_OZONE_WL isn't *needed*.
# electron should auto-detect x11 v.s. wayland: launching with `NIXOS_OZONE_WL=1` is an optional way to force it when debugging.
# xdg-utils: needed for ozone-platform-hint=auto to work
# else `LaunchProcess: failed to execvp: xdg-settings`
makeShellWrapper ${electron'}/bin/electron $out/bin/signal-desktop \
"''${gappsWrapperArgs[@]}" \
--add-flags $out/lib/Signal/resources/app.asar \
--suffix PATH : ${lib.makeBinPath [ xdg-utils ]} \
--add-flags --ozone-platform-hint=auto \
--add-flags "\''${WAYLAND_DISPLAY:+--ozone-platform=wayland --enable-features=WaylandWindowDecorations}" \
--inherit-argv0
'';
passthru = {
# inherit bettersqlitePatch signal-fts5-extension;
updateScript = gitUpdater {
rev-prefix = "v";
ignoredVersions = "beta";
};
};
meta = {
description = "Private, simple, and secure messenger";
longDescription = ''
Signal Desktop is an Electron application that links with your
"Signal Android" or "Signal iOS" app.
'';
homepage = "https://signal.org/";
changelog = "https://github.com/signalapp/Signal-Desktop/releases/tag/v${version}";
license = lib.licenses.agpl3Only;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment