diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md index 141815e0e2..44b9b1611b 100644 --- a/ACKNOWLEDGMENTS.md +++ b/ACKNOWLEDGMENTS.md @@ -19587,7 +19587,7 @@ For more information on this, and how to apply and follow the GNU AGPL, see ``` -## libsignal-account-keys 0.1.0, libsignal-core 0.1.0, libsignal-debug 0.89.2, mrp 2.69.3, protobuf 2.69.3, ringrtc 2.69.3, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 +## libsignal-account-keys 0.1.0, libsignal-core 0.1.0, libsignal-debug 0.89.2, mrp 2.69.4, protobuf 2.69.4, ringrtc 2.69.4, regex-aot 0.1.0, partial-default-derive 0.1.0, partial-default 0.1.0 ``` GNU AFFERO GENERAL PUBLIC LICENSE @@ -20682,7 +20682,7 @@ THIS SOFTWARE. ``` -## cubeb-core 0.34.0, cubeb-sys 0.34.0, cubeb 0.34.0 +## cubeb-core 0.35.3, cubeb-sys 0.35.3, cubeb 0.35.3 ``` Copyright © 2017 Mozilla Foundation diff --git a/app/AssetService.main.ts b/app/AssetService.main.ts index 33b20b8d5f..222af8e262 100644 --- a/app/AssetService.main.ts +++ b/app/AssetService.main.ts @@ -27,13 +27,15 @@ const LOCAL_ASSETS = new Set([ 'fonts/inter-v3.19/Inter-Italic.woff2', 'fonts/inter-v3.19/Inter-SemiBoldItalic.woff2', 'fonts/mono-special/MonoSpecial-Regular.woff2', - 'fonts/emoji.woff2', ]); // pathname to optional resource name -const OPTIONAL_ASSETS = new Map([ - ['optional-fonts/emoji-large.woff2', 'emoji-font.woff2'], -]); +const OPTIONAL_ASSETS = new Map([]); + +if (!process.mas) { + LOCAL_ASSETS.add('fonts/emoji.woff2'); + OPTIONAL_ASSETS.set('optional-fonts/emoji-large.woff2', 'emoji-font.woff2'); +} export class AssetService { readonly #resourceService: OptionalResourceService; diff --git a/build/entitlements.mas.inherit.plist b/build/entitlements.mas.inherit.plist index 714fc60854..272a571ddb 100644 --- a/build/entitlements.mas.inherit.plist +++ b/build/entitlements.mas.inherit.plist @@ -8,5 +8,9 @@ com.apple.security.cs.allow-jit + com.apple.security.app-sandbox + + com.apple.security.inherit + diff --git a/build/entitlements.mas.plist b/build/entitlements.mas.plist index 4603c560a9..d7f1469405 100644 --- a/build/entitlements.mas.plist +++ b/build/entitlements.mas.plist @@ -15,13 +15,28 @@ com.apple.security.device.camera + com.apple.security.device.usb + com.apple.security.files.downloads.read-write com.apple.security.files.user-selected.read-write - com.apple.security.personal-information.photos-library + com.apple.security.files.bookmarks.app-scope + + com.apple.security.print com.apple.security.network.client + com.apple.security.network.server + + com.apple.security.application-groups + + U68MSDN6DR.org.whispersystems.signal-desktop + U68MSDN6DR.signal-desktop + + com.apple.application-identifier + U68MSDN6DR.org.whispersystems.signal-desktop + com.apple.developer.team-identifier + U68MSDN6DR diff --git a/package.json b/package.json index 3750a986ae..1792c71db7 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "prepare-staging-build": "node scripts/prepare_staging_build.mjs", "prepare-no-delay-release": "node scripts/prepare-no-delay-release.mjs", "prepare-linux-build": "node scripts/prepare_linux_build.mjs", + "prepare-mas-build": "node scripts/prepare_mas_build.mjs", "test": "run-s test-node test-electron test-lint-intl test-oxlint", "test-electron": "node scripts/test-electron.mjs", "test-release": "node scripts/test-release.mjs", @@ -104,6 +105,7 @@ "build:styles:tailwind:prod": "pnpm run build:styles:tailwind --minify", "build:electron": "cross-env NODE_OPTIONS='--import=tsx' electron-builder --config.extraMetadata.environment=$SIGNAL_ENV", "build:release": "cross-env SIGNAL_ENV=production pnpm run build:electron --config.directories.output=release", + "build:release:mas": "pnpm run build:release --mac mas --universal", "build:mas-dev": "bash ./scripts/build-mas-dev.sh", "build:release-win32-all": "pnpm run build:release --arm64 --x64", "build:preload-cache": "node scripts/generate-preload-cache.mjs", @@ -120,7 +122,7 @@ "@indutny/simple-windows-notifications": "2.0.16", "@signalapp/libsignal-client": "0.95.0", "@signalapp/mute-state-change": "workspace:*", - "@signalapp/ringrtc": "2.69.3", + "@signalapp/ringrtc": "2.69.4", "@signalapp/sqlcipher": "3.3.5", "@signalapp/windows-ucv": "workspace:*", "google-libphonenumber": "3.2.44" @@ -359,6 +361,7 @@ ], "mergeASARs": true, "sign": "scripts/sign-macos.mjs", + "signInstaller": "scripts/sign-mas-installer.mjs", "releaseInfo": { "vendor": { "minOSVersion": "21.0.1" @@ -416,6 +419,15 @@ "entitlementsInherit": "./build/entitlements.mas-dev.inherit.plist", "preAutoEntitlements": false, "extendInfo": { + "ITSAppUsesNonExemptEncryption": false, + "ElectronTeamID": "U68MSDN6DR", + "NSCameraUsageDescription": "Signal uses your camera for video calling.", + "NSMicrophoneUsageDescription": "Signal uses your microphone for voice and video calling." + } + }, + "mas": { + "extendInfo": { + "ITSAppUsesNonExemptEncryption": false, "ElectronTeamID": "U68MSDN6DR", "NSCameraUsageDescription": "Signal uses your camera for video calling.", "NSMicrophoneUsageDescription": "Signal uses your microphone for voice and video calling." diff --git a/patches/app-builder-lib.patch b/patches/app-builder-lib.patch index 65867182de..c5bf77956e 100644 --- a/patches/app-builder-lib.patch +++ b/patches/app-builder-lib.patch @@ -31,6 +31,53 @@ index ffb85dea810257c8ddbed2f857c25787c9e5b694..fdcc65fb94bcf95adbb4cf97b7d4c85a // Otherwise order by name return a < b ? -1 : 1; }); +diff --git a/out/macPackager.js b/out/macPackager.js +index d67dc0583d1bc98d2c60f5f4ff5c22a1fcd6ff44..1364f12a2791a4319ad741bef79fc4fb81f92516 100644 +--- a/out/macPackager.js ++++ b/out/macPackager.js +@@ -330,22 +330,30 @@ class MacPackager extends platformPackager_1.PlatformPackager { + await this.doSign(signOptions, customSignOptions, identity); + // https://github.com/electron-userland/electron-builder/issues/1196#issuecomment-312310209 + if (masOptions != null && !isDevelopment) { ++ const customSignInstaller = await (0, resolve_1.resolveFunction)(this.appInfo.type, customSignOptions.signInstaller, "signInstaller"); ++ const artifactName = this.expandArtifactNamePattern(masOptions, "pkg", arch); ++ const artifactPath = path.join(outDir, artifactName); ++ ++ let masInstallerIdentity; ++ if (customSignInstaller == null) { + const certType = isDevelopment ? "Mac Developer" : "3rd Party Mac Developer Installer"; +- const masInstallerIdentity = await (0, macCodeSign_1.findIdentity)(certType, masOptions.identity, keychainFile); ++ masInstallerIdentity = await (0, macCodeSign_1.findIdentity)(certType, masOptions.identity, keychainFile); + if (masInstallerIdentity == null) { + throw new builder_util_1.InvalidConfigurationError(`Cannot find valid "${certType}" identity to sign MAS installer, please see https://electron.build/code-signing`); + } +- // mas uploaded to AppStore, so, use "-" instead of space for name +- const artifactName = this.expandArtifactNamePattern(masOptions, "pkg", arch); +- const artifactPath = path.join(outDir, artifactName); +- await this.doFlat(appPath, artifactPath, masInstallerIdentity, keychainFile); +- await this.info.emitArtifactBuildCompleted({ +- file: artifactPath, +- target: null, +- arch: builder_util_1.Arch.x64, +- safeArtifactName: this.computeSafeArtifactName(artifactName, "pkg", arch, true, this.platformSpecificBuildOptions.defaultArch), +- packager: this, +- }); ++ } ++ // mas uploaded to AppStore, so, use "-" instead of space for name ++ await this.doFlat(appPath, artifactPath, masInstallerIdentity, keychainFile); ++ if (customSignInstaller != null) { ++ await customSignInstaller(artifactPath, this); ++ } ++ await this.info.emitArtifactBuildCompleted({ ++ file: artifactPath, ++ target: null, ++ arch: builder_util_1.Arch.x64, ++ safeArtifactName: this.computeSafeArtifactName(artifactName, "pkg", arch, true, this.platformSpecificBuildOptions.defaultArch), ++ packager: this, ++ }); + } + if (!isMas) { + await this.notarizeIfProvided(appPath); diff --git a/out/targets/FpmTarget.js b/out/targets/FpmTarget.js index f10f8148a237fae6c7af44818a127dfc881d884f..3bc2a9d1895d4f00133c82240ec2eba8c87d605a 100644 --- a/out/targets/FpmTarget.js @@ -43,6 +90,68 @@ index f10f8148a237fae6c7af44818a127dfc881d884f..3bc2a9d1895d4f00133c82240ec2eba8 sanitizedProductName: packager.appInfo.sanitizedProductName, productFilename: packager.appInfo.productFilename, ...packager.platformSpecificBuildOptions, +diff --git a/out/targets/nsis/NsisTarget.js b/out/targets/nsis/NsisTarget.js +index 32afb5e2f16e18a4c054d48b47b649e60fab1131..bd7c75f95d1ee15a59d705632136f66f681745e9 100644 +--- a/out/targets/nsis/NsisTarget.js ++++ b/out/targets/nsis/NsisTarget.js +@@ -175,11 +175,6 @@ class NsisTarget extends core_1.Target { + if (uninstallAppKey !== guid) { + defines.UNINSTALL_REGISTRY_KEY_2 = `Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${guid}`; + } +- const { homepage } = this.packager.info.metadata; +- (0, builder_util_1.use)(options.uninstallUrlHelp || homepage, it => (defines.UNINSTALL_URL_HELP = it)); +- (0, builder_util_1.use)(options.uninstallUrlInfoAbout || homepage, it => (defines.UNINSTALL_URL_INFO_ABOUT = it)); +- (0, builder_util_1.use)(options.uninstallUrlUpdateInfo || homepage, it => (defines.UNINSTALL_URL_UPDATE_INFO = it)); +- (0, builder_util_1.use)(options.uninstallUrlReadme || homepage, it => (defines.UNINSTALL_URL_README = it)); + const commands = { + OutFile: `"${installerPath}"`, + VIProductVersion: appInfo.getVersionInWeirdWindowsForm(), +diff --git a/scheme.json b/scheme.json +index f4ea4fbbc5f19a5b6cad17f0c8d3cc8e7776fead..4ea9b0808db815b2c3c006a7a3fbe64876b92a35 100644 +--- a/scheme.json ++++ b/scheme.json +@@ -3073,6 +3073,20 @@ + ], + "description": "The custom function (or path to file or module id) to sign an app bundle." + }, ++ "signInstaller": { ++ "anyOf": [ ++ { ++ "typeof": "function" ++ }, ++ { ++ "type": [ ++ "null", ++ "string" ++ ] ++ } ++ ], ++ "description": "The custom function (or path to file or module id) to sign an app package." ++ }, + "signIgnore": { + "anyOf": [ + { +@@ -3711,6 +3725,20 @@ + ], + "description": "The custom function (or path to file or module id) to sign an app bundle." + }, ++ "signInstaller": { ++ "anyOf": [ ++ { ++ "typeof": "function" ++ }, ++ { ++ "type": [ ++ "null", ++ "string" ++ ] ++ } ++ ], ++ "description": "The custom function (or path to file or module id) to sign an app package." ++ }, + "signIgnore": { + "anyOf": [ + { diff --git a/templates/linux/after-install.tpl b/templates/linux/after-install.tpl index 2bb3d32d9df96a4bf0245670613f20459b32fb46..6dda2f3798ec0b13366f1b8d4adb9cd61696fd28 100644 --- a/templates/linux/after-install.tpl @@ -87,7 +196,7 @@ index 19b3decabe18a816f9ed5440fa9124ebfd6e3907..fa1ecd2d991977c53a5082b2efb3120c + +POLKIT_TARGET_PATH='/usr/share/polkit-1/actions' +if [ -d "$POLKIT_TARGET_PATH" ]; then -+ rm -f $POLKIT_TARGET_PATH/org.signalapp.${sanitizedName}.*.policy ++ rm -f $POLKIT_TARGET_PATH/org.signalapp.${sanitizedName}.*.policy +fi + +# SIGNAL CHANGES END diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1a1a1c5c32..4a7e1dd882 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,7 +21,7 @@ patchedDependencies: '@types/chai': b1cea4e432957039e7f72a32140d7a718258944078c5d5bdb40ad62b8717cb97 '@types/fabric@4.5.3': e5f339ecf72fbab1c91505e7713e127a7184bfe8164aa3a9afe9bf45a0ad6b89 '@vitest/expect@2.0.5': e8a96f71e52bf903c9f1eadba4740489a0beb48da33db52354adca484fe1f495 - app-builder-lib: 4b0b6a075db66810319028f6784bd5bb11cd9bb38570800f1fff0d80f90c44d8 + app-builder-lib: 02fa41bb6c77d0ecc2b4c7a03b1d16089baaeadf948fcab1d63b2bb12404c1d6 casual@1.6.2: b88b5052437cbdc1882137778b76ca5037f71b2a030ae9ef39dc97f51670d599 dmg-builder: 75ddbdfdce4e9fad4f5e7d3e2ac0d29fc920006584534018bf560c486e0642ec fabric@4.6.0: 259e6eff3d60c4a453f7815fca6aa0d3a81842f4efdc4051836812fc1e711e00 @@ -50,8 +50,8 @@ importers: specifier: workspace:* version: link:packages/mute-state-change '@signalapp/ringrtc': - specifier: 2.69.3 - version: 2.69.3 + specifier: 2.69.4 + version: 2.69.4 '@signalapp/sqlcipher': specifier: 3.3.5 version: 3.3.5 @@ -4270,8 +4270,8 @@ packages: resolution: {integrity: sha512-y2sgqdivlrG41J4Zvt/82xtH/PZjDlgItqlD2g/Cv3ZbjlR6cGhTNXbfNygCJB8nXj+C7I28pjt1Zm3k0pv2mg==, tarball: https://registry.npmjs.org/@signalapp/quill-cjs/-/quill-cjs-2.1.2.tgz} engines: {npm: '>=8.2.3'} - '@signalapp/ringrtc@2.69.3': - resolution: {integrity: sha512-QZE9SUj0pCPAJWEjQO3W3/2BnZcX8Md7y4K4pnTQssHis72qhppZeXxZrvbnwkeQmvRvGHsRGwsspj812JXzMw==, tarball: https://registry.npmjs.org/@signalapp/ringrtc/-/ringrtc-2.69.3.tgz} + '@signalapp/ringrtc@2.69.4': + resolution: {integrity: sha512-OLavGfCzfYuqUVoAtTeHi7QrXpVNmT8LxzOI9XOPId29bn5gJNrAG31IPVw7Fw7vvWpZwZHFi5MTmcmZGibs4A==, tarball: https://registry.npmjs.org/@signalapp/ringrtc/-/ringrtc-2.69.4.tgz} hasBin: true '@signalapp/sqlcipher@3.3.5': @@ -14737,7 +14737,7 @@ snapshots: lodash: 4.18.1 quill-delta: 5.1.0 - '@signalapp/ringrtc@2.69.3': + '@signalapp/ringrtc@2.69.4': dependencies: https-proxy-agent: 7.0.6 tar: 7.5.15 @@ -15969,7 +15969,7 @@ snapshots: app-builder-bin@5.0.0-alpha.12: {} - app-builder-lib@26.11.1(patch_hash=4b0b6a075db66810319028f6784bd5bb11cd9bb38570800f1fff0d80f90c44d8)(dmg-builder@26.11.1)(electron-builder-squirrel-windows@26.11.1): + app-builder-lib@26.11.1(patch_hash=02fa41bb6c77d0ecc2b4c7a03b1d16089baaeadf948fcab1d63b2bb12404c1d6)(dmg-builder@26.11.1)(electron-builder-squirrel-windows@26.11.1): dependencies: '@develar/schema-utils': 2.6.5 '@electron/asar': 3.4.1 @@ -17042,7 +17042,7 @@ snapshots: dmg-builder@26.11.1(patch_hash=75ddbdfdce4e9fad4f5e7d3e2ac0d29fc920006584534018bf560c486e0642ec)(electron-builder-squirrel-windows@26.11.1): dependencies: - app-builder-lib: 26.11.1(patch_hash=4b0b6a075db66810319028f6784bd5bb11cd9bb38570800f1fff0d80f90c44d8)(dmg-builder@26.11.1)(electron-builder-squirrel-windows@26.11.1) + app-builder-lib: 26.11.1(patch_hash=02fa41bb6c77d0ecc2b4c7a03b1d16089baaeadf948fcab1d63b2bb12404c1d6)(dmg-builder@26.11.1)(electron-builder-squirrel-windows@26.11.1) builder-util: 26.11.1 fs-extra: 10.1.0 iconv-lite: 0.6.3 @@ -17184,7 +17184,7 @@ snapshots: electron-builder-squirrel-windows@26.11.1(dmg-builder@26.11.1): dependencies: - app-builder-lib: 26.11.1(patch_hash=4b0b6a075db66810319028f6784bd5bb11cd9bb38570800f1fff0d80f90c44d8)(dmg-builder@26.11.1)(electron-builder-squirrel-windows@26.11.1) + app-builder-lib: 26.11.1(patch_hash=02fa41bb6c77d0ecc2b4c7a03b1d16089baaeadf948fcab1d63b2bb12404c1d6)(dmg-builder@26.11.1)(electron-builder-squirrel-windows@26.11.1) builder-util: 26.11.1 electron-winstaller: 5.4.0 transitivePeerDependencies: @@ -17193,7 +17193,7 @@ snapshots: electron-builder@26.11.1(electron-builder-squirrel-windows@26.11.1): dependencies: - app-builder-lib: 26.11.1(patch_hash=4b0b6a075db66810319028f6784bd5bb11cd9bb38570800f1fff0d80f90c44d8)(dmg-builder@26.11.1)(electron-builder-squirrel-windows@26.11.1) + app-builder-lib: 26.11.1(patch_hash=02fa41bb6c77d0ecc2b4c7a03b1d16089baaeadf948fcab1d63b2bb12404c1d6)(dmg-builder@26.11.1)(electron-builder-squirrel-windows@26.11.1) builder-util: 26.11.1 builder-util-runtime: 9.6.1 chalk: 4.1.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ca9c85ed45..95893dd727 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -80,7 +80,7 @@ allowBuilds: '@parcel/watcher@2.5.6': true '@signalapp/libsignal-client@0.92.2': true # duplicate package '@signalapp/libsignal-client@0.95.0': true - '@signalapp/ringrtc@2.69.3': true + '@signalapp/ringrtc@2.69.4': true '@signalapp/sqlcipher@3.3.5': true '@signalapp/windows-ucv@1.0.1': true '@swc/core@1.10.16': true diff --git a/scripts/get-expire-time.mjs b/scripts/get-expire-time.mjs index 8c520ba5b4..ead86ba455 100644 --- a/scripts/get-expire-time.mjs +++ b/scripts/get-expire-time.mjs @@ -2,18 +2,13 @@ // SPDX-License-Identifier: AGPL-3.0-only // @ts-check import { join } from 'node:path'; -import { execSync } from 'node:child_process'; import { writeFileSync } from 'node:fs'; import { DAY } from './utils/durations.mjs'; import { parseVersion } from './utils/parseVersion.mjs'; +import { getBuildCreationTimestamp } from './utils/getBuildCreationTimestamp.mjs'; import packageJson from '../package.json' with { type: 'json' }; -const unixTimestamp = parseInt( - process.env.SOURCE_DATE_EPOCH || - execSync('git show -s --format=%ct').toString('utf8'), - 10 -); -const buildCreation = unixTimestamp * 1000; +const buildCreation = getBuildCreationTimestamp(); const isNotUpdatable = !parseVersion(packageJson.version).isUpdatable; diff --git a/scripts/prepare_mas_build.mjs b/scripts/prepare_mas_build.mjs new file mode 100644 index 0000000000..87673d3032 --- /dev/null +++ b/scripts/prepare_mas_build.mjs @@ -0,0 +1,74 @@ +// Copyright 2026 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only +// @ts-check +import fs from 'node:fs'; +import _ from 'lodash'; +import moment from 'moment'; + +import { parseVersion } from './utils/parseVersion.mjs'; +import { getBuildCreationTimestamp } from './utils/getBuildCreationTimestamp.mjs'; +import packageJson from '../package.json' with { type: 'json' }; + +const version = parseVersion(packageJson.version); +if (version.channel !== 'alpha') { + console.error('Only alpha versions can be published as MAS builds'); + process.exit(1); +} + +console.log('prepare_mas_build: updating package.json'); + +// ------- + +const NAME_PATH = 'name'; +const VERSION_PATH = 'version'; +const PRODUCTION_NAME = 'signal-desktop'; + +const PRODUCT_NAME_PATH = 'productName'; +const PRODUCTION_PRODUCT_NAME = 'Signal'; + +const APP_ID_PATH = 'build.appId'; +const PRODUCTION_APP_ID = 'org.whispersystems.signal-desktop'; + +const BUNDLE_VERSION_PATH = 'build.mac.bundleVersion'; +const NON_MAS_BUNDLE_VERSION = '1'; +const MAS_BUNDLE_VERSION = moment(getBuildCreationTimestamp()).format('YYYY.MM.DDHHMM'); + +const FILE_EXCLUSION_LIST = ['!fonts/emoji.woff2']; + +// ------- + +/** + * @param {object} object + * @param {string} objectPath + * @param {string} expected + */ +function checkValue(object, objectPath, expected) { + const actual = _.get(object, objectPath); + if (actual !== expected) { + throw new Error(`${objectPath} was ${actual}; expected ${expected}`); + } +} + +// ------ + +checkValue(packageJson, NAME_PATH, PRODUCTION_NAME); +checkValue(packageJson, PRODUCT_NAME_PATH, PRODUCTION_PRODUCT_NAME); +checkValue(packageJson, APP_ID_PATH, PRODUCTION_APP_ID); +checkValue(packageJson, BUNDLE_VERSION_PATH, NON_MAS_BUNDLE_VERSION); +for (const file of FILE_EXCLUSION_LIST) { + if (packageJson.build.files.includes(file)) { + throw new Error(`Expected ${file} to be absent from 'files'`); + } +} + +// ------- + +_.set(packageJson, VERSION_PATH, `${version.major}.${version.minor}.${version.patch}`); +_.set(packageJson, BUNDLE_VERSION_PATH, MAS_BUNDLE_VERSION); +for (const file of FILE_EXCLUSION_LIST) { + packageJson.build.files.push(file); +} + +// ------- + +fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, ' ')); diff --git a/scripts/sign-macos.mjs b/scripts/sign-macos.mjs index 4a3af61ae7..4af3bc0124 100644 --- a/scripts/sign-macos.mjs +++ b/scripts/sign-macos.mjs @@ -34,6 +34,10 @@ export async function sign(configuration) { // The script will update the file in-place const returnCode = execSync(`bash "${scriptPath}" "${target}"`, { stdio: [null, process.stdout, process.stderr], + env: { + ...process.env, + ELECTRON_BUILDER_PLATFORM: configuration.platform, + }, }); if (returnCode) { diff --git a/scripts/sign-mas-installer.mjs b/scripts/sign-mas-installer.mjs new file mode 100644 index 0000000000..1d3b6a1479 --- /dev/null +++ b/scripts/sign-mas-installer.mjs @@ -0,0 +1,35 @@ +// Copyright 2026 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only +// @ts-check +import { execSync } from 'node:child_process'; +import { realpath } from 'node:fs/promises'; + +/** + * @param {string} installerPath + * @returns {Promise} + */ +export async function signInstaller(installerPath) { + if (process.env.SKIP_SIGNING_SCRIPT === '1') { + console.log('SKIP_SIGNING_SCRIPT=1, skipping custom mas installer signing script'); + return; + } + + const scriptPath = process.env.SIGN_MAS_INSTALLER_SCRIPT; + if (!scriptPath) { + throw new Error( + 'path to macos sign script must be provided in environment variable SIGN_MAS_INSTALLER_SCRIPT' + ); + } + + const target = await realpath(installerPath); + + // The script will update the file in-place + const returnCode = execSync(`bash "${scriptPath}" "${target}"`, { + stdio: [null, process.stdout, process.stderr], + }); + + if (returnCode) { + // oxlint-disable-next-line typescript/restrict-template-expressions + throw new Error(`sign-macos: Script returned code ${returnCode}`); + } +} diff --git a/scripts/utils/getBuildCreationTimestamp.mjs b/scripts/utils/getBuildCreationTimestamp.mjs new file mode 100644 index 0000000000..dce01a0297 --- /dev/null +++ b/scripts/utils/getBuildCreationTimestamp.mjs @@ -0,0 +1,17 @@ +// Copyright 2026 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only +// @ts-check +import { execSync } from 'node:child_process'; +import { SECOND } from './durations.mjs'; + +/** + * @returns {number} + */ +export function getBuildCreationTimestamp() { + const unixTimestamp = parseInt( + process.env.SOURCE_DATE_EPOCH || + execSync('git show -s --format=%ct').toString('utf8'), + 10 + ); + return unixTimestamp * SECOND; +}