Calling auto update from demo app

This commit is contained in:
Mattias Gustavsson 2021-09-29 15:47:57 +02:00
parent bff51a782d
commit 9adec0ffda
10 changed files with 219 additions and 80 deletions

View File

@ -146,6 +146,10 @@ int main( int argc, char** argv ) {
while( size < sizeof( response ) - 1 && status == IPC_RECEIVE_STATUS_MORE_DATA ) { while( size < sizeof( response ) - 1 && status == IPC_RECEIVE_STATUS_MORE_DATA ) {
status = ipc_client_receive( client, response + size, status = ipc_client_receive( client, response + size,
sizeof( response ) - size - 1, &temp_size ); sizeof( response ) - size - 1, &temp_size );
if( status == IPC_RECEIVE_STATUS_ERROR ) {
LOG_ERROR( "Receiving response failed" );
break;
}
size += temp_size; size += temp_size;
} }
response[ size ] = '\0'; response[ size ] = '\0';
@ -175,6 +179,10 @@ int main( int argc, char** argv ) {
while( size < sizeof( response ) - 1 && status == IPC_RECEIVE_STATUS_MORE_DATA ) { while( size < sizeof( response ) - 1 && status == IPC_RECEIVE_STATUS_MORE_DATA ) {
status = ipc_client_receive( client, response + size, status = ipc_client_receive( client, response + size,
sizeof( response ) - size - 1, &temp_size ); sizeof( response ) - size - 1, &temp_size );
if( status == IPC_RECEIVE_STATUS_ERROR ) {
LOG_ERROR( "Receiving response failed" );
break;
}
size += temp_size; size += temp_size;
} }
response[ size ] = '\0'; response[ size ] = '\0';

View File

@ -35,6 +35,9 @@
// or the installation packages signed with it will be rejected. // or the installation packages signed with it will be rejected.
struct { BYTE hash[ 20 ]; } thumbprints[] = { struct { BYTE hash[ 20 ]; } thumbprints[] = {
/* e846d3fb2a93007e921c3affcd7032f0186f116a */
"\xe8\x46\xd3\xfb\x2a\x93\x00\x7e\x92\x1c\x3a\xff\xcd\x70\x32\xf0\x18\x6f\x11\x6a",
/* 99b3333ac4457a4e21a527cc11040b28c15c1d3f */ /* 99b3333ac4457a4e21a527cc11040b28c15c1d3f */
"\x99\xb3\x33\x3a\xc4\x45\x7a\x4e\x21\xa5\x27\xcc\x11\x04\x0b\x28\xc1\x5c\x1d\x3f", "\x99\xb3\x33\x3a\xc4\x45\x7a\x4e\x21\xa5\x27\xcc\x11\x04\x0b\x28\xc1\x5c\x1d\x3f",
}; };
@ -349,6 +352,7 @@ BOOL validate_installer( char const* filename ) {
mbstowcs_s( &length, wfilename, length, filename, strlen( filename ) ); mbstowcs_s( &length, wfilename, length, filename, strlen( filename ) );
BOOL signature_valid = VerifyEmbeddedSignature( wfilename ); BOOL signature_valid = VerifyEmbeddedSignature( wfilename );
if( !signature_valid ) { if( !signature_valid ) {
LOG_ERROR( "The installer was not signed with a valid certificate" );
free( wfilename ); free( wfilename );
return FALSE; return FALSE;
} }
@ -393,7 +397,9 @@ BOOL validate_installer( char const* filename ) {
CertFreeCertificateContext( cert_context ); CertFreeCertificateContext( cert_context );
} }
} }
if( !found ) {
LOG_ERROR( "The installer was not signed with a known Symphony certificate" );
}
CryptMsgClose( hMsg ); CryptMsgClose( hMsg );
CertCloseStore( hStore, CERT_CLOSE_STORE_FORCE_FLAG ); CertCloseStore( hStore, CERT_CLOSE_STORE_FORCE_FLAG );
return found; return found;
@ -407,9 +413,11 @@ bool run_installer( char const* filename ) {
LOG_ERROR( "The signature of %s could is not a valid Symphony signature" ); LOG_ERROR( "The signature of %s could is not a valid Symphony signature" );
return false; return false;
} }
LOG_INFO( "Signature of installer successfully validated" );
char command[ 512 ]; char command[ 512 ];
sprintf( command, "/i %s /q", filename ); sprintf( command, "/i %s /q", filename );
LOG_INFO( "MSI command: %s", command );
SHELLEXECUTEINFO ShExecInfo = { 0 }; SHELLEXECUTEINFO ShExecInfo = { 0 };
ShExecInfo.cbSize = sizeof( SHELLEXECUTEINFO ); ShExecInfo.cbSize = sizeof( SHELLEXECUTEINFO );
@ -422,9 +430,12 @@ bool run_installer( char const* filename ) {
ShExecInfo.nShow = SW_SHOW; ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL; ShExecInfo.hInstApp = NULL;
if( ShellExecuteEx( &ShExecInfo ) ) { if( ShellExecuteEx( &ShExecInfo ) ) {
LOG_INFO( "ShellExecuteEx successful, waiting to finish" );
WaitForSingleObject( ShExecInfo.hProcess, INFINITE ); WaitForSingleObject( ShExecInfo.hProcess, INFINITE );
LOG_INFO( "ShellExecuteEx finished" );
DWORD exitCode = 0; DWORD exitCode = 0;
GetExitCodeProcess( ShExecInfo.hProcess, &exitCode ); GetExitCodeProcess( ShExecInfo.hProcess, &exitCode );
LOG_INFO( "ShellExecuteEx exit code: %d", exitCode );
CloseHandle( ShExecInfo.hProcess ); CloseHandle( ShExecInfo.hProcess );
return exitCode == 0 ? true : false; return exitCode == 0 ? true : false;
} else { } else {
@ -451,8 +462,10 @@ void ipc_handler( char const* request, void* user_data, char* response, size_t c
// "msi" - run installer // "msi" - run installer
LOG_INFO( "MSI command, running installer" ); LOG_INFO( "MSI command, running installer" );
if( run_installer( request + 4 ) ) { if( run_installer( request + 4 ) ) {
LOG_INFO( "Response: OK" );
strcpy( response, "OK" ); strcpy( response, "OK" );
} else { } else {
LOG_INFO( "Response: ERROR" );
strcpy( response, "ERROR" ); strcpy( response, "ERROR" );
} }
} else if( strlen( request ) == 3 && stricmp( request, "log" ) == 0 ) { } else if( strlen( request ) == 3 && stricmp( request, "log" ) == 0 ) {

10
auto_update/manifest.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -5,6 +5,6 @@
"scripts": { "scripts": {
"test": "cl tests.cpp /O2 /MTd /D_DEBUG /D_CRTDBG_MAP_ALLOC /nologo /link /SUBSYSTEM:CONSOLE && tests.exe", "test": "cl tests.cpp /O2 /MTd /D_DEBUG /D_CRTDBG_MAP_ALLOC /nologo /link /SUBSYSTEM:CONSOLE && tests.exe",
"preinstall": "npm run test && npm run build", "preinstall": "npm run test && npm run build",
"build": "rc.exe /nologo auto_update_helper.rc & cl auto_update_helper.c auto_update_helper.res /O2 /MT /nologo /link /SUBSYSTEM:CONSOLE & rc.exe /nologo auto_update_service.rc & cl auto_update_service.c auto_update_service.res /O2 /MT /nologo /link /SUBSYSTEM:CONSOLE" "build": "rc.exe /nologo auto_update_helper.rc & cl auto_update_helper.c auto_update_helper.res /O2 /MT /nologo /link /SUBSYSTEM:CONSOLE /MANIFESTINPUT:manifest.xml /MANIFEST:EMBED & rc.exe /nologo auto_update_service.rc & cl auto_update_service.c auto_update_service.res /O2 /MT /nologo /link /SUBSYSTEM:CONSOLE /MANIFESTINPUT:manifest.xml /MANIFEST:EMBED"
} }
} }

View File

@ -0,0 +1,69 @@
import { app } from 'electron';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { spawn } from 'child_process';
import { isDevEnv, isElectronQA, isWindowsOS } from '../common/env';
import { logger } from '../common/logger';
class AutoUpdate {
private readonly tempDir: string;
private filename: string;
private logFilePath: string;
private updateUtil: string;
private updateUtilArgs: ReadonlyArray<string>;
constructor() {
if (isElectronQA) {
this.tempDir = os.tmpdir();
} else {
this.tempDir = path.join(app.getPath('userData'), 'temp');
if (!fs.existsSync(this.tempDir)) {
fs.mkdirSync(this.tempDir);
}
}
this.filename = '';
this.logFilePath = path.join(this.tempDir, 'auto_update.log');
this.updateUtil = isDevEnv
? path.join(
__dirname,
'../../../node_modules/auto-update/auto_update_helper.exe',
)
: path.join(path.dirname(app.getPath('exe')), 'auto_update_helper.exe');
this.updateUtilArgs = [];
}
/**
* Launch the auto update helper
*/
public async update(filename: string) {
logger.info(`auto-update-handler: Starting auto update!`);
this.filename = filename;
if (isWindowsOS) {
this.updateUtilArgs = [
this.filename,
app.getPath('exe'),
this.logFilePath,
];
logger.info(
`auto-update-handler: Running update helper${this.updateUtil} with args ${this.updateUtilArgs}!`,
);
try {
spawn(this.updateUtil, this.updateUtilArgs);
} catch (error) {
logger.error(
`auto-update-handler: auto update failed. Error: ${error}!`,
);
}
}
}
}
const autoUpdate = new AutoUpdate();
export { autoUpdate };

View File

@ -10,6 +10,7 @@ import { logger } from '../common/logger';
import { activityDetection } from './activity-detection'; import { activityDetection } from './activity-detection';
import { analytics } from './analytics-handler'; import { analytics } from './analytics-handler';
import appStateHandler from './app-state-handler'; import appStateHandler from './app-state-handler';
import { autoUpdate } from './auto-update-handler';
import { CloudConfigDataTypes, config, ICloudConfig } from './config-handler'; import { CloudConfigDataTypes, config, ICloudConfig } from './config-handler';
import { downloadHandler } from './download-handler'; import { downloadHandler } from './download-handler';
import { memoryMonitor } from './memory-monitor'; import { memoryMonitor } from './memory-monitor';
@ -291,6 +292,9 @@ ipcMain.on(
?.webContents.setZoomFactor(arg.zoomLevel as number); ?.webContents.setZoomFactor(arg.zoomLevel as number);
} }
break; break;
case apiCmds.autoUpdate:
autoUpdate.update(arg.filename);
break;
default: default:
break; break;
} }

View File

@ -47,6 +47,7 @@ export enum apiCmds {
showNotification = 'show-notification', showNotification = 'show-notification',
closeAllWrapperWindows = 'close-all-windows', closeAllWrapperWindows = 'close-all-windows',
setZoomLevel = 'set-zoom-level', setZoomLevel = 'set-zoom-level',
autoUpdate = 'auto-update',
} }
export enum apiName { export enum apiName {
@ -87,6 +88,7 @@ export interface IApiArgs {
notificationId: number; notificationId: number;
theme: Themes; theme: Themes;
zoomLevel: number; zoomLevel: number;
filename: string;
} }
export type Themes = 'light' | 'dark'; export type Themes = 'light' | 'dark';

View File

@ -270,6 +270,14 @@
</tr> </tr>
</table> </table>
<input type="button" id="restart-app" value="Restart App" /> <input type="button" id="restart-app" value="Restart App" />
<hr />
<h1>Auto-update Test</h1>
Full path to MSI <input type="text" id="update-file" />
<br />
<button id="run-update">Update</button>
<hr />
<br />
</body> </body>
<script> <script>
window.name = 'main'; window.name = 'main';
@ -314,6 +322,7 @@
getCPUUsage: 'get-cpu-usage', getCPUUsage: 'get-cpu-usage',
checkMediaPermission: 'check-media-permission', checkMediaPermission: 'check-media-permission',
restartApp: 'restart-app', restartApp: 'restart-app',
autoUpdate: 'auto-update',
}; };
let requestId = 0; let requestId = 0;
@ -469,6 +478,17 @@
} }
}); });
const runUpdateButton = document.getElementById('run-update');
runUpdateButton.addEventListener('click', () => {
const filename = document.getElementById('update-file').value;
if (window.ssf) {
const autoUpdate = new window.ssf.AutoUpdate();
autoUpdate.update(filename);
} else {
postMessage(apiCmds.autoUpdate, { filename: filename });
}
});
let win; let win;
const openWinButton = document.getElementById('open-win'); const openWinButton = document.getElementById('open-win');

View File

@ -246,6 +246,9 @@ export class AppBridge {
response: mediaPermission, response: mediaPermission,
}); });
break; break;
case apiCmds.autoUpdate:
ssf.autoUpdate(data.filename);
break;
} }
} }

View File

@ -434,6 +434,16 @@ export class SSFApi {
}); });
} }
/**
* Auto update
*/
public autoUpdate(filename: string): void {
local.ipcRenderer.send(apiName.symphonyApi, {
cmd: apiCmds.autoUpdate,
filename,
});
}
/** /**
* Sets the count on the tray icon to the given number. * Sets the count on the tray icon to the given number.
* *