Skip to content

Commit

Permalink
Merge branch 'master' into smartUnpack
Browse files Browse the repository at this point in the history
  • Loading branch information
beyondkmp authored Nov 1, 2024
2 parents ead15e1 + e796d24 commit d37e117
Show file tree
Hide file tree
Showing 38 changed files with 277 additions and 85 deletions.
5 changes: 5 additions & 0 deletions .changeset/dull-eyes-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-builder-lib": patch
---

fix(win): add required `publisherName` field to Azure Trusted Signing
5 changes: 5 additions & 0 deletions .changeset/fresh-camels-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-builder-lib": patch
---

fix: cscIKeyPassword must support empty string arguments
4 changes: 4 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
"@electron-builder/test": "0.0.0"
},
"changesets": [
"dull-eyes-check",
"early-penguins-share",
"fluffy-wolves-smile",
"fresh-camels-smash",
"gold-parents-complain",
"khaki-schools-provide",
"lucky-tigers-do",
Expand All @@ -30,6 +32,8 @@
"sixty-dogs-deliver",
"slimy-chairs-buy",
"slow-zoos-mate",
"small-peas-drop",
"smooth-camels-decide",
"sour-points-refuse",
"stupid-buses-compete",
"sweet-masks-sparkle",
Expand Down
5 changes: 5 additions & 0 deletions .changeset/small-peas-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-builder-lib": patch
---

chore: refactor electron dist logic to avoid unnecessary console logs
5 changes: 5 additions & 0 deletions .changeset/smooth-camels-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-builder-lib": patch
---

fix: check ResolvedFileSet src when verifying symlinks to be within project directory
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# [](https://github.com/electron-userland/electron-builder/compare/v26.0.0-alpha.4...v) (2024-11-01)


### Bug Fixes

* `cscIKeyPassword` must support empty string arguments ([#8653](https://github.com/electron-userland/electron-builder/issues/8653)) ([796e1a0](https://github.com/electron-userland/electron-builder/commit/796e1a072a2bbe97ced6f4be05325c704fc04b7f))
* **asar:** check ResolvedFileSet src when verifying symlinks to be within project directory ([#8654](https://github.com/electron-userland/electron-builder/issues/8654)) ([9e11358](https://github.com/electron-userland/electron-builder/commit/9e11358fc28249675cd7ec4f7037408cc18dfa8a))
* **win:** add required `publisherName` field to Azure Trusted Signing options ([#8650](https://github.com/electron-userland/electron-builder/issues/8650)) ([f84a083](https://github.com/electron-userland/electron-builder/commit/f84a0831d1d02b782ad07d4f7feff79d96dd45ec))



# [](https://github.com/electron-userland/electron-builder/compare/v26.0.0-alpha.3...v) (2024-10-28)


Expand Down
16 changes: 16 additions & 0 deletions packages/app-builder-lib/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# app-builder-lib

## 26.0.0-alpha.5

### Patch Changes

- [#8650](https://github.com/electron-userland/electron-builder/pull/8650) [`f84a0831`](https://github.com/electron-userland/electron-builder/commit/f84a0831d1d02b782ad07d4f7feff79d96dd45ec) Thanks [@mmaietta](https://github.com/mmaietta)! - fix(win): add required `publisherName` field to Azure Trusted Signing

- [#8653](https://github.com/electron-userland/electron-builder/pull/8653) [`796e1a07`](https://github.com/electron-userland/electron-builder/commit/796e1a072a2bbe97ced6f4be05325c704fc04b7f) Thanks [@IsaacAderogba](https://github.com/IsaacAderogba)! - fix: cscIKeyPassword must support empty string arguments

- [#8639](https://github.com/electron-userland/electron-builder/pull/8639) [`28006623`](https://github.com/electron-userland/electron-builder/commit/28006623a1a344007e283cdc65ce1a81f42a136d) Thanks [@mmaietta](https://github.com/mmaietta)! - chore: refactor electron dist logic to avoid unnecessary console logs

- [#8654](https://github.com/electron-userland/electron-builder/pull/8654) [`9e11358f`](https://github.com/electron-userland/electron-builder/commit/9e11358fc28249675cd7ec4f7037408cc18dfa8a) Thanks [@mmaietta](https://github.com/mmaietta)! - fix: check ResolvedFileSet src when verifying symlinks to be within project directory

- Updated dependencies []:
- [email protected]
- [email protected]

## 26.0.0-alpha.4

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "app-builder-lib",
"description": "electron-builder lib",
"version": "26.0.0-alpha.4",
"version": "26.0.0-alpha.5",
"main": "out/index.js",
"files": [
"out",
Expand Down
9 changes: 7 additions & 2 deletions packages/app-builder-lib/scheme.json
Original file line number Diff line number Diff line change
Expand Up @@ -6116,6 +6116,10 @@
"description": "The File Digest for signing each file. Translates to field: FileDigest",
"type": "string"
},
"publisherName": {
"description": "[The publisher name](https://github.com/electron-userland/electron-builder/issues/1187#issuecomment-278972073), exactly as in your code signed certificate. Several names can be provided.",
"type": "string"
},
"timestampDigest": {
"default": "SHA256",
"description": "The Timestamp Digest. Translates to field: TimestampDigest",
Expand All @@ -6130,7 +6134,8 @@
"required": [
"certificateProfileName",
"codeSigningAccountName",
"endpoint"
"endpoint",
"publisherName"
],
"type": "object"
},
Expand Down Expand Up @@ -7082,7 +7087,7 @@
]
}
],
"description": "The function (or path to file or module id) to be run when staging the electron artifact environment.\nReturns the path to custom Electron build (e.g. `~/electron/out/R`) or folder of electron zips. Zip files must follow the pattern `electron-v${version}-${platformName}-${arch}.zip`, otherwise it will be assumed to be an unpacked Electron app directory"
"description": "The function (or path to file or module id) to be run when staging the electron artifact environment.\nReturns the path to custom Electron build (e.g. `~/electron/out/R`) or folder of electron zips.\n\nZip files must follow the pattern `electron-v${version}-${platformName}-${arch}.zip`, otherwise it will be assumed to be an unpacked Electron app directory"
},
"electronDownload": {
"$ref": "#/definitions/ElectronDownloadOptions",
Expand Down
16 changes: 11 additions & 5 deletions packages/app-builder-lib/src/asar/asarUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export class AsarPackager {

constructor(
private readonly config: {
appDir: string
defaultDestination: string
resourcePath: string
options: AsarOptions
Expand Down Expand Up @@ -86,7 +85,14 @@ export class AsarPackager {
return
}
}
const writeFileOrSymlink = async (transformedData: string | Buffer | undefined, source: string, destination: string, stat: fs.Stats) => {
const writeFileOrSymlink = async (options: { transformedData: string | Buffer | undefined; file: string; destination: string; stat: fs.Stats; fileSet: ResolvedFileSet }) => {
const {
transformedData,
file: source,
destination,
stat,
fileSet: { src: sourceDir },
} = options
copiedFiles.add(destination)

// If transformed data, skip symlink logic
Expand All @@ -100,8 +106,7 @@ export class AsarPackager {
return this.copyFileOrData(undefined, source, destination, stat)
}

const realPathRelative = path.relative(this.config.appDir, realPathFile)
const symlinkTarget = path.resolve(this.rootForAppFilesWithoutAsar, realPathRelative)
const realPathRelative = path.relative(sourceDir, realPathFile)
const isOutsidePackage = realPathRelative.startsWith("..")
if (isOutsidePackage) {
log.error({ source: log.filePath(source), realPathFile: log.filePath(realPathFile) }, `unable to copy, file is symlinked outside the package`)
Expand All @@ -110,6 +115,7 @@ export class AsarPackager {
)
}

const symlinkTarget = path.resolve(this.rootForAppFilesWithoutAsar, realPathRelative)
await this.copyFileOrData(undefined, source, symlinkTarget, stat)
const target = path.relative(path.dirname(destination), symlinkTarget)
fsNode.symlinkSync(target, destination)
Expand All @@ -130,7 +136,7 @@ export class AsarPackager {
const dest = path.resolve(this.rootForAppFilesWithoutAsar, relative)

matchUnpacker(file, dest, metadata)
taskManager.addTask(writeFileOrSymlink(transformedData, file, dest, metadata))
taskManager.addTask(writeFileOrSymlink({ transformedData, file, destination: dest, stat: metadata, fileSet }))

if (taskManager.tasks.length > MAX_FILE_REQUESTS) {
await taskManager.awaitTasks()
Expand Down
2 changes: 1 addition & 1 deletion packages/app-builder-lib/src/codeSign/macCodeSign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export async function createKeychain({ tmpDir, cscLink, cscKeyPassword, cscILink
BluebirdPromise.mapSeries(securityCommands, it => exec("/usr/bin/security", it)),
])
const cscPasswords: Array<string> = [cscKeyPassword]
if (cscIKeyPassword) {
if (cscIKeyPassword != null) {
cscPasswords.push(cscIKeyPassword)
}
return await importCerts(keychainFile, certPaths, cscPasswords)
Expand Down
14 changes: 14 additions & 0 deletions packages/app-builder-lib/src/codeSign/signManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Lazy } from "lazy-val"
import { WindowsSignOptions } from "./windowsCodeSign"
import { Target } from "../core"
import { MemoLazy } from "builder-util-runtime"
import { FileCodeSigningInfo, CertificateFromStoreInfo } from "./windowsSignToolManager"
import { WindowsConfiguration } from "../options/winOptions"

export interface SignManager {
readonly computedPublisherName: Lazy<Array<string> | null>
readonly cscInfo: MemoLazy<WindowsConfiguration, FileCodeSigningInfo | CertificateFromStoreInfo | null>
computePublisherName(target: Target, publisherName: string | null | undefined): Promise<string>
initialize(): Promise<void>
signFile(options: WindowsSignOptions): Promise<boolean>
}
50 changes: 26 additions & 24 deletions packages/app-builder-lib/src/codeSign/windowsCodeSign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,36 @@ export interface WindowsSignOptions {
}

export async function signWindows(options: WindowsSignOptions, packager: WinPackager): Promise<boolean> {
const packageManager = await packager.signingManager.value
if (options.options.azureSignOptions) {
if (options.options.signtoolOptions) {
log.warn(null, "ignoring signtool options, using Azure Trusted Signing; please only configure one")
}
log.info({ path: log.filePath(options.path) }, "signing with Azure Trusted Signing (beta)")
const packageManager = await packager.azureSignManager.value
return signWithRetry(async () => packageManager.signUsingAzureTrustedSigning(options))
} else {
log.info({ path: log.filePath(options.path) }, "signing with signtool.exe")
const deprecatedFields = {
sign: options.options.sign,
signDlls: options.options.signDlls,
signingHashAlgorithms: options.options.signingHashAlgorithms,
certificateFile: options.options.certificateFile,
certificatePassword: options.options.certificatePassword,
certificateSha1: options.options.certificateSha1,
certificateSubjectName: options.options.certificateSubjectName,
additionalCertificateFile: options.options.additionalCertificateFile,
rfc3161TimeStampServer: options.options.rfc3161TimeStampServer,
timeStampServer: options.options.timeStampServer,
publisherName: options.options.publisherName,
}
const fields = Object.entries(deprecatedFields)
.filter(([, value]) => !!value)
.map(([field]) => field)
if (fields.length) {
log.warn({ fields, reason: "please move to win.signtoolOptions.<field_name>" }, `deprecated field`)
}
}

log.info({ path: log.filePath(options.path) }, "signing with signtool.exe")
const deprecatedFields = {
sign: options.options.sign,
signDlls: options.options.signDlls,
signingHashAlgorithms: options.options.signingHashAlgorithms,
certificateFile: options.options.certificateFile,
certificatePassword: options.options.certificatePassword,
certificateSha1: options.options.certificateSha1,
certificateSubjectName: options.options.certificateSubjectName,
additionalCertificateFile: options.options.additionalCertificateFile,
rfc3161TimeStampServer: options.options.rfc3161TimeStampServer,
timeStampServer: options.options.timeStampServer,
publisherName: options.options.publisherName,
}
const fields = Object.entries(deprecatedFields)
.filter(([, value]) => !!value)
.map(([field]) => field)
if (fields.length) {
log.warn({ fields, reason: "please move to win.signtoolOptions.<field_name>" }, `deprecated field`)
}
const packageManager = await packager.signtoolManager.value
return signWithRetry(async () => packageManager.signUsingSigntool(options))
return signWithRetry(async () => packageManager.signFile(options))
}

function signWithRetry(signer: () => Promise<boolean>): Promise<boolean> {
Expand Down
52 changes: 44 additions & 8 deletions packages/app-builder-lib/src/codeSign/windowsSignAzureManager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
import { InvalidConfigurationError, log } from "builder-util"
import { WindowsAzureSigningConfiguration } from "../options/winOptions"
import { asArray, InvalidConfigurationError, log } from "builder-util"
import { WindowsAzureSigningConfiguration, WindowsConfiguration } from "../options/winOptions"
import { WinPackager } from "../winPackager"
import { getPSCmd, WindowsSignOptions } from "./windowsCodeSign"
import { Lazy } from "lazy-val"
import { SignManager } from "./signManager"
import { MemoLazy } from "builder-util-runtime"
import { CertificateFromStoreInfo, FileCodeSigningInfo } from "./windowsSignToolManager"

export class WindowsSignAzureManager {
constructor(private readonly packager: WinPackager) {}
export class WindowsSignAzureManager implements SignManager {
private readonly platformSpecificBuildOptions: WindowsConfiguration

async initializeProviderModules() {
readonly computedPublisherName = new Lazy<Array<string> | null>(() => {
const publisherName = this.platformSpecificBuildOptions.azureSignOptions?.publisherName
if (publisherName === null) {
return Promise.resolve(null)
} else if (publisherName != null) {
return Promise.resolve(asArray(publisherName))
}

// TODO: Is there another way to automatically pull Publisher Name from AzureTrusted service?
// For now return null.
return Promise.resolve(null)
})

constructor(private readonly packager: WinPackager) {
this.platformSpecificBuildOptions = packager.platformSpecificBuildOptions
}

async initialize() {
const vm = await this.packager.vm.value
const ps = await getPSCmd(vm)

Expand Down Expand Up @@ -74,13 +95,28 @@ export class WindowsSignAzureManager {
return true
}

computePublisherName(): Promise<string> {
return Promise.resolve(this.packager.platformSpecificBuildOptions.azureSignOptions!.publisherName)
}
readonly cscInfo = new MemoLazy<WindowsConfiguration, FileCodeSigningInfo | CertificateFromStoreInfo | null>(
() => this.packager.platformSpecificBuildOptions,
_selected => Promise.resolve(null)
)
// prerequisite: requires `initializeProviderModules` to already have been executed
async signUsingAzureTrustedSigning(options: WindowsSignOptions): Promise<boolean> {
async signFile(options: WindowsSignOptions): Promise<boolean> {
const vm = await this.packager.vm.value
const ps = await getPSCmd(vm)

const { endpoint, certificateProfileName, codeSigningAccountName, fileDigest, timestampRfc3161, timestampDigest, ...extraSigningArgs }: WindowsAzureSigningConfiguration =
options.options.azureSignOptions!
const {
publisherName: _publisher, // extract from `extraSigningArgs`
endpoint,
certificateProfileName,
codeSigningAccountName,
fileDigest,
timestampRfc3161,
timestampDigest,
...extraSigningArgs
}: WindowsAzureSigningConfiguration = options.options.azureSignOptions!
const params = {
...extraSigningArgs,
Endpoint: endpoint,
Expand Down
26 changes: 24 additions & 2 deletions packages/app-builder-lib/src/codeSign/windowsSignToolManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import { getPSCmd } from "./windowsCodeSign"
import { MemoLazy, parseDn } from "builder-util-runtime"
import { Lazy } from "lazy-val"
import { importCertificate } from "./codesign"
import { SignManager } from "./signManager"
import { Target } from "../core"
import AppXTarget from "../targets/AppxTarget"

export function getSignVendorPath() {
return getBin("winCodeSign")
Expand Down Expand Up @@ -65,7 +68,7 @@ interface CertInfo {
PSParentPath: string
}

export class WindowsSignToolManager {
export class WindowsSignToolManager implements SignManager {
private readonly platformSpecificBuildOptions: WindowsConfiguration

constructor(private readonly packager: WinPackager) {
Expand Down Expand Up @@ -161,7 +164,26 @@ export class WindowsSignToolManager {
}
)

async signUsingSigntool(options: WindowsSignOptions): Promise<boolean> {
initialize(): Promise<void> {
return Promise.resolve()
}

// https://github.com/electron-userland/electron-builder/issues/2108#issuecomment-333200711
async computePublisherName(target: Target, publisherName: string) {
if (target instanceof AppXTarget && (await this.cscInfo.value) == null) {
log.info({ reason: "Windows Store only build" }, "AppX is not signed")
return publisherName || "CN=ms"
}

const certInfo = await this.lazyCertInfo.value
const publisher = publisherName || (certInfo == null ? null : certInfo.bloodyMicrosoftSubjectDn)
if (publisher == null) {
throw new Error("Internal error: cannot compute subject using certificate info")
}
return publisher
}

async signFile(options: WindowsSignOptions): Promise<boolean> {
let hashes = chooseNotNull(options.options.signtoolOptions?.signingHashAlgorithms, options.options.signingHashAlgorithms)
// msi does not support dual-signing
if (options.path.endsWith(".msi")) {
Expand Down
4 changes: 3 additions & 1 deletion packages/app-builder-lib/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,9 @@ Configuration in the same way as `afterPack` (see above).
readonly beforeBuild?: Hook<BeforeBuildContext, boolean | void> | string | null
/**
* The function (or path to file or module id) to be run when staging the electron artifact environment.
* Returns the path to custom Electron build (e.g. `~/electron/out/R`) or folder of electron zips. Zip files must follow the pattern `electron-v${version}-${platformName}-${arch}.zip`, otherwise it will be assumed to be an unpacked Electron app directory
* Returns the path to custom Electron build (e.g. `~/electron/out/R`) or folder of electron zips.
*
* Zip files must follow the pattern `electron-v${version}-${platformName}-${arch}.zip`, otherwise it will be assumed to be an unpacked Electron app directory
*/
readonly electronDist?: Hook<PrepareApplicationStageDirectoryOptions, string> | string | null
}
Expand Down
Loading

0 comments on commit d37e117

Please sign in to comment.