Rohan Verma



Commit Diff


commit - c86fbcd84d03494d9288500e642ba3a7c93dfac1
commit + 6a3713883a8f2ab04bb047dfa49439920061c50f
blob - e700701617b01129f0b60469b09a780fd1b971d3
blob + 24691e3c7e5981dd0e9b3a08b7d00937bdce5bfe
--- .gitignore
+++ .gitignore
@@ -4,3 +4,4 @@ milna.exe
 deps-win-x86_64/
 milna-macos-app.zip
 milna.app/
+milna.sec
blob - 3e119da204e6c6355e61fb2055c7f06ddcc5fb9e
blob + f5d5903678900c6e3877a59af8e9f3546bfe684d
--- build.sh
+++ build.sh
@@ -4,6 +4,55 @@ INC="-Ilib -Isrc"
 CORE="src/ui.c src/audio.c src/aproc.c src/net.c src/update.c lib/microui.c"
 CFLAGS="-Os -Wall -ffunction-sections -fdata-sections"
 
+SIGNDIR="${SIGNDIR:-$HOME/.signify}"
+SIGNKEYNAME="${SIGNKEYNAME:-rverma-2026}"
+SIGNKEY="${SIGNKEY:-$SIGNDIR/$SIGNKEYNAME.sec}"
+SIGNPUB="${SIGNPUB:-$SIGNDIR/$SIGNKEYNAME.pub}"
+SIGNIFY=signify
+command -v "$SIGNIFY" >/dev/null 2>&1 || SIGNIFY=signify-openbsd
+
+if [ "$1" = "release" ]; then
+	[ -f "$SIGNPUB" ] || { echo "no pubkey at $SIGNPUB"; exit 1; }
+	[ -f "$SIGNKEY" ] || { echo "no seckey at $SIGNKEY"; exit 1; }
+	echo ">> mac build + sign"
+	"$0"
+	echo ">> windows build + sign"
+	"$0" win
+	cat <<'NOTE'
+
+>> upload to VPS /var/www/mi/ (rename binaries; .sig names already match):
+     milna              -> milna-macos        (+ milna-macos.sig)
+     milna.exe          -> milna-windows.exe  (+ milna-windows.exe.sig)
+     milna-macos-app.zip                      (+ milna-macos-app.zip.sig)
+   then bump version LAST:
+     echo "X.Y" | ssh USER@mi.rsap.sh 'doas tee /var/www/mi/version'
+NOTE
+	exit 0
+fi
+
+PUBDEF=""
+if [ -f "$SIGNPUB" ]; then
+	bytes=$(sed -n 2p "$SIGNPUB" | base64 -d 2>/dev/null | \
+	        dd bs=1 skip=10 count=32 2>/dev/null | od -An -tu1 | \
+	        tr -s ' \n' ',' | sed 's/^,//;s/,$//')
+	if [ -n "$bytes" ]; then
+		PUBDEF="-DMILNA_PUBKEY=$bytes"
+		echo "pubkey: baked in from $SIGNPUB"
+	fi
+fi
+CFLAGS="$CFLAGS $PUBDEF"
+
+sign_artifact() {
+	[ -f "$SIGNKEY" ] || return 0
+	signame="${2:-$1}"
+	command -v "$SIGNIFY" >/dev/null 2>&1 || {
+		echo "  (signify not found — '$1' UNSIGNED; brew install signify-osx)"
+		return 0; }
+	"$SIGNIFY" -S -c '' -s "$SIGNKEY" -m "$1" -x "$signame.sig" 2>/dev/null && \
+		echo "  signed $1 -> $signame.sig" || \
+		echo "  (signing failed for $1)"
+}
+
 if [ "$1" = "win" ]; then
 	WARCH=${WINARCH:-x86_64}
 	case "$WARCH" in
@@ -11,7 +60,6 @@ if [ "$1" = "win" ]; then
 		arm64)  TRIPLE=aarch64-w64-mingw32 ;;
 		*) echo "WINARCH: x86_64 | arm64"; exit 1 ;;
 	esac
-
 	if [ -n "$WINCC" ]; then WCC=$WINCC
 	elif command -v $TRIPLE-clang >/dev/null 2>&1; then WCC=$TRIPLE-clang
 	elif command -v $TRIPLE-gcc-posix >/dev/null 2>&1; then WCC=$TRIPLE-gcc-posix
@@ -23,7 +71,7 @@ if [ "$1" = "win" ]; then
 		exit 1
 	fi
 	PFX=${WINPFX:-./deps-win-$WARCH}
-	[ -d "$PFX" ] || PFX=/tmp/w64     # sandbox fallback
+	[ -d "$PFX" ] || PFX=/tmp/w64
 	[ -d "$PFX" ] || { echo "deps missing: run ./win-deps.sh $WARCH"; exit 1; }
 
 	ICON_OBJ=""
@@ -69,13 +117,14 @@ if [ "$1" = "win" ]; then
 		-static -mwindows -Wl,--gc-sections
 	$TRIPLE-strip milna.exe 2>/dev/null || true
 	echo "built ./milna.exe ($(du -h milna.exe | cut -f1))"
+	sign_artifact milna.exe milna-windows.exe
 	exit 0
 fi
 
 CC=${CC:-cc}
 OUT=milna
 case "$(uname -s)" in
-Darwin)   
+Darwin)
 	OPUS=$(brew --prefix opus 2>/dev/null || echo /opt/homebrew/opt/opus)
 	SPX=$(brew --prefix speexdsp 2>/dev/null || echo /opt/homebrew/opt/speexdsp)
 	SODIUM=$(brew --prefix libsodium 2>/dev/null || echo /opt/homebrew/opt/libsodium)
@@ -91,6 +140,7 @@ Darwin)   
 		-Wl,-dead_strip
 	strip "$OUT" 2>/dev/null || true
 	echo "built ./$OUT ($(du -h $OUT | cut -f1))"
+	sign_artifact "$OUT" milna-macos
 
 	APP=milna.app
 	rm -rf "$APP"
@@ -146,13 +196,14 @@ PLIST
 	rm -f milna-macos-app.zip
 	if command -v zip >/dev/null 2>&1; then
 		zip -qry milna-macos-app.zip "$APP"
-		echo "zipped ./milna-macos-app.zip (upload to /var/www/milna/)"
+		echo "zipped ./milna-macos-app.zip (upload to /var/www/mi/)"
+		sign_artifact milna-macos-app.zip
 	else
 		echo "note: 'zip' not found — install it to produce the update zip"
 	fi
 	exit 0
 	;;
-Linux)    
+Linux)
 	$CC $CFLAGS $INC $(pkg-config --cflags opus speexdsp vpx libsodium) \
 		src/plat_x11.c src/vid.c src/cap_stub.c src/cam_stub.c $CORE -o $OUT \
 		$(pkg-config --libs opus speexdsp vpx libsodium) \
blob - e9cb2be653e83b08633356e88ac51293627f7736
blob + b46cf5fa3e8cb58fa688e9740ca1303b6e0ac826
--- src/update.c
+++ src/update.c
@@ -4,7 +4,81 @@
 #include <errno.h>
 #include <pthread.h>
 #include "update.h"
+#include <sodium.h>
 
+static int run_argv(char *const argv[]);
+
+#ifndef MILNA_PUBKEY
+#define MILNA_PUBKEY 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, \
+                     0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
+#endif
+static const unsigned char SIGN_PUBKEY[32] = { MILNA_PUBKEY };
+
+static int signing_enabled(void) {
+	for (int i = 0; i < 32; i++) if (SIGN_PUBKEY[i]) return 1;
+	return 0;
+}
+
+static int signify_sig_bytes(const char *path, unsigned char sig[64]) {
+	FILE *f = fopen(path, "rb");
+	if (!f) return -1;
+	char line[512]; int got = 0;
+	while (fgets(line, sizeof(line), f)) {
+		if (!strncmp(line, "untrusted comment:", 18)) continue;
+		char *nl = strpbrk(line, "\r\n"); if (nl) *nl = 0;
+		unsigned char raw[128]; size_t rawlen = 0;
+		if (sodium_base642bin(raw, sizeof(raw), line, strlen(line),
+		        NULL, &rawlen, NULL, sodium_base64_VARIANT_ORIGINAL) != 0)
+			break;
+		if (rawlen != 2 + 8 + 64) break;
+		memcpy(sig, raw + 10, 64);
+		got = 1; break;
+	}
+	fclose(f);
+	return got ? 0 : -1;
+}
+
+static int verify_file(const char *file, const char *sigpath) {
+	if (!signing_enabled()) return 0;
+	unsigned char sig[64];
+	if (signify_sig_bytes(sigpath, sig) != 0) {
+		fprintf(stderr, "[milna] update: signature file missing/invalid\n");
+		return -1;
+	}
+	FILE *f = fopen(file, "rb");
+	if (!f) return -1;
+	fseek(f, 0, SEEK_END); long sz = ftell(f); fseek(f, 0, SEEK_SET);
+	if (sz <= 0 || sz > 64 * 1024 * 1024) { fclose(f); return -1; }
+	unsigned char *buf = malloc((size_t)sz);
+	if (!buf) { fclose(f); return -1; }
+	size_t rd = fread(buf, 1, (size_t)sz, f);
+	fclose(f);
+	if (rd != (size_t)sz) { free(buf); return -1; }
+	int ok = crypto_sign_verify_detached(sig, buf, (size_t)sz,
+	                                      SIGN_PUBKEY) == 0;
+	free(buf);
+	if (!ok) fprintf(stderr, "[milna] update: SIGNATURE VERIFY FAILED — "
+	                 "refusing to install\n");
+	return ok ? 0 : -1;
+}
+
+static int fetch_and_verify(const char *url, const char *localfile) {
+	if (!signing_enabled()) return 0;
+	char sigurl[1300], sigfile[1200];
+	snprintf(sigurl, sizeof(sigurl), "%s.sig", url);
+	snprintf(sigfile, sizeof(sigfile), "%s.sig", localfile);
+	char *sv[] = { (char*)"curl", (char*)"-fsSL", (char*)"--max-time",
+	               (char*)"30", sigurl, (char*)"-o", sigfile, NULL };
+	if (run_argv(sv) != 0) {
+		fprintf(stderr, "[milna] update: could not fetch signature %s\n",
+		        sigurl);
+		return -1;
+	}
+	int r = verify_file(localfile, sigfile);
+	remove(sigfile);
+	return r;
+}
+
 static pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER;
 #ifndef __APPLE__
 static void *update_run_blocking_thunk(void *a);
@@ -31,8 +105,8 @@ static void *update_run_blocking_thunk(void *a);
 #define VER_URL  "https://mi.rsap.sh/version"
 #define BIN_BASE "https://mi.rsap.sh/milna-"
 
-static char g_self[1024];        /* path to the running executable */
-static char g_new[1024];         /* path to the downloaded update */
+static char g_self[1024];
+static char g_new[1024];
 
 static int bundle_path(char *out, size_t cap) {
 #ifdef __APPLE__
@@ -41,14 +115,14 @@ static int bundle_path(char *out, size_t cap) {
 	snprintf(tmp, sizeof(tmp), "%s", g_self);
 	char *p = strstr(tmp, marker);
 	if (!p) return 0;
-	p[4] = 0;                        /* cut right after ".app" */
+	p[4] = 0;
 	snprintf(out, cap, "%s", tmp);
 	return 1;
 #else
 	(void)out; (void)cap; return 0;
 #endif
 }
-static volatile int g_ready;     /* an update is downloaded & waiting */
+static volatile int g_ready;
 static char g_latest[32];
 static char g_localver[32];
 
@@ -74,6 +148,7 @@ static void self_path(char *out, size_t cap) {
 #elif defined(__APPLE__)
 	char raw[1024]; uint32_t sz = sizeof(raw);
 	if (_NSGetExecutablePath(raw, &sz) != 0) { out[0] = 0; return; }
+
 	if (!realpath(raw, out)) snprintf(out, cap, "%s", raw);
 #else
 	ssize_t n = readlink("/proc/self/exe", out, cap - 1);
@@ -84,6 +159,7 @@ static void self_path(char *out, size_t cap) {
 #ifdef _WIN32
 #include <process.h>
 static int run_argv(char *const argv[]) {
+
 	intptr_t r = _spawnvp(_P_WAIT, argv[0], (const char *const *)argv);
 	return r == 0 ? 0 : -1;
 }
@@ -118,12 +194,12 @@ static int valid_ver(const char *s) {
 	int digits = 0;
 	for (const char *p = s; *p; p++) {
 		if (*p >= '0' && *p <= '9') digits++;
-		else if (*p != '.') return 0;   /* only digits and dots allowed */
+		else if (*p != '.') return 0;
 	}
 	return digits > 0 && strlen(s) < 24;
 }
 static int newer(const char *remote, const char *local) {
-	if (!valid_ver(remote)) return 0;   /* junk remote: never "newer" */
+	if (!valid_ver(remote)) return 0;
 	int ra, rb = 0, la, lb = 0;
 	ra = atoi(remote);
 	const char *rd = strchr(remote, '.'); if (rd) rb = atoi(rd + 1);
@@ -153,6 +229,7 @@ void update_run_blocking(void) {
 	char bp[1024];
 	int in_bundle = bundle_path(bp, sizeof(bp));
 	if (in_bundle) {
+
 		snprintf(url, sizeof(url), "%smacos-app.zip", BIN_BASE);
 		char zip[1100]; snprintf(zip, sizeof(zip), "%s.zip", g_new);
 		char *dz[] = { (char*)"curl", (char*)"-fsSL", (char*)"--max-time",
@@ -163,9 +240,14 @@ void update_run_blocking(void) {
 			        "milna-macos-app.zip on the vps?\n");
 			remove(zip); return;
 		}
+
 		char *xz[] = { (char*)"xattr", (char*)"-d",
 		               (char*)"com.apple.quarantine", zip, NULL };
 		run_argv(xz);
+
+		if (fetch_and_verify(url, zip) != 0) {
+			remove(zip); return;
+		}
 		pthread_mutex_lock(&g_mu);
 		snprintf(g_latest, sizeof(g_latest), "%s", remote);
 		g_ready = 1;
@@ -183,8 +265,13 @@ void update_run_blocking(void) {
 		        "uploaded to the vps?\n", url);
 		remove(g_new); return;
 	}
+
+	if (fetch_and_verify(url, g_new) != 0) {
+		remove(g_new); return;
+	}
 #ifndef _WIN32
 	chmod(g_new, 0755);
+
 	char *xargv[] = { (char*)"xattr", (char*)"-d",
 	                  (char*)"com.apple.quarantine", g_new, NULL };
 	run_argv(xargv);
@@ -204,6 +291,7 @@ void update_init(const char *local_version) {
 	fprintf(stderr, "[milna] update_init: self=%s\n", g_self);
 
 #ifdef __APPLE__
+
 	{
 		char bp[1024];
 		char zip[1100]; snprintf(zip, sizeof(zip), "%s.zip", g_new);
@@ -212,11 +300,13 @@ void update_init(const char *local_version) {
 			fclose(z);
 			fprintf(stderr, "[milna] update: staged bundle zip found, "
 			        "launching swap helper for %s\n", bp);
+
 			char hp[] = "/tmp/milna_update.XXXXXX";
 			int hfd = mkstemp(hp);
 			FILE *h = (hfd >= 0) ? fdopen(hfd, "w") : NULL;
 			if (h) {
 				fchmod(hfd, 0700);
+
 				fprintf(h,
 				    "#!/bin/sh\n"
 				    "pid=\"$1\"; app=\"$2\"; zip=\"$3\"\n"
@@ -233,7 +323,7 @@ void update_init(const char *local_version) {
 				    "rm -rf \"$app.old\" \"$tmp\" \"$zip\"\n"
 				    "/usr/bin/open \"$app\"\n");
 				fclose(h);
-				/* spawn detached and exit so the helper can replace us */
+
 				char pidbuf[16];
 				snprintf(pidbuf, sizeof(pidbuf), "%d", (int)getpid());
 				char *hv[] = { (char*)"/bin/sh", hp, pidbuf, bp, zip, NULL };
@@ -245,7 +335,7 @@ void update_init(const char *local_version) {
 				}
 				fprintf(stderr, "[milna] update: helper spawned, quitting "
 				        "for bundle swap\n");
-				_exit(0);   /* let the helper take over */
+				_exit(0);
 			}
 		} else if (z) fclose(z);
 	}
@@ -259,11 +349,11 @@ void update_init(const char *local_version) {
 #ifdef _WIN32
 		char old[1100]; snprintf(old, sizeof(old), "%s.old", g_self);
 		remove(old);
-		MoveFileA(g_self, old);              /* unlock the name */
-		if (MoveFileA(g_new, g_self) == 0)   /* promote */
-			MoveFileA(old, g_self);          /* failed: roll back */
+		MoveFileA(g_self, old);
+		if (MoveFileA(g_new, g_self) == 0)
+			MoveFileA(old, g_self);
 		else
-			/* relaunch into the new binary, old one exits */
+
 			;
 #else
 		if (rename(g_new, g_self) != 0) {
@@ -271,14 +361,17 @@ void update_init(const char *local_version) {
 			        "in a writable location (not /Applications)?\n",
 			        strerror(errno), g_self);
 		} else {
+
 			fprintf(stderr, "[milna] update: promoted, relaunching\n");
 #ifdef __APPLE__
+
 			{
 				char bundle[1024];
 				snprintf(bundle, sizeof(bundle), "%s", g_self);
 				char *p = strstr(bundle, ".app/Contents/MacOS/");
 				if (p) {
-					p[4] = 0;   /* terminate right after ".app" */
+					p[4] = 0;
+
 					char *cs[] = { (char*)"codesign", (char*)"--force",
 					               (char*)"--sign", (char*)"-", bundle, NULL };
 					int rc = run_argv(cs);
@@ -299,6 +392,7 @@ void update_init(const char *local_version) {
 }
 
 #ifdef __APPLE__
+
 void update_dispatch_bg(void);
 #endif
 
@@ -318,7 +412,7 @@ void update_check_async(void) {
 }
 
 #ifndef __APPLE__
-/* pthread needs a void*(void*) signature */
+
 static void *update_run_blocking_thunk(void *a) {
 	(void)a; update_run_blocking(); return NULL;
 }