sign code and uninstallers

This commit is contained in:
antelle 2016-07-22 22:13:39 +03:00
parent 43582ffbef
commit 595142b0ae
14 changed files with 436 additions and 353 deletions

View File

@ -178,11 +178,14 @@ module.exports = function(grunt) {
dest: 'tmp/desktop/KeeWeb-win32-x64/',
nonull: true
},
'desktop-win32-dist': {
cwd: 'tmp/desktop',
src: ['KeeWeb.win.x64.exe', 'KeeWeb.win.ia32.exe'],
dest: 'dist/desktop/',
expand: true,
'desktop-win32-dist-x64': {
src: 'tmp/desktop/KeeWeb.win.x64.exe',
dest: `dist/desktop/KeeWeb-${pkg.version}.win.x64.exe`,
nonull: true
},
'desktop-win32-dist-ia32': {
src: 'tmp/desktop/KeeWeb.win.ia32.exe',
dest: `dist/desktop/KeeWeb-${pkg.version}.win.ia32.exe`,
nonull: true
}
},
@ -353,19 +356,19 @@ module.exports = function(grunt) {
files: [{ cwd: 'tmp/desktop/app', src: '**', expand: true }]
},
'win32-x64': {
options: { archive: 'dist/desktop/KeeWeb.win.x64.zip' },
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.win.x64.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-win32-x64', src: '**', expand: true }]
},
'win32-ia32': {
options: { archive: 'dist/desktop/KeeWeb.win.ia32.zip' },
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.win.ia32.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-win32-ia32', src: '**', expand: true }]
},
'linux-x64': {
options: { archive: 'dist/desktop/KeeWeb.linux.x64.zip' },
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.linux.x64.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-linux-x64', src: '**', expand: true }]
},
'linux-ia32': {
options: { archive: 'dist/desktop/KeeWeb.linux.ia32.zip' },
options: { archive: `dist/desktop/KeeWeb-${pkg.version}.linux.ia32.zip` },
files: [{ cwd: 'tmp/desktop/KeeWeb-linux-ia32', src: '**', expand: true }]
}
},
@ -383,12 +386,11 @@ module.exports = function(grunt) {
]
},
app: {
dest: 'dist/desktop/KeeWeb.mac.dmg'
dest: `dist/desktop/KeeWeb-${pkg.version}.mac.dmg`
}
},
nsis: {
options: {
installScript: 'package/nsis/main.nsi',
vars: {
version: pkg.version,
rev: function() { return grunt.config.get('gitinfo.local.branch.current.shortSHA'); },
@ -397,15 +399,31 @@ module.exports = function(grunt) {
},
'win32-x64': {
options: {
installScript: 'package/nsis/main.nsi',
arch: 'x64',
output: 'tmp/desktop/KeeWeb.win.x64.exe'
}
},
'win32-un-x64': {
options: {
installScript: 'package/nsis/main-un.nsi',
arch: 'x64',
output: 'tmp/desktop/KeeWeb-win32-x64/uninst.exe'
}
},
'win32-ia32': {
options: {
installScript: 'package/nsis/main.nsi',
arch: 'ia32',
output: 'tmp/desktop/KeeWeb.win.ia32.exe'
}
},
'win32-un-ia32': {
options: {
installScript: 'package/nsis/main-un.nsi',
arch: 'ia32',
output: 'tmp/desktop/KeeWeb-win32-ia32/uninst.exe'
}
}
},
deb: {
@ -423,7 +441,7 @@ module.exports = function(grunt) {
info: {
arch: 'amd64',
targetDir: 'dist/desktop',
pkgName: 'KeeWeb.linux.x64.deb',
pkgName: `KeeWeb-${pkg.version}.linux.x64.deb`,
appName: 'KeeWeb',
depends: 'libappindicator1',
scripts: {
@ -488,16 +506,54 @@ module.exports = function(grunt) {
keytarPasswordService: 'code-sign-win32-keeweb',
keytarPasswordAccount: 'code-sign-win32-keeweb'
},
'win32-build-x64': {
options: {
files: {
'tmp/desktop/KeeWeb-win32-x64/KeeWeb.exe': 'KeeWeb',
'tmp/desktop/KeeWeb-win32-x64/ffmpeg.dll': '',
'tmp/desktop/KeeWeb-win32-x64/libEGL.dll': 'ANGLE libEGL Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-x64/libGLESv2.dll': 'ANGLE libGLESv2 Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-x64/node.dll': 'Node.js'
}
}
},
'win32-build-ia32': {
options: {
files: {
'tmp/desktop/KeeWeb-win32-ia32/KeeWeb.exe': 'KeeWeb',
'tmp/desktop/KeeWeb-win32-ia32/ffmpeg.dll': '',
'tmp/desktop/KeeWeb-win32-ia32/libEGL.dll': 'ANGLE libEGL Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-ia32/libGLESv2.dll': 'ANGLE libGLESv2 Dynamic Link Library',
'tmp/desktop/KeeWeb-win32-ia32/node.dll': 'Node.js'
}
}
},
'win32-uninst-x64': {
options: {
files: {
'tmp/desktop/KeeWeb-win32-x64/uninst.exe': 'KeeWeb Uninstaller'
}
}
},
'win32-uninst-ia32': {
options: {
files: {
'tmp/desktop/KeeWeb-win32-ia32/uninst.exe': 'KeeWeb Uninstaller'
}
}
},
'win32-installer-x64': {
options: {
file: 'tmp/desktop/KeeWeb.win.x64.exe',
name: 'KeeWeb Setup'
files: {
'tmp/desktop/KeeWeb.win.x64.exe': 'KeeWeb Setup'
}
}
},
'win32-installer-ia32': {
options: {
file: 'tmp/desktop/KeeWeb.win.ia32.exe',
name: 'KeeWeb Setup'
files: {
'tmp/desktop/KeeWeb.win.ia32.exe': 'KeeWeb Setup'
}
}
}
},
@ -547,6 +603,8 @@ module.exports = function(grunt) {
grunt.registerTask('build-desktop-executables', [
'electron',
'sign-exe:win32-build-x64',
'sign-exe:win32-build-ia32',
'copy:desktop-windows-helper-ia32',
'copy:desktop-windows-helper-x64'
]);
@ -563,11 +621,16 @@ module.exports = function(grunt) {
]);
grunt.registerTask('build-desktop-dist-win32', [
'nsis:win32-un-x64',
'nsis:win32-un-ia32',
'sign-exe:win32-uninst-x64',
'sign-exe:win32-uninst-ia32',
'nsis:win32-x64',
'nsis:win32-ia32',
'sign-exe:win32-installer-x64',
'sign-exe:win32-installer-ia32',
'copy:desktop-win32-dist'
'copy:desktop-win32-dist-x64',
'copy:desktop-win32-dist-ia32'
]);
grunt.registerTask('build-desktop-dist-linux', [

View File

@ -12,11 +12,14 @@ module.exports = function (grunt) {
if (typeof value === 'function') {
value = value();
}
if (value) {
args.push(`${prefix}D${key}=${value}`);
}
});
args.push(`${prefix}Darch=${opt.arch}`);
args.push(`${prefix}Doutput=${opt.output}`);
args.push(`${prefix}NOCD`);
args.push(`${prefix}V2`);
args.push(opt.installScript);
let executable = win ? 'C:\\Program Files (x86)\\NSIS\\makensis.exe' : 'makensis';
grunt.log.writeln('Running NSIS:', args.join(' '));

View File

@ -2,6 +2,8 @@
// https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Signing_an_executable_with_Authenticode
const fs = require('fs');
module.exports = function (grunt) {
grunt.registerMultiTask('sign-exe', 'Signs exe file with authenticode certificate', function () {
const keytar = require('keytar');
@ -11,30 +13,44 @@ module.exports = function (grunt) {
if (!password) {
return grunt.warn('Code sign password not found');
}
let spawned = grunt.util.spawn({
cmd: 'signcode',
args: [
let promises = Object.keys(opt.files).map(file => signFile(file, opt.files[file], opt, password));
Promise.all(promises).then(done);
});
function signFile(file, name, opt, password) {
let signedFile = file + '.sign';
return new Promise((resolve, reject) => {
let args = [
'-spc', opt.spc,
'-v', opt.pvk,
'-a', opt.algo,
'-$', 'commercial',
'-n', opt.name,
'-key', require('path').resolve(opt.pvk),
'-h', opt.algo,
'-n', name,
'-i', opt.url,
'-t', 'http://timestamp.verisign.com/scripts/timstamp.dll',
'-tr', 10,
opt.file
]
'-pass', password,
'-in', file,
'-out', signedFile
];
let spawned = grunt.util.spawn({
cmd: 'osslsigncode',
args: args
}, (error, result, code) => {
if (error || code) {
spawned.kill();
return grunt.warn(`signtool error ${code}: ${error}`);
grunt.warn(`Cannot sign file ${file}, signtool error ${code}: ${error}`);
return reject();
}
done();
if (fs.existsSync(file)) {
fs.renameSync(signedFile, file);
}
grunt.log.writeln(`Signed: ${file}: ${name}`);
resolve();
});
spawned.stdout.pipe(process.stdout);
// spawned.stdout.pipe(process.stdout);
spawned.stderr.pipe(process.stderr);
spawned.stdin.setEncoding('utf-8');
spawned.stdin.write(password);
spawned.stdin.write('\n');
// spawned.stdin.setEncoding('utf-8');
// spawned.stdin.write(password);
// spawned.stdin.write('\n');
});
}
};

4
package/nsis/check-running.nsh Normal file → Executable file
View File

@ -4,11 +4,11 @@
Pop $0
${If} $0 != 0
DetailPrint "Error checking ${PRODUCT_EXE}: $0"
MessageBox MB_ICONSTOP|MB_OK "Failed to check whether process is running"
MessageBox MB_ICONSTOP|MB_OK "Failed to check whether process is running" /SD IDOK
Quit
${EndIf}
Pop $1
${StrContains} $0 "${PRODUCT_EXE}" $1
${StrStr} $0 $1 "${PRODUCT_EXE}"
${If} $0 == ""
DetailPrint "${PRODUCT_EXE} is not running"
${ExitDo}

View File

@ -1,5 +0,0 @@
Name "${PRODUCT_NAME}"
OutFile "${output}"
InstallDir "$PROGRAMFILES\KeeWeb"
ShowInstDetails show
ShowUnInstDetails show

8
package/nsis/defines.nsh Normal file → Executable file
View File

@ -5,14 +5,18 @@
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_EXE "KeeWeb.exe"
!define PRODUCT_UNINST_TEMP_EXE "KeeWebUninst.exe"
!define MUI_ABORTWARNING
!define MUI_ICON "graphics\icon.ico"
!define MUI_UNICON "graphics\icon.ico"
!define MUI_FINISHPAGE_RUN "$INSTDIR\KeeWeb.exe"
!define MUI_FINISHPAGE_RUN "$INSTDIR\${PRODUCT_EXE}"
!define MULTIUSER_EXECUTIONLEVEL Highest
!define MULTIUSER_MUI
!define MULTIUSER_INSTALLMODE_COMMANDLINE
SetCompressor lzma
Name "${PRODUCT_NAME}"
OutFile "${output}"
InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
ShowInstDetails show

2
package/nsis/includes.nsh Normal file → Executable file
View File

@ -4,7 +4,7 @@
!include x64.nsh
!include nsDialogs.nsh
!include LogicLib.nsh
!include StrFunc.nsh
!include WinVer.nsh
!include package\nsis\lib\FileAssoc.nsh
!include package\nsis\lib\StrContains.nsh

27
package/nsis/install.nsh Normal file → Executable file
View File

@ -1,8 +1,16 @@
!insertmacro MUI_PAGE_WELCOME
#!insertmacro MULTIUSER_PAGE_INSTALLMODE
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_LANGUAGE "English"
Function .onInit
${If} ${RunningX64}
${If} ${arch} == "x64"
SetRegView 64
StrCpy $InstDir "$PROGRAMFILES64\KeeWeb"
StrCpy $InstDir "$PROGRAMFILES64\${PRODUCT_NAME}"
${Else}
MessageBox MB_ICONSTOP|MB_OK "Please use 64-bit installer on 64-bit system"
Quit
@ -32,9 +40,12 @@ FunctionEnd
Section "MainSection" SEC01
!insertmacro EnsureAppIsNotRunning
SetOverwrite on
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString"
${If} $R0 != ""
ExecWait '$R0 /S _?=$INSTDIR'
CopyFiles "$R0" "$TEMP\${PRODUCT_UNINST_TEMP_EXE}"
ExecWait '"$TEMP\${PRODUCT_UNINST_TEMP_EXE}" /S'
${EndIf}
ReadRegStr $R0 "HKCU" "${PRODUCT_UNINST_KEY}" "QuietUninstallString"
@ -48,24 +59,24 @@ Section "MainSection" SEC01
${EndIf}
SetOutPath "$INSTDIR"
SetOverwrite ifnewer
SetOverwrite on
File /r "tmp\desktop\KeeWeb-win32-${arch}\*"
CreateDirectory "$SMPROGRAMS\KeeWeb"
CreateShortCut "$SMPROGRAMS\KeeWeb\KeeWeb.lnk" "$INSTDIR\KeeWeb.exe"
CreateShortCut "$DESKTOP\KeeWeb.lnk" "$INSTDIR\KeeWeb.exe"
CreateShortCut "$SMPROGRAMS\KeeWeb\KeeWeb.lnk" "$INSTDIR\${PRODUCT_EXE}"
CreateShortCut "$DESKTOP\KeeWeb.lnk" "$INSTDIR\${PRODUCT_EXE}"
!insertmacro APP_ASSOCIATE "kdbx" "kdbxfile" "KeePass Password Database" \
"$INSTDIR\KeeWeb.exe,0" "Open with KeeWeb" "$INSTDIR\KeeWeb.exe $\"%1$\""
"$INSTDIR\${PRODUCT_EXE},0" "Open with KeeWeb" "$INSTDIR\${PRODUCT_EXE} $\"%1$\""
!insertmacro UPDATEFILEASSOC
SectionEnd
Section -Post
WriteUninstaller "$INSTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" '"$INSTDIR\uninst.exe"'
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "QuietUninstallString" '"$INSTDIR\uninst.exe" /S'
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\KeeWeb.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallDir" "$INSTDIR"
SectionEnd

0
package/nsis/lib/FileAssoc.nsh Normal file → Executable file
View File

View File

@ -1,50 +0,0 @@
# http://nsis.sourceforge.net/StrContains
; StrContains
; This function does a case sensitive searches for an occurrence of a substring in a string.
; It returns the substring if it is found.
; Otherwise it returns null("").
; Written by kenglish_hi
; Adapted from StrReplace written by dandaman32
Var STR_HAYSTACK
Var STR_NEEDLE
Var STR_CONTAINS_VAR_1
Var STR_CONTAINS_VAR_2
Var STR_CONTAINS_VAR_3
Var STR_CONTAINS_VAR_4
Var STR_RETURN_VAR
Function StrContains
Exch $STR_NEEDLE
Exch 1
Exch $STR_HAYSTACK
; Uncomment to debug
;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK '
StrCpy $STR_RETURN_VAR ""
StrCpy $STR_CONTAINS_VAR_1 -1
StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE
StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK
loop:
IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1
StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1
StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found
StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done
Goto loop
found:
StrCpy $STR_RETURN_VAR $STR_NEEDLE
Goto done
done:
Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the
Exch $STR_RETURN_VAR
FunctionEnd
!macro _StrContainsConstructor OUT NEEDLE HAYSTACK
Push `${HAYSTACK}`
Push `${NEEDLE}`
Call StrContains
Pop `${OUT}`
!macroend
!define StrContains '!insertmacro "_StrContainsConstructor"'

4
package/nsis/main-un.nsi Executable file
View File

@ -0,0 +1,4 @@
!include package\nsis\defines.nsh
!include package\nsis\includes.nsh
!include package\nsis\check-running.nsh
!include package\nsis\uninstall.nsh

3
package/nsis/main.nsi Normal file → Executable file
View File

@ -1,7 +1,4 @@
!include package\nsis\defines.nsh
!include package\nsis\includes.nsh
!include package\nsis\mui.nsh
!include package\nsis\config.nsh
!include package\nsis\check-running.nsh
!include package\nsis\install.nsh
!include package\nsis\uninstall.nsh

View File

@ -1,9 +0,0 @@
!insertmacro MUI_PAGE_WELCOME
#!insertmacro MULTIUSER_PAGE_INSTALLMODE
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"

63
package/nsis/uninstall.nsh Normal file → Executable file
View File

@ -1,29 +1,78 @@
Function un.onInit
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Function .onInit
${If} ${RunningX64}
SetRegView 64
StrCpy $InstDir "$PROGRAMFILES64\${PRODUCT_NAME}"
${EndIf}
!insertmacro MULTIUSER_INIT
${StrStr} $0 "$EXEPATH" "${PRODUCT_UNINST_TEMP_EXE}"
${If} $0 == ""
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Remove $(^Name) from your computer?" /SD IDYES IDYES yes
Abort
yes:
${If} ${RunningX64}
SetRegView 64
!insertmacro EnsureAppIsNotRunning
SetOverwrite on
CopyFiles "$EXEPATH" "$TEMP\${PRODUCT_UNINST_TEMP_EXE}"
${If} ${Silent}
Exec '"$TEMP\${PRODUCT_UNINST_TEMP_EXE}" /S'
${Else}
Exec '"$TEMP\${PRODUCT_UNINST_TEMP_EXE}"'
${EndIf}
Quit
${EndIf}
!insertmacro MULTIUSER_UNINIT
FunctionEnd
Function un.onUninstSuccess
Function .onInstSuccess
HideWindow
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer." /SD IDOK
FunctionEnd
Section Uninstall
Section "MainSection" SEC01
!insertmacro EnsureAppIsNotRunning
DetailPrint "Removing desktop shortcut"
Delete "$DESKTOP\KeeWeb.lnk"
DetailPrint "Removing menu shortcut"
Delete "$SMPROGRAMS\KeeWeb\KeeWeb.lnk"
DetailPrint "Removing menu items"
RMDir "$SMPROGRAMS\KeeWeb"
RMDir /r "$INSTDIR"
ReadRegStr $R0 ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallDir"
${If} $R0 == ""
DetailPrint "InstallDir key is absent"
Abort
${EndIf}
StrCpy $InstDir "$R0"
ClearErrors
DetailPrint "Removing app files from $InstDir"
Var /GLOBAL deleteRetry
${ForEach} $deleteRetry 1 3 + 1
RMDir /r "$InstDir"
${If} ${Errors}
ClearErrors
DetailPrint "Error removing files, retrying in a second"
Sleep 1000
${Else}
${ExitFor}
${EndIf}
${Next}
DetailPrint "Deleting registry keys"
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
DetailPrint "Unregistering file associations"
!insertmacro APP_UNASSOCIATE "kdbx" "kdbxfile"
DetailPrint "Updating file associations"
!insertmacro UPDATEFILEASSOC
DetailPrint "Done"
SetAutoClose true
SectionEnd