You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Chore: Implement SSL eSigner for Windows app signing (#13397)
This commit is contained in:
		
							
								
								
									
										26
									
								
								.github/workflows/github-actions-main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								.github/workflows/github-actions-main.yml
									
									
									
									
										vendored
									
									
								
							| @@ -50,6 +50,22 @@ jobs: | ||||
|           username: ${{ secrets.DOCKERHUB_USERNAME }} | ||||
|           password: ${{ secrets.DOCKERHUB_TOKEN }} | ||||
|  | ||||
|       # - name: Test Windows app signing | ||||
|       #   if: runner.os == 'Windows' | ||||
|       #   env: | ||||
|       #     GH_TOKEN: ${{ secrets.GH_TOKEN }} | ||||
|       #     IS_CONTINUOUS_INTEGRATION: 1 | ||||
|       #     BUILD_SEQUENCIAL: 1 | ||||
|       #     SSL_ESIGNER_USER_NAME: ${{ secrets.SSL_ESIGNER_USER_NAME }} | ||||
|       #     SSL_ESIGNER_USER_PASSWORD: ${{ secrets.SSL_ESIGNER_USER_PASSWORD }} | ||||
|       #     SSL_ESIGNER_CREDENTIAL_ID: ${{ secrets.SSL_ESIGNER_CREDENTIAL_ID }} | ||||
|       #     SSL_ESIGNER_USER_TOTP: ${{ secrets.SSL_ESIGNER_USER_TOTP }} | ||||
|       #     SIGN_APPLICATION: 1 | ||||
|       #   # To ensure that the operations stop on failure, all commands | ||||
|       #   # should be on one line with "&&" in between. | ||||
|       #   run: | | ||||
|       #     yarn install && cd packages/app-desktop && yarn dist | ||||
|  | ||||
|       - name: Run tests, build and publish Linux and macOS apps | ||||
|         if: runner.os == 'Linux' || runner.os == 'macOs' | ||||
|         env: | ||||
| @@ -71,11 +87,14 @@ jobs: | ||||
|       - name: Build and publish Windows app | ||||
|         if: runner.os == 'Windows' && startsWith(github.ref, 'refs/tags/v') | ||||
|         env: | ||||
|           CSC_KEY_PASSWORD: ${{ secrets.WINDOWS_CSC_KEY_PASSWORD }} | ||||
|           CSC_LINK: ${{ secrets.WINDOWS_CSC_LINK }} | ||||
|           GH_TOKEN: ${{ secrets.GH_TOKEN }} | ||||
|           IS_CONTINUOUS_INTEGRATION: 1 | ||||
|           BUILD_SEQUENCIAL: 1 | ||||
|           SSL_ESIGNER_USER_NAME: ${{ secrets.SSL_ESIGNER_USER_NAME }} | ||||
|           SSL_ESIGNER_USER_PASSWORD: ${{ secrets.SSL_ESIGNER_USER_PASSWORD }} | ||||
|           SSL_ESIGNER_CREDENTIAL_ID: ${{ secrets.SSL_ESIGNER_CREDENTIAL_ID }} | ||||
|           SSL_ESIGNER_USER_TOTP: ${{ secrets.SSL_ESIGNER_USER_TOTP }} | ||||
|           SIGN_APPLICATION: 1 | ||||
|         # To ensure that the operations stop on failure, all commands | ||||
|         # should be on one line with "&&" in between. | ||||
|         run: | | ||||
| @@ -195,5 +214,4 @@ jobs: | ||||
|           if [[ "$actual_body" != "$expected_body" ]]; then | ||||
|             echo 'Failed while checking the body response after request to /api/ping' | ||||
|             exit 1; | ||||
|           fi | ||||
|  | ||||
|           fi | ||||
| @@ -46,6 +46,7 @@ | ||||
|     "asar": true, | ||||
|     "asarUnpack": "./node_modules/node-notifier/vendor/**", | ||||
|     "win": { | ||||
|       "sign": "./sign.js", | ||||
|       "rfc3161TimeStampServer": "http://timestamp.digicert.com", | ||||
|       "icon": "../../Assets/ImageSources/Joplin.ico", | ||||
|       "target": [ | ||||
|   | ||||
							
								
								
									
										96
									
								
								packages/app-desktop/sign.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								packages/app-desktop/sign.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* eslint-disable no-console */ | ||||
|  | ||||
| const { execSync } = require('child_process'); | ||||
| const { chdir, cwd } = require('process'); | ||||
| const { mkdirpSync, moveSync, pathExists } = require('fs-extra'); | ||||
| const { readdirSync, writeFileSync } = require('fs'); | ||||
|  | ||||
| const signToolName = 'CodeSignTool.bat'; | ||||
|  | ||||
| const downloadSignTool = async () => { | ||||
| 	const signToolUrl = 'https://www.ssl.com/download/codesigntool-for-windows/'; | ||||
| 	const downloadDir = `${__dirname}/signToolDownloadTemp`; | ||||
| 	const extractDir = `${__dirname}/signToolExtractTemp`; | ||||
|  | ||||
| 	if (await pathExists(`${extractDir}/${signToolName}`)) { | ||||
| 		console.info('sign.js: Sign tool has already been downloaded - skipping'); | ||||
| 		return extractDir; | ||||
| 	} | ||||
|  | ||||
| 	mkdirpSync(downloadDir); | ||||
| 	mkdirpSync(extractDir); | ||||
|  | ||||
| 	const response = await fetch(signToolUrl); | ||||
| 	if (!response.ok) throw new Error(`sign.js: HTTP error ${response.status}: ${response.statusText}`); | ||||
|  | ||||
| 	const zipPath = `${downloadDir}/codeSignTool.zip`; | ||||
|  | ||||
| 	const buffer = Buffer.from(await response.arrayBuffer()); | ||||
| 	writeFileSync(zipPath, buffer); | ||||
|  | ||||
| 	console.info('sign.js: Downloaded sign tool zip:', readdirSync(downloadDir)); | ||||
|  | ||||
| 	mkdirpSync(extractDir); | ||||
|  | ||||
| 	execSync( | ||||
| 		`powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${extractDir}' -Force"`, | ||||
| 		{ stdio: 'inherit' }, | ||||
| 	); | ||||
|  | ||||
| 	console.info('sign.js: Extracted sign tool zip:', readdirSync(extractDir)); | ||||
|  | ||||
| 	return extractDir; | ||||
| }; | ||||
|  | ||||
| exports.default = async (configuration) => { | ||||
| 	const inputFilePath = configuration.path; | ||||
|  | ||||
| 	const { | ||||
| 		SSL_ESIGNER_USER_NAME, | ||||
| 		SSL_ESIGNER_USER_PASSWORD, | ||||
| 		SSL_ESIGNER_CREDENTIAL_ID, | ||||
| 		SSL_ESIGNER_USER_TOTP, | ||||
| 		SIGN_APPLICATION, | ||||
| 	} = process.env; | ||||
|  | ||||
| 	console.info('sign.js: File to sign:', inputFilePath); | ||||
|  | ||||
| 	if (SIGN_APPLICATION !== '1') { | ||||
| 		console.info('sign.js: SIGN_APPLICATION != 1 - not signing application'); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	console.info('sign.js: SIGN_APPLICATION = 1 - signing application'); | ||||
|  | ||||
| 	const signToolDir = await downloadSignTool(); | ||||
| 	const tempDir = `${__dirname}/temp`; | ||||
|  | ||||
| 	mkdirpSync(tempDir); | ||||
|  | ||||
| 	const previousDir = cwd(); | ||||
| 	chdir(signToolDir); | ||||
|  | ||||
| 	try { | ||||
| 		const cmd = [ | ||||
| 			`${signToolName} sign`, | ||||
| 			`-input_file_path="${inputFilePath}"`, | ||||
| 			`-output_dir_path="${tempDir}"`, | ||||
| 			`-credential_id="${SSL_ESIGNER_CREDENTIAL_ID}"`, | ||||
| 			`-username="${SSL_ESIGNER_USER_NAME}"`, | ||||
| 			`-password="${SSL_ESIGNER_USER_PASSWORD}"`, | ||||
| 			`-totp_secret="${SSL_ESIGNER_USER_TOTP}"`, | ||||
| 		]; | ||||
|  | ||||
| 		execSync(cmd.join(' ')); | ||||
|  | ||||
| 		const createdFiles = readdirSync(tempDir); | ||||
| 		console.info('sign.js: Created files:', createdFiles); | ||||
|  | ||||
| 		moveSync(`${tempDir}/${createdFiles[0]}`, inputFilePath, { overwrite: true }); | ||||
| 	} catch (error) { | ||||
| 		console.error('sign.js: Could not sign file:', error); | ||||
| 		process.exit(1); | ||||
| 	} finally { | ||||
| 		chdir(previousDir); | ||||
| 	} | ||||
| }; | ||||
| @@ -202,4 +202,6 @@ vikasmanimc | ||||
| traspire | ||||
| Pokies | ||||
| Pokiesman | ||||
| Gamstop | ||||
| Gamstop | ||||
| ESIGNER | ||||
| TOTP | ||||
|   | ||||
		Reference in New Issue
	
	Block a user