You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2026-02-01 07:49:31 +02:00
Compare commits
11 Commits
renovate/n
...
notarize_p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec69097cec | ||
|
|
6b1f2c946e | ||
|
|
c6c1a9a888 | ||
|
|
e95e84edeb | ||
|
|
4e5895e53f | ||
|
|
0bf92c2cdd | ||
|
|
2a9dfe7cf9 | ||
|
|
66388acfbe | ||
|
|
dd12f4df64 | ||
|
|
7209948ded | ||
|
|
cdf104f650 |
@@ -611,6 +611,7 @@ packages/app-desktop/tools/copy7Zip.js
|
||||
packages/app-desktop/tools/generateLatestArm64Yml.js
|
||||
packages/app-desktop/tools/githubReleasesUtils.js
|
||||
packages/app-desktop/tools/modifyReleaseAssets.js
|
||||
packages/app-desktop/tools/notarizeFile.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/tools/resolveSourceMap.js
|
||||
packages/app-desktop/utils/7zip/getPathToExecutable7Zip.js
|
||||
|
||||
35
.github/workflows/build-macos-m1.yml
vendored
35
.github/workflows/build-macos-m1.yml
vendored
@@ -46,6 +46,8 @@ jobs:
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
|
||||
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
|
||||
CSC_INSTALLER_KEY_PASSWORD: ${{ secrets.CSC_INSTALLER_KEY_PASSWORD }}
|
||||
CSC_INSTALLER_LINK: ${{ secrets.CSC_INSTALLER_LINK }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
||||
@@ -72,6 +74,39 @@ jobs:
|
||||
npm pkg set 'build.mac.target[2].arch[0]'='arm64'
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
curl -L -o installer.p12 "$CSC_INSTALLER_LINK"
|
||||
|
||||
# Create an explicit keychain file path (avoid temp dirs / weird defaults)
|
||||
KEYCHAIN="$RUNNER_TEMP/build.keychain-db"
|
||||
KEYCHAIN_PW=""
|
||||
|
||||
security create-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN"
|
||||
security set-keychain-settings -lut 21600 "$KEYCHAIN"
|
||||
security unlock-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN"
|
||||
|
||||
# Make sure this keychain is the one security uses
|
||||
security list-keychains -d user -s "$KEYCHAIN"
|
||||
security default-keychain -d user -s "$KEYCHAIN"
|
||||
|
||||
# Import with -A to avoid access-control prompts in CI
|
||||
security import installer.p12 \
|
||||
-k "$KEYCHAIN" \
|
||||
-P "$CSC_INSTALLER_KEY_PASSWORD" \
|
||||
-A
|
||||
|
||||
# Sanity: confirm identity is now present
|
||||
security find-identity -p codesigning -v "$KEYCHAIN"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
build_dist() {
|
||||
if [[ "$PUBLISH_ENABLED" == "true" ]]; then
|
||||
echo "Building and publishing desktop application..."
|
||||
|
||||
2
.github/workflows/github-actions-main.yml
vendored
2
.github/workflows/github-actions-main.yml
vendored
@@ -75,6 +75,8 @@ jobs:
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
|
||||
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
|
||||
CSC_INSTALLER_KEY_PASSWORD: ${{ secrets.CSC_INSTALLER_KEY_PASSWORD }}
|
||||
CSC_INSTALLER_LINK: ${{ secrets.CSC_INSTALLER_LINK }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
IS_CONTINUOUS_INTEGRATION: 1
|
||||
BUILD_SEQUENCIAL: 1
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -585,6 +585,7 @@ packages/app-desktop/tools/copy7Zip.js
|
||||
packages/app-desktop/tools/generateLatestArm64Yml.js
|
||||
packages/app-desktop/tools/githubReleasesUtils.js
|
||||
packages/app-desktop/tools/modifyReleaseAssets.js
|
||||
packages/app-desktop/tools/notarizeFile.js
|
||||
packages/app-desktop/tools/notarizeMacApp.js
|
||||
packages/app-desktop/tools/resolveSourceMap.js
|
||||
packages/app-desktop/utils/7zip/getPathToExecutable7Zip.js
|
||||
|
||||
@@ -2,6 +2,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const sha512 = require('js-sha512');
|
||||
const notarizeFile = require('./tools/notarizeFile').default;
|
||||
const distDirName = 'dist';
|
||||
const distPath = path.join(__dirname, distDirName);
|
||||
|
||||
@@ -31,7 +32,24 @@ const generateChecksumFile = () => {
|
||||
return sha512FilePath;
|
||||
};
|
||||
|
||||
const mainHook = () => {
|
||||
const notarizePkg = async () => {
|
||||
if (os.platform() !== 'darwin') {
|
||||
return;
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(distPath);
|
||||
for (const filename of files) {
|
||||
if (filename.endsWith('.pkg')) {
|
||||
const pkgPath = path.join(distPath, filename);
|
||||
await notarizeFile(pkgPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const mainHook = async () => {
|
||||
await notarizePkg();
|
||||
|
||||
const sha512FilePath = generateChecksumFile();
|
||||
const outputFiles = [sha512FilePath].filter(item => item);
|
||||
return outputFiles;
|
||||
|
||||
109
packages/app-desktop/tools/notarizeFile.ts
Normal file
109
packages/app-desktop/tools/notarizeFile.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { existsSync } from 'fs';
|
||||
import { notarize } from '@electron/notarize';
|
||||
const execCommand = require('./execCommand');
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
// Same appId in electron-builder.
|
||||
const appId = 'net.cozic.joplin-desktop';
|
||||
|
||||
function isDesktopAppTag(tagName: string) {
|
||||
if (!tagName) return false;
|
||||
return tagName[0] === 'v';
|
||||
}
|
||||
|
||||
export default async function notarizeFile(filePath: string) {
|
||||
if (process.platform !== 'darwin') return;
|
||||
|
||||
console.info(`Checking if notarization should be done on: ${filePath}`);
|
||||
|
||||
if (!process.env.IS_CONTINUOUS_INTEGRATION || !isDesktopAppTag(process.env.GIT_TAG_NAME)) {
|
||||
console.info(`Either not running in CI or not processing a desktop app tag - skipping notarization. process.env.IS_CONTINUOUS_INTEGRATION = ${process.env.IS_CONTINUOUS_INTEGRATION}; process.env.GIT_TAG_NAME = ${process.env.GIT_TAG_NAME}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!process.env.APPLE_ID || !process.env.APPLE_ID_PASSWORD) {
|
||||
console.warn('Environment variables APPLE_ID and APPLE_ID_PASSWORD not found - notarization will NOT be done.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!existsSync(filePath)) {
|
||||
throw new Error(`Cannot find file at: ${filePath}`);
|
||||
}
|
||||
|
||||
// Every x seconds we print something to stdout, otherwise CI may timeout
|
||||
// the task after 10 minutes, and Apple notarization can take more time.
|
||||
const waitingIntervalId = setInterval(() => {
|
||||
console.info('.');
|
||||
}, 60000);
|
||||
|
||||
const isPkg = filePath.endsWith('.pkg');
|
||||
|
||||
console.info(`Notarizing ${filePath}`);
|
||||
|
||||
try {
|
||||
if (isPkg) {
|
||||
await execAsync(
|
||||
`xcrun notarytool submit "${filePath}" ` +
|
||||
`--apple-id "${process.env.APPLE_ID}" ` +
|
||||
`--password "${process.env.APPLE_ID_PASSWORD}" ` +
|
||||
`--team-id "${process.env.APPLE_ASC_PROVIDER}" ` +
|
||||
'--wait',
|
||||
{ maxBuffer: 1024 * 1024 },
|
||||
);
|
||||
} else {
|
||||
await notarize({
|
||||
appBundleId: appId,
|
||||
appPath: filePath,
|
||||
|
||||
// Apple Developer email address
|
||||
appleId: process.env.APPLE_ID,
|
||||
|
||||
// App-specific password: https://support.apple.com/en-us/HT204397
|
||||
appleIdPassword: process.env.APPLE_ID_PASSWORD,
|
||||
|
||||
// When Apple ID is attached to multiple providers (eg if the
|
||||
// account has been used to build multiple apps for different
|
||||
// companies), in that case the provider "Team Short Name" (also
|
||||
// known as "ProviderShortname") must be provided.
|
||||
//
|
||||
// Use this to get it:
|
||||
//
|
||||
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
|
||||
// ascProvider: process.env.APPLE_ASC_PROVIDER,
|
||||
|
||||
// In our case, the team ID is the same as the legacy ASC_PROVIDER
|
||||
teamId: process.env.APPLE_ASC_PROVIDER,
|
||||
|
||||
tool: 'notarytool',
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
} as any);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
clearInterval(waitingIntervalId);
|
||||
|
||||
// It appears that electron-notarize doesn't staple the app, but without
|
||||
// this we were still getting the malware warning when launching the app.
|
||||
// Stapling the app means attaching the notarization ticket to it, so that
|
||||
// if the user is offline, macOS can still check if the app was notarized.
|
||||
// So it seems to be more or less optional, but at least in our case it
|
||||
// wasn't.
|
||||
console.info('Stapling notarization ticket to the file...');
|
||||
const staplerCmd = `xcrun stapler staple "${filePath}"`;
|
||||
console.info(`> ${staplerCmd}`);
|
||||
console.info(await execCommand(staplerCmd));
|
||||
|
||||
console.info(`Validating stapled file: ${filePath}`);
|
||||
try {
|
||||
await execAsync(`spctl -a -vv -t install "${filePath}"`);
|
||||
} catch (error) {
|
||||
console.error(`Failed validating stapled file: ${filePath}:`, error);
|
||||
}
|
||||
|
||||
console.info(`Done notarizing ${filePath}`);
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
import { existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { notarize } from '@electron/notarize';
|
||||
const execCommand = require('./execCommand');
|
||||
|
||||
function isDesktopAppTag(tagName: string) {
|
||||
if (!tagName) return false;
|
||||
return tagName[0] === 'v';
|
||||
}
|
||||
import notarizeFile from './notarizeFile';
|
||||
|
||||
interface Params {
|
||||
appOutDir: string;
|
||||
@@ -18,80 +11,6 @@ interface Params {
|
||||
}
|
||||
|
||||
export default async (params: Params) => {
|
||||
if (process.platform !== 'darwin') return;
|
||||
|
||||
console.info('Checking if notarization should be done...');
|
||||
|
||||
if (!process.env.IS_CONTINUOUS_INTEGRATION || !isDesktopAppTag(process.env.GIT_TAG_NAME)) {
|
||||
console.info(`Either not running in CI or not processing a desktop app tag - skipping notarization. process.env.IS_CONTINUOUS_INTEGRATION = ${process.env.IS_CONTINUOUS_INTEGRATION}; process.env.GIT_TAG_NAME = ${process.env.GIT_TAG_NAME}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!process.env.APPLE_ID || !process.env.APPLE_ID_PASSWORD) {
|
||||
console.warn('Environment variables APPLE_ID and APPLE_ID_PASSWORD not found - notarization will NOT be done.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Same appId in electron-builder.
|
||||
const appId = 'net.cozic.joplin-desktop';
|
||||
|
||||
const appPath = join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
|
||||
if (!existsSync(appPath)) {
|
||||
throw new Error(`Cannot find application at: ${appPath}`);
|
||||
}
|
||||
|
||||
console.log(`Notarizing ${appId} found at ${appPath}`);
|
||||
|
||||
// Every x seconds we print something to stdout, otherwise CI may timeout
|
||||
// the task after 10 minutes, and Apple notarization can take more time.
|
||||
const waitingIntervalId = setInterval(() => {
|
||||
console.log('.');
|
||||
}, 60000);
|
||||
|
||||
try {
|
||||
await notarize({
|
||||
appBundleId: appId,
|
||||
appPath: appPath,
|
||||
|
||||
// Apple Developer email address
|
||||
appleId: process.env.APPLE_ID,
|
||||
|
||||
// App-specific password: https://support.apple.com/en-us/HT204397
|
||||
appleIdPassword: process.env.APPLE_ID_PASSWORD,
|
||||
|
||||
// When Apple ID is attached to multiple providers (eg if the
|
||||
// account has been used to build multiple apps for different
|
||||
// companies), in that case the provider "Team Short Name" (also
|
||||
// known as "ProviderShortname") must be provided.
|
||||
//
|
||||
// Use this to get it:
|
||||
//
|
||||
// xcrun altool --list-providers -u APPLE_ID -p APPLE_ID_PASSWORD
|
||||
// ascProvider: process.env.APPLE_ASC_PROVIDER,
|
||||
|
||||
// In our case, the team ID is the same as the legacy ASC_PROVIDER
|
||||
teamId: process.env.APPLE_ASC_PROVIDER,
|
||||
|
||||
tool: 'notarytool',
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
} as any);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
clearInterval(waitingIntervalId);
|
||||
|
||||
// It appears that electron-notarize doesn't staple the app, but without
|
||||
// this we were still getting the malware warning when launching the app.
|
||||
// Stapling the app means attaching the notarization ticket to it, so that
|
||||
// if the user is offline, macOS can still check if the app was notarized.
|
||||
// So it seems to be more or less optional, but at least in our case it
|
||||
// wasn't.
|
||||
console.log('Staple notarization ticket to the app...');
|
||||
const staplerCmd = `xcrun stapler staple "${appPath}"`;
|
||||
console.log(`> ${staplerCmd}`);
|
||||
console.log(await execCommand(staplerCmd));
|
||||
|
||||
console.log(`Done notarizing ${appId}`);
|
||||
await notarizeFile(appPath);
|
||||
};
|
||||
|
||||
@@ -246,3 +246,6 @@ youtu
|
||||
nocookie
|
||||
fgag
|
||||
mrjo
|
||||
spctl
|
||||
codesign
|
||||
productbuild
|
||||
Reference in New Issue
Block a user