mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-12-27 17:31:36 -06:00
Calling auto update from demo app
This commit is contained in:
parent
bff51a782d
commit
9adec0ffda
@ -35,23 +35,23 @@ void internal_log( char const* file, int line, char const* func, char const* lev
|
||||
}
|
||||
|
||||
time_t rawtime;
|
||||
struct tm* info;
|
||||
time( &rawtime );
|
||||
info = localtime( &rawtime );
|
||||
int offset = g_log.time_offset;
|
||||
int offs_s = offset % 60;
|
||||
offset -= offs_s;
|
||||
int offs_m = ( offset % (60 * 60) ) / 60;
|
||||
offset -= offs_m * 60;
|
||||
int offs_h = offset / ( 60 * 60 );
|
||||
struct tm* info;
|
||||
time( &rawtime );
|
||||
info = localtime( &rawtime );
|
||||
int offset = g_log.time_offset;
|
||||
int offs_s = offset % 60;
|
||||
offset -= offs_s;
|
||||
int offs_m = ( offset % (60 * 60) ) / 60;
|
||||
offset -= offs_m * 60;
|
||||
int offs_h = offset / ( 60 * 60 );
|
||||
|
||||
fprintf( g_log.file, "%d-%02d-%02d %02d:%02d:%02d:025 %+02d:%02d | %s | %s(%d) | %s: ", info->tm_year + 1900, info->tm_mon + 1,
|
||||
info->tm_mday, info->tm_hour, info->tm_min, info->tm_sec, offs_h, offs_m, level, file, line, func );
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
vfprintf( g_log.file, format, args );
|
||||
va_end( args );
|
||||
fflush( g_log.file );
|
||||
fprintf( g_log.file, "%d-%02d-%02d %02d:%02d:%02d:025 %+02d:%02d | %s | %s(%d) | %s: ", info->tm_year + 1900, info->tm_mon + 1,
|
||||
info->tm_mday, info->tm_hour, info->tm_min, info->tm_sec, offs_h, offs_m, level, file, line, func );
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
vfprintf( g_log.file, format, args );
|
||||
va_end( args );
|
||||
fflush( g_log.file );
|
||||
}
|
||||
|
||||
LeaveCriticalSection( &g_log.mutex );
|
||||
@ -146,6 +146,10 @@ int main( int argc, char** argv ) {
|
||||
while( size < sizeof( response ) - 1 && status == IPC_RECEIVE_STATUS_MORE_DATA ) {
|
||||
status = ipc_client_receive( client, response + size,
|
||||
sizeof( response ) - size - 1, &temp_size );
|
||||
if( status == IPC_RECEIVE_STATUS_ERROR ) {
|
||||
LOG_ERROR( "Receiving response failed" );
|
||||
break;
|
||||
}
|
||||
size += temp_size;
|
||||
}
|
||||
response[ size ] = '\0';
|
||||
@ -175,6 +179,10 @@ int main( int argc, char** argv ) {
|
||||
while( size < sizeof( response ) - 1 && status == IPC_RECEIVE_STATUS_MORE_DATA ) {
|
||||
status = ipc_client_receive( client, response + size,
|
||||
sizeof( response ) - size - 1, &temp_size );
|
||||
if( status == IPC_RECEIVE_STATUS_ERROR ) {
|
||||
LOG_ERROR( "Receiving response failed" );
|
||||
break;
|
||||
}
|
||||
size += temp_size;
|
||||
}
|
||||
response[ size ] = '\0';
|
||||
|
@ -35,6 +35,9 @@
|
||||
// or the installation packages signed with it will be rejected.
|
||||
|
||||
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 */
|
||||
"\x99\xb3\x33\x3a\xc4\x45\x7a\x4e\x21\xa5\x27\xcc\x11\x04\x0b\x28\xc1\x5c\x1d\x3f",
|
||||
};
|
||||
@ -68,36 +71,36 @@ void internal_log( char const* file, int line, char const* func, char const* lev
|
||||
}
|
||||
|
||||
time_t rawtime;
|
||||
struct tm* info;
|
||||
time( &rawtime );
|
||||
info = localtime( &rawtime );
|
||||
int offset = g_log.time_offset;
|
||||
int offs_s = offset % 60;
|
||||
offset -= offs_s;
|
||||
int offs_m = ( offset % (60 * 60) ) / 60;
|
||||
offset -= offs_m * 60;
|
||||
int offs_h = offset / ( 60 * 60 );
|
||||
struct tm* info;
|
||||
time( &rawtime );
|
||||
info = localtime( &rawtime );
|
||||
int offset = g_log.time_offset;
|
||||
int offs_s = offset % 60;
|
||||
offset -= offs_s;
|
||||
int offs_m = ( offset % (60 * 60) ) / 60;
|
||||
offset -= offs_m * 60;
|
||||
int offs_h = offset / ( 60 * 60 );
|
||||
|
||||
if( g_log.file ) {
|
||||
fprintf( g_log.file, "%d-%02d-%02d %02d:%02d:%02d:025 %+02d:%02d | %s | %s(%d) | %s: ", info->tm_year + 1900, info->tm_mon + 1,
|
||||
info->tm_mday, info->tm_hour, info->tm_min, info->tm_sec, offs_h, offs_m, level, file, line, func );
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
vfprintf( g_log.file, format, args );
|
||||
va_end( args );
|
||||
fflush( g_log.file );
|
||||
fprintf( g_log.file, "%d-%02d-%02d %02d:%02d:%02d:025 %+02d:%02d | %s | %s(%d) | %s: ", info->tm_year + 1900, info->tm_mon + 1,
|
||||
info->tm_mday, info->tm_hour, info->tm_min, info->tm_sec, offs_h, offs_m, level, file, line, func );
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
vfprintf( g_log.file, format, args );
|
||||
va_end( args );
|
||||
fflush( g_log.file );
|
||||
}
|
||||
|
||||
size_t len = IPC_MESSAGE_MAX_LENGTH;
|
||||
char* buffer = (char*) malloc( len + 1 );
|
||||
size_t count = snprintf( buffer, len, "%d-%02d-%02d %02d:%02d:%02d:025 %+02d:%02d | %s | %s(%d) | %s: ", info->tm_year + 1900, info->tm_mon + 1,
|
||||
info->tm_mday, info->tm_hour, info->tm_min, info->tm_sec, offs_h, offs_m, level, file, line, func );
|
||||
size_t count = snprintf( buffer, len, "%d-%02d-%02d %02d:%02d:%02d:025 %+02d:%02d | %s | %s(%d) | %s: ", info->tm_year + 1900, info->tm_mon + 1,
|
||||
info->tm_mday, info->tm_hour, info->tm_min, info->tm_sec, offs_h, offs_m, level, file, line, func );
|
||||
buffer[ count ] = '\0';
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
count += vsnprintf( buffer + count, len - count, format, args );
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
count += vsnprintf( buffer + count, len - count, format, args );
|
||||
buffer[ count ] = '\0';
|
||||
va_end( args );
|
||||
va_end( args );
|
||||
|
||||
if( g_log.count >= g_log.capacity ) {
|
||||
g_log.capacity *= 2;
|
||||
@ -260,7 +263,7 @@ BOOL VerifyEmbeddedSignature( LPCWSTR pwszSourceFile ) {
|
||||
// and Wintrust_Data.
|
||||
lStatus = WinVerifyTrust( NULL, &WVTPolicyGUID, &WinTrustData );
|
||||
|
||||
BOOL result = FALSE;
|
||||
BOOL result = FALSE;
|
||||
switch( lStatus ) {
|
||||
case ERROR_SUCCESS:
|
||||
/*
|
||||
@ -277,7 +280,7 @@ BOOL VerifyEmbeddedSignature( LPCWSTR pwszSourceFile ) {
|
||||
subject.
|
||||
*/
|
||||
LOG_INFO( "The file is signed and the signature was verified." );
|
||||
result = TRUE;
|
||||
result = TRUE;
|
||||
break;
|
||||
|
||||
case TRUST_E_NOSIGNATURE:
|
||||
@ -348,54 +351,57 @@ BOOL validate_installer( char const* filename ) {
|
||||
wchar_t* wfilename = (wchar_t*) malloc( sizeof( wchar_t* ) * ( length + 1 ) );
|
||||
mbstowcs_s( &length, wfilename, length, filename, strlen( filename ) );
|
||||
BOOL signature_valid = VerifyEmbeddedSignature( wfilename );
|
||||
if( !signature_valid ) {
|
||||
free( wfilename );
|
||||
return FALSE;
|
||||
}
|
||||
if( !signature_valid ) {
|
||||
LOG_ERROR( "The installer was not signed with a valid certificate" );
|
||||
free( wfilename );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD dwEncoding, dwContentType, dwFormatType;
|
||||
HCERTSTORE hStore = NULL;
|
||||
HCRYPTMSG hMsg = NULL;
|
||||
BOOL result = CryptQueryObject( CERT_QUERY_OBJECT_FILE,
|
||||
wfilename,
|
||||
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
|
||||
CERT_QUERY_FORMAT_FLAG_BINARY,
|
||||
0,
|
||||
&dwEncoding,
|
||||
&dwContentType,
|
||||
&dwFormatType,
|
||||
&hStore,
|
||||
&hMsg,
|
||||
NULL );
|
||||
BOOL result = CryptQueryObject( CERT_QUERY_OBJECT_FILE,
|
||||
wfilename,
|
||||
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
|
||||
CERT_QUERY_FORMAT_FLAG_BINARY,
|
||||
0,
|
||||
&dwEncoding,
|
||||
&dwContentType,
|
||||
&dwFormatType,
|
||||
&hStore,
|
||||
&hMsg,
|
||||
NULL );
|
||||
free( wfilename );
|
||||
|
||||
|
||||
if( !result ) {
|
||||
LOG_LAST_ERROR( "CryptQueryObject failed" );
|
||||
return FALSE;
|
||||
}
|
||||
LOG_LAST_ERROR( "CryptQueryObject failed" );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL found = FALSE;
|
||||
for( int i = 0; i < sizeof( thumbprints ) / sizeof( *thumbprints ); ++i ) {
|
||||
CRYPT_HASH_BLOB hash_blob = {
|
||||
BOOL found = FALSE;
|
||||
for( int i = 0; i < sizeof( thumbprints ) / sizeof( *thumbprints ); ++i ) {
|
||||
CRYPT_HASH_BLOB hash_blob = {
|
||||
sizeof( thumbprints[ i ].hash ) / sizeof( *(thumbprints[ i ].hash) ),
|
||||
thumbprints[ i ].hash
|
||||
};
|
||||
CERT_CONTEXT const* cert_context = CertFindCertificateInStore(
|
||||
hStore,
|
||||
(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING),
|
||||
0,
|
||||
CERT_FIND_HASH,
|
||||
&hash_blob,
|
||||
NULL );
|
||||
|
||||
CERT_CONTEXT const* cert_context = CertFindCertificateInStore(
|
||||
hStore,
|
||||
(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING),
|
||||
0,
|
||||
CERT_FIND_HASH,
|
||||
&hash_blob,
|
||||
NULL );
|
||||
|
||||
if( cert_context ) {
|
||||
found = TRUE;
|
||||
CertFreeCertificateContext( cert_context );
|
||||
}
|
||||
}
|
||||
|
||||
CryptMsgClose( hMsg );
|
||||
CertCloseStore( hStore, CERT_CLOSE_STORE_FORCE_FLAG );
|
||||
found = TRUE;
|
||||
CertFreeCertificateContext( cert_context );
|
||||
}
|
||||
}
|
||||
if( !found ) {
|
||||
LOG_ERROR( "The installer was not signed with a known Symphony certificate" );
|
||||
}
|
||||
CryptMsgClose( hMsg );
|
||||
CertCloseStore( hStore, CERT_CLOSE_STORE_FORCE_FLAG );
|
||||
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" );
|
||||
return false;
|
||||
}
|
||||
LOG_INFO( "Signature of installer successfully validated" );
|
||||
|
||||
char command[ 512 ];
|
||||
sprintf( command, "/i %s /q", filename );
|
||||
char command[ 512 ];
|
||||
sprintf( command, "/i %s /q", filename );
|
||||
LOG_INFO( "MSI command: %s", command );
|
||||
|
||||
SHELLEXECUTEINFO ShExecInfo = { 0 };
|
||||
ShExecInfo.cbSize = sizeof( SHELLEXECUTEINFO );
|
||||
@ -422,9 +430,12 @@ bool run_installer( char const* filename ) {
|
||||
ShExecInfo.nShow = SW_SHOW;
|
||||
ShExecInfo.hInstApp = NULL;
|
||||
if( ShellExecuteEx( &ShExecInfo ) ) {
|
||||
LOG_INFO( "ShellExecuteEx successful, waiting to finish" );
|
||||
WaitForSingleObject( ShExecInfo.hProcess, INFINITE );
|
||||
LOG_INFO( "ShellExecuteEx finished" );
|
||||
DWORD exitCode = 0;
|
||||
GetExitCodeProcess( ShExecInfo.hProcess, &exitCode );
|
||||
LOG_INFO( "ShellExecuteEx exit code: %d", exitCode );
|
||||
CloseHandle( ShExecInfo.hProcess );
|
||||
return exitCode == 0 ? true : false;
|
||||
} else {
|
||||
@ -451,8 +462,10 @@ void ipc_handler( char const* request, void* user_data, char* response, size_t c
|
||||
// "msi" - run installer
|
||||
LOG_INFO( "MSI command, running installer" );
|
||||
if( run_installer( request + 4 ) ) {
|
||||
LOG_INFO( "Response: OK" );
|
||||
strcpy( response, "OK" );
|
||||
} else {
|
||||
LOG_INFO( "Response: ERROR" );
|
||||
strcpy( response, "ERROR" );
|
||||
}
|
||||
} else if( strlen( request ) == 3 && stricmp( request, "log" ) == 0 ) {
|
||||
|
10
auto_update/manifest.xml
Normal file
10
auto_update/manifest.xml
Normal 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>
|
@ -5,6 +5,6 @@
|
||||
"scripts": {
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
69
src/app/auto-update-handler.ts
Normal file
69
src/app/auto-update-handler.ts
Normal 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 };
|
@ -10,6 +10,7 @@ import { logger } from '../common/logger';
|
||||
import { activityDetection } from './activity-detection';
|
||||
import { analytics } from './analytics-handler';
|
||||
import appStateHandler from './app-state-handler';
|
||||
import { autoUpdate } from './auto-update-handler';
|
||||
import { CloudConfigDataTypes, config, ICloudConfig } from './config-handler';
|
||||
import { downloadHandler } from './download-handler';
|
||||
import { memoryMonitor } from './memory-monitor';
|
||||
@ -291,6 +292,9 @@ ipcMain.on(
|
||||
?.webContents.setZoomFactor(arg.zoomLevel as number);
|
||||
}
|
||||
break;
|
||||
case apiCmds.autoUpdate:
|
||||
autoUpdate.update(arg.filename);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ export enum apiCmds {
|
||||
showNotification = 'show-notification',
|
||||
closeAllWrapperWindows = 'close-all-windows',
|
||||
setZoomLevel = 'set-zoom-level',
|
||||
autoUpdate = 'auto-update',
|
||||
}
|
||||
|
||||
export enum apiName {
|
||||
@ -87,6 +88,7 @@ export interface IApiArgs {
|
||||
notificationId: number;
|
||||
theme: Themes;
|
||||
zoomLevel: number;
|
||||
filename: string;
|
||||
}
|
||||
|
||||
export type Themes = 'light' | 'dark';
|
||||
|
@ -270,6 +270,14 @@
|
||||
</tr>
|
||||
</table>
|
||||
<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>
|
||||
<script>
|
||||
window.name = 'main';
|
||||
@ -314,6 +322,7 @@
|
||||
getCPUUsage: 'get-cpu-usage',
|
||||
checkMediaPermission: 'check-media-permission',
|
||||
restartApp: 'restart-app',
|
||||
autoUpdate: 'auto-update',
|
||||
};
|
||||
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;
|
||||
|
||||
const openWinButton = document.getElementById('open-win');
|
||||
|
@ -246,6 +246,9 @@ export class AppBridge {
|
||||
response: mediaPermission,
|
||||
});
|
||||
break;
|
||||
case apiCmds.autoUpdate:
|
||||
ssf.autoUpdate(data.filename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user