From c8cadd8bec1350b28c0042a18055eb2c7db096c6 Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Fri, 24 Apr 2020 20:38:49 +0200 Subject: [pkg] two-stage build for windows to allow signed uninstaller --- Makefile | 13 ++++--- branding/scripts/provider.py | 2 +- branding/templates/makefile/Makefile | 18 ++++++--- branding/templates/windows/template.nsi | 34 +++++++++-------- docker/Makefile | 67 ++++++++++++++++++++++++++++++++- docker/builder.sh | 13 ++++++- pkg/helper/windows.go | 2 - 7 files changed, 117 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 709bdb1..7f12624 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ ######################################################################### # Multiplatform build and packaging recipes for BitmaskVPN -# (c) LEAP Encryption Access Project, 2019 +# (c) LEAP Encryption Access Project, 2019-2020 ######################################################################### .PHONY: all get build build_bitmaskd icon locales generate_locales clean @@ -150,8 +150,8 @@ TGZ_NAME = bitmask-vpn_${VERSION}-src TGZ_PATH = $(shell pwd)/build/${TGZ_NAME} tgz: @mkdir -p $(TGZ_PATH) - @git archive HEAD | tar -x -C $(TGZ_PATH) - @cd build/ && tar cvzf bitmask-vpn_$(VERSION).tgz ${TGZ_NAME} + git archive HEAD | tar -x -C $(TGZ_PATH) + @cd build/ && tar czf bitmask-vpn_$(VERSION).tgz ${TGZ_NAME} @rm -rf $(TGZ_PATH) gen_pkg_win: @@ -209,8 +209,11 @@ package_snap: package_deb: @make -C build/${PROVIDER} pkg_deb -package_win: - @make -C build/${PROVIDER} pkg_win +package_win_stage_1: + @make -C build/${PROVIDER} pkg_win_stage_1 + +package_win_stage_2: + @make -C build/${PROVIDER} pkg_win_stage_2 package_osx: @make -C build/${PROVIDER} pkg_osx diff --git a/branding/scripts/provider.py b/branding/scripts/provider.py index 7455556..b1beab9 100644 --- a/branding/scripts/provider.py +++ b/branding/scripts/provider.py @@ -5,7 +5,7 @@ import os def getDefaultProvider(config): provider = os.environ.get('PROVIDER') if provider: - print('[+] Got provider {} from environemnt'.format(provider)) + print('[+] Got provider {} from environment'.format(provider)) else: print('[+] Using default provider from config file') provider = config['default']['provider'] diff --git a/branding/templates/makefile/Makefile b/branding/templates/makefile/Makefile index 5994e19..c042d27 100755 --- a/branding/templates/makefile/Makefile +++ b/branding/templates/makefile/Makefile @@ -34,11 +34,19 @@ pkg_win: staging\openvpn\openvpn.exe copy ..\bin\bitmask-helper staging\bitmask_helper.exe "C:\Program Files (x86)\NSIS\makensis.exe" windows/$(APPNAME)-installer.nsi else -pkg_win: staging/openvpn/openvpn.exe - echo "[+] building windows" +pkg_win_stage_1: staging/openvpn/openvpn.exe + echo "[+] building windows [stage1]" + cp ../bin/windows/bitmask-vpn staging/bitmask-vpn.exe + cp ../bin/windows/bitmask-helper-go staging/helper.exe + touch windows/uninstall.exe + makensis -DUNINSTALLER windows/$(APPNAME)-installer.nsi + mv dist/produce-bitmask-uninstaller.exe ../../deploy/ + +pkg_win_stage_2: staging/openvpn/openvpn.exe + echo "[+] building windows [stage2]" cp ../bin/windows/bitmask-vpn staging/bitmask-vpn.exe - #cp ../bin/windows/bitmask-helper staging/bitmask_helper.exe cp ../bin/windows/bitmask-helper-go staging/helper.exe + cp ../windows/staging/uninstall-signed.exe windows/uninstall.exe makensis windows/$(APPNAME)-installer.nsi mv dist/$(APPNAME)-$(VERSION).exe ../../deploy/ endif @@ -117,10 +125,10 @@ staging\openvpn\openvpn.exe: copy .\staging\openvpn\openvpn.exe .\staging copy .\staging\openvpn\*.dll .\staging staging/openvpn/openvpn.exe: - mkdir -p staging/openvpn + @mkdir -p staging/openvpn wget https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe -O $(STAGING)/openvpn/tap-windows.exe wget https://downloads.leap.se/thirdparty/windows/openvpn-x86_64-w64-mingw32.tar.bz2 -O $(STAGING)/openvpn/openvpn.tar.bz2 - tar xvjf $(STAGING)/openvpn/openvpn.tar.bz2 -C $(STAGING)/openvpn/ + @tar xjf $(STAGING)/openvpn/openvpn.tar.bz2 -C $(STAGING)/openvpn/ cp $(STAGING)/openvpn/bin/openvpn.exe $(STAGING)/openvpn cp $(STAGING)/openvpn/bin/*.dll $(STAGING) cp $(STAGING)/openvpn/lib/engines-1_1/*.dll $(STAGING) diff --git a/branding/templates/windows/template.nsi b/branding/templates/windows/template.nsi index e3b2379..6fa189b 100755 --- a/branding/templates/windows/template.nsi +++ b/branding/templates/windows/template.nsi @@ -2,10 +2,10 @@ !echo "Stage 1: building uninstaller" ; we don't care about this installer, in this step we just pick the uninstaller ; to be able to sign it. - OutFile "$%TEMP%\tempinstaller.exe" - SetCompressor off + OutFile "..\dist\produce-bitmask-uninstaller.exe" + SetCompress off !else - !echo "Stage 2: building installer" + !echo "Stage 2: building main installer" Outfile "..\dist\$applicationName-$version.exe" SetCompressor /SOLID lzma !endif @@ -59,7 +59,6 @@ Section "InstallFiles" DetailPrint "Trying to uninstall any older helper..." ClearErrors Delete 'C:\Program Files\$applicationName\bitmask_helper.exe' - IfErrors 0 noErrorHelper DetailPrint "Trying to uninstall new helper..." ClearErrors @@ -67,14 +66,14 @@ Section "InstallFiles" ExecWait '"$INSTDIR\helper.exe" remove' ClearErrors Delete 'C:\Program Files\$applicationName\helper.exe' - IfErrors 0 noErrorHelper + ;IfErrors 0 noErrorHelper ; uninstalling old nssm helper - could fail if it isn't there, or if nssm is not there... ClearErrors DetailPrint "Trying to uninstall an old style helper..." ExecWait '"$INSTDIR\nssm.exe" stop $applicationNameLower-helper' ExecWait '"$INSTDIR\nssm.exe" remove $applicationNameLower-helper confirm' - IfErrors 0 noErrorHelper + ;IfErrors 0 noErrorHelper DetailPrint "Failed to stop nssm-style helper, maybe it was not there" ; let's try to stop it in case it's the new style helper -- we need to do it to be able to overwrite it. @@ -82,16 +81,10 @@ Section "InstallFiles" ClearErrors DetailPrint "Trying to uninstall a new style helper..." ExecWait '"$INSTDIR\bitmask_helper.exe" stop' - IfErrors 0 noErrorHelper + ;IfErrors 0 noErrorHelper DetailPrint "Failed to stop new-style helper, maybe it was not there" - ClearErrors - DetailPrint "Trying to uninstall a new style helper..." - ExecWait '"$INSTDIR\helper.exe" stop' - IfErrors 0 noErrorHelper - DetailPrint "Failed to stop new-style helper, maybe it was not there" - - noErrorHelper: + ;noErrorHelper: ; now we try to delete the systray, locked by the app - just to know if another instance of FoobarVPN is running. ClearErrors @@ -105,9 +98,7 @@ Section "InstallFiles" noDelError: - ; TODO -- write uninstaller in a separate stage, so we can sign it! SetOutPath $INSTDIR - WriteUninstaller $INSTDIR\uninstall.exe ; Add ourselves to Add/remove programs WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$applicationNameLower" "DisplayName" "$applicationName" @@ -125,6 +116,7 @@ Section "InstallFiles" createShortCut "$SMPROGRAMS\$applicationName\$applicationName.lnk" "$INSTDIR\bitmask-vpn.exe" "" "$INSTDIR\icon.ico" File "readme.txt" + File "uninstall.exe" File "/oname=icon.ico" "..\assets\icon.ico" $extra_install_files @@ -156,6 +148,8 @@ Section /o "TAP Virtual Ethernet Adapter" SecTAP DetailPrint "TAP installed!" SectionEnd +!ifdef UNINSTALLER +; this section should not be in the main installer, because it will cause warnings. Section "Uninstall" ; we uninstall the new-style go helper ExecWait '"$INSTDIR\bitmask_helper.exe" stop' @@ -180,9 +174,17 @@ Section "Uninstall" Delete $INSTDIR\uninstall.exe RMDir $INSTDIR SectionEnd +!endif Function .onInit +!ifdef UNINSTALLER + ; If UNINSTALLER is defined, then we don't do anything execpt write out the uninstaller. + SetSilent silent + WriteUninstaller "c:\bitmask-uninstall.exe" + Quit ; bail out quickly when running the UNINSTALLER stage. +!else !insertmacro SelectByParameter ${SecTAP} SELECT_TAP 1 +!endif FunctionEnd ;---------------------------------------- diff --git a/docker/Makefile b/docker/Makefile index 80ca9dd..ac674cb 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -1,23 +1,86 @@ +######################################################################### +# Docker build environment for BitmaskVPN +# (c) LEAP Encryption Access Project, 2019-2020 +######################################################################### + IMAGE=bitmask-vpn REGISTRY=registry.0xacab.org/leap/docker +PROVIDER=riseup +PRODUCT=$(shell echo $(PROVIDER) | sed -e "s/\b\(.\)/\u\1/g")VPN + +UNINSTALLER_NSIS="../deploy/produce-bitmask-uninstaller.exe" +UNINSTALLER_WINE=".wine/drive_c/bitmask-uninstall.exe" +UNINSTALLER_STAGING="../build/windows/staging/uninstall.exe" +UNINSTALLER_SIGNED="../build/windows/staging/uninstall-signed.exe" +SIGNCODE=osslsigncode +SECRETS="leap/secrets/windoze" + build: mkdir -p mods && cp ../go.mod ../go.sum mods/ && cp -r ../packages mods/ docker build -t $(REGISTRY)/$(IMAGE):latest . +deps: + sudo apt install osslsigncode push: docker push $(REGISTRY)/$(IMAGE):latest prune: docker system prune login: docker login $(REGISTRY) -package_win: + +package_win: clean_win package_win_stage_1 sign_win_uninstaller_in_host package_win_stage_2 sign_win_installer_in_host + +clean_win: + @rm ../deploy/*.exe + +package_win_stage_1: docker run \ + -e PROVIDER=$(PROVIDER) \ -e XBUILD=win \ - -e PROVIDER=riseup \ + -e STAGE=1 \ -v `python3 -c 'import os; print(os.path.abspath(".."))'`:/bitmask-vpn.host \ --cpus="4" \ -it --rm \ $(REGISTRY)/$(IMAGE):latest \ /builder.sh + +sign_win_uninstaller_in_host: + @rm -f $(UNINSTALLER_STAGING) + @rm -f $(UNINSTALLER_WINE) + @echo "[+] running nsis uninstaller under wine..." + @wine $(UNINSTALLER_NSIS) || echo "[+] wine finished (it exits badly)" + @cp ~/$(UNINSTALLER_WINE) $(UNINSTALLER_STAGING) && echo "[+] copied uninstaller to staging dir:" $(UNINSTALLER_STAGING) + @$(SIGNCODE) sign \ + -certs ~/$(SECRETS)/win.crt \ + -key ~/$(SECRETS)/key.pem \ + -pass `gpg --decrypt ~/$(SECRETS)/../windoze.gpg` \ + -n "$(PRODUCT) Uninstaller" -i "https://leap.se/" \ + -in $(UNINSTALLER_STAGING) \ + -out $(UNINSTALLER_SIGNED) + @echo "[+] signed uninstaller in:" $(UNINSTALLER_SIGNED) + +package_win_stage_2: + docker run \ + -e PROVIDER=$(PROVIDER) \ + -e XBUILD=win \ + -e STAGE=2 \ + -v `python3 -c 'import os; print(os.path.abspath(".."))'`:/bitmask-vpn.host \ + --cpus="4" \ + -it --rm \ + $(REGISTRY)/$(IMAGE):latest \ + /builder.sh + +sign_win_installer_in_host: + $(eval INSTALLER := $(shell ls -tr ../deploy/$(PRODUCT)*.exe | tail -n 1)) + $(eval INSTALLER_SIGNED := $(shell echo $(INSTALLER) | sed 's/\.exe/-signed.exe/')) + @$(SIGNCODE) sign \ + -certs ~/$(SECRETS)/win.crt \ + -key ~/$(SECRETS)/key.pem \ + -pass `gpg --decrypt ~/$(SECRETS)/../windoze.gpg` \ + -n "$(PRODUCT) Installer" -i "https://leap.se/" \ + -in $(INSTALLER) \ + -out ../deploy/$(INSTALLER_SIGNED) + @echo "[+] signed installer in:" $(INSTALLER_SIGNED) + shell: docker run -v `python3 -c 'import os; print(os.path.abspath(".."))'`:/bitmask-vpn.host -it --rm $(REGISTRY)/$(IMAGE):latest /bin/bash diff --git a/docker/builder.sh b/docker/builder.sh index 2767d61..a7a2a40 100755 --- a/docker/builder.sh +++ b/docker/builder.sh @@ -10,7 +10,18 @@ make prepare make build case $XBUILD in win) - make package_win + if [ "$STAGE" = "1" ]; then + echo "" + echo "[+] Bulding WIN installer >>>>>>>>>>> STAGE 1" + make package_win_stage_1 + echo "" + fi + if [ "$STAGE" = "2" ]; then + echo "" + echo "[+] Building WIN installer >>>>>>>>>> STAGE 2" + make package_win_stage_2 + echo "" + fi ;; osx) make package_osx diff --git a/pkg/helper/windows.go b/pkg/helper/windows.go index 2872702..5eef863 100644 --- a/pkg/helper/windows.go +++ b/pkg/helper/windows.go @@ -82,8 +82,6 @@ func parseCliArgs() { runService(svcName, true) return case "install": - // TODO get binary name -- or maybe not, since in this way we make sure - // that all bitmask-vpn brandings are mutually exclusive. err = installService(svcName, "bitmask-helper service") case "remove": err = removeService(svcName) -- cgit v1.2.3