Skip to content
Merged
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
17 changes: 17 additions & 0 deletions building/macos/build-pkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,15 @@ def ensure_freerdp_libs() -> None:
fail(f"Required FreeRDP library not found: {lib_path}")


def find_bundled_openh264(app_dir: Path) -> list[Path]:
"""
Our licence from Cisco covers downloading libopenh264, never redistributing it, so no
copy of it may ship inside the bundle. The postinstall script fetches it at install
time instead. This obligation runs until 2031.
"""
return [path for path in app_dir.rglob("*") if "openh264" in path.name.lower()]


def validate_bundle_dependencies(app_dir: Path) -> bool:
"""
Validate that all binaries and dylibs inside the app bundle only depend on:
Expand Down Expand Up @@ -563,6 +572,14 @@ def main() -> None:
if not validate_bundle_dependencies(APP_DIR):
fail("App bundle contains invalid dependencies")

print("==> Checking that no openh264 library ships inside the bundle")
bundled_openh264 = find_bundled_openh264(APP_DIR)
if bundled_openh264:
for path in bundled_openh264:
print(f" !! {path.relative_to(APP_DIR)}")
fail("Bundle ships libopenh264; we may only download it, never redistribute it")
print(">> No openh264 inside the bundle")

print("==> App bundle structure created successfully")
print(f"Output path: {APP_DIR}")

Expand Down
104 changes: 63 additions & 41 deletions building/macos/scripts/postinstall
Original file line number Diff line number Diff line change
@@ -1,63 +1,85 @@
#!/bin/bash
set -e

# --- Configuration -----------------------------------------------------------

OPENH264_VERSION="2.6.0"
OPENH264_BASE_URL="https://ciscobinary.openh264.org"

# Our licence covers downloading this library from Cisco, never redistributing it, so it
# must come from their site and carry their signature. The launcher runs with library
# validation disabled, so dyld no longer enforces that team id: this check is what is
# left guarding the file.
CISCO_TEAM_ID="DE8Y96K9QP"

TARGET_DIR="/Library/Application Support/UDSLauncher/openh264"
LOG_FILE="/tmp/udslauncher-postinstall.log"
# FreeRDP's load command asks for the soname, so the file has to land under that name.
TARGET_FILE="libopenh264.8.dylib"

touch /tmp/udslauncher-postinstall-ran 2>/dev/null
LOG_DIR="/var/log"
LOG_FILE="$LOG_DIR/udslauncher-install.log"

# --- Helpers -----------------------------------------------------------------

log() {
echo "$@"
echo "$@" >> "$LOG_FILE"
echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_FILE"
}

# Failing to install the codec must not fail the installation: the launcher works
# without it, and the alternative is leaving the user with no client at all.
give_up() {
log "WARNING: $1"
log "OpenH264 was not installed. Webcam H264 will fall back to MJPEG."
log "=== UDSLauncher postinstall finished WITH WARNINGS at $(date) ==="
exit 0
}

download_url() {
case "$(uname -m)" in
arm64) echo "$OPENH264_BASE_URL/libopenh264-$OPENH264_VERSION-mac-arm64.dylib.bz2" ;;
*) echo "$OPENH264_BASE_URL/libopenh264-$OPENH264_VERSION-mac-x64.dylib.bz2" ;;
esac
}

# --- Install -----------------------------------------------------------------

log "=== UDSLauncher postinstall started at $(date) ==="
log "Running as: $(whoami)"
log "Running as $(whoami) on $(uname -m)"

log "Creating target directory: $TARGET_DIR"
if ! mkdir -p "$TARGET_DIR"; then
log "FATAL: Could not create $TARGET_DIR"
exit 1
fi
mkdir -p "$TARGET_DIR" || give_up "could not create $TARGET_DIR"

ARCH=$(uname -m)
VERSION="2.6.0"
work_dir=$(mktemp -d) || give_up "could not create a temporary directory"
trap 'rm -rf "$work_dir"' EXIT

if [ "$ARCH" = "arm64" ]; then
URL="http://ciscobinary.openh264.org/libopenh264-${VERSION}-mac-arm64.dylib.bz2"
else
URL="http://ciscobinary.openh264.org/libopenh264-${VERSION}-mac-x64.dylib.bz2"
fi
archive="$work_dir/openh264.dylib.bz2"
url=$(download_url)

TEMP_FILE="/tmp/openh264.dylib.bz2"
DECOMPRESSED="/tmp/openh264.dylib"
TARGET_FILE="libopenh264.8.dylib"
log "Downloading OpenH264 from $url"
curl -L -s -f -o "$archive" "$url" || give_up "download failed"
log "Downloaded $(stat -f%z "$archive") bytes"

bunzip2 -f "$archive" || give_up "bunzip2 failed"
dylib="$work_dir/openh264.dylib"
[ -f "$dylib" ] || give_up "bunzip2 produced no $dylib"

log "Architecture: $ARCH"
log "Downloading OpenH264 from $URL..."
if curl -L -s -f -o "$TEMP_FILE" "$URL"; then
log "Downloaded OK ($(stat -f%z "$TEMP_FILE") bytes)"
log "Decompressing OpenH264..."
if bunzip2 -f "$TEMP_FILE"; then
if mv "$DECOMPRESSED" "$TARGET_DIR/$TARGET_FILE"; then
chmod 644 "$TARGET_DIR/$TARGET_FILE"
xattr -d com.apple.quarantine "$TARGET_DIR/$TARGET_FILE" 2>/dev/null || true
log "OpenH264 installed successfully to $TARGET_DIR"
rm -f "$TEMP_FILE" "$DECOMPRESSED"
log "=== UDSLauncher postinstall finished OK at $(date) ==="
exit 0
else
log "ERROR: Failed to move dylib to $TARGET_DIR"
fi
else
log "ERROR: bunzip2 failed"
# Reject anything not signed by Cisco before it reaches a system-wide directory.
# codesign ships with macOS, but never assume a tool is there on someone else's machine:
# without it we still install, because the target directory is root-owned and the old
# script verified nothing at all.
if command -v codesign > /dev/null 2>&1; then
team_id=$(codesign -dvvv "$dylib" 2>&1 | sed -n 's/^TeamIdentifier=//p')
if [ "$team_id" != "$CISCO_TEAM_ID" ]; then
give_up "downloaded library is signed by '${team_id:-nothing}', expected $CISCO_TEAM_ID"
fi
log "Signature verified: TeamIdentifier=$team_id"
else
log "ERROR: curl download failed"
log "WARNING: codesign not available, installing without verifying the signature"
fi

rm -f "$TEMP_FILE" "$DECOMPRESSED"
install -m 644 "$dylib" "$TARGET_DIR/$TARGET_FILE" || give_up "could not install into $TARGET_DIR"
xattr -d com.apple.quarantine "$TARGET_DIR/$TARGET_FILE" 2>/dev/null || true

log "Warning: Failed to download or extract OpenH264. Fallback to MJPEG will be used."
log "=== UDSLauncher postinstall finished WITH WARNINGS at $(date) ==="
log "OpenH264 installed at $TARGET_DIR/$TARGET_FILE"
log "=== UDSLauncher postinstall finished OK at $(date) ==="
exit 0
35 changes: 20 additions & 15 deletions building/macos/scripts/postremove
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
#!/bin/bash
set -e

TARGET_DIR="/Library/Application Support/UDSLauncher/openh264"
LOG_FILE="/tmp/udslauncher-postremove.log"
# --- Configuration -----------------------------------------------------------

SUPPORT_DIR="/Library/Application Support/UDSLauncher"
TARGET_DIR="$SUPPORT_DIR/openh264"
TARGET_FILE="libopenh264.8.dylib"

LOG_DIR="/var/log"
LOG_FILE="$LOG_DIR/udslauncher-install.log"

# --- Helpers -----------------------------------------------------------------

log() {
echo "$@"
echo "$@" >> "$LOG_FILE"
echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_FILE"
}

# --- Remove ------------------------------------------------------------------

log "=== UDSLauncher postremove started at $(date) ==="

if [ -f "$TARGET_DIR/libopenh264.8.dylib" ]; then
rm -f "$TARGET_DIR/libopenh264.8.dylib"
log "Removed OpenH264 dylib from $TARGET_DIR"
if [ -f "$TARGET_DIR/$TARGET_FILE" ]; then
rm -f "$TARGET_DIR/$TARGET_FILE"
log "Removed $TARGET_DIR/$TARGET_FILE"
else
log "No OpenH264 dylib found at $TARGET_DIR"
log "Nothing to remove at $TARGET_DIR/$TARGET_FILE"
fi

if [ -d "$TARGET_DIR" ]; then
rmdir "$TARGET_DIR" 2>/dev/null || true
fi

PARENT_DIR="/Library/Application Support/UDSLauncher"
if [ -d "$PARENT_DIR" ]; then
rmdir "$PARENT_DIR" 2>/dev/null || true
fi
# Only prune the directories we created, and only while they are empty.
rmdir "$TARGET_DIR" 2>/dev/null || true
rmdir "$SUPPORT_DIR" 2>/dev/null || true

log "=== UDSLauncher postremove finished at $(date) ==="
exit 0
Loading