Skip to content
Snippets Groups Projects
Commit 9666f8bd authored by jkito's avatar jkito :skull:
Browse files

[installer] add post-install.go to replace post-install.py

the python script needed python to be installed on the user's machine
to be able to successfully install

this is changed to use a statically compiled go binary for performing
the post-install tasks

fixes #775
parent 98005eb8
No related branches found
No related tags found
1 merge request!178[installer] add post-install.go to replace post-install.py
......@@ -196,9 +196,7 @@ ifeq (${PLATFORM}, darwin)
@cp "${TEMPLATES}/osx/bitmask.pf.conf" ${INST_DATA}helper/bitmask.pf.conf
@cp "${TEMPLATES}/osx/client.up.sh" ${INST_DATA}/
@cp "${TEMPLATES}/osx/client.down.sh" ${INST_DATA}/
@cp "${TEMPLATES}/qtinstaller/osx-data/post-install.py" ${INST_ROOT}/
@cp "${TEMPLATES}/qtinstaller/osx-data/uninstall.py" ${INST_ROOT}/
@cp "${TEMPLATES}/qtinstaller/osx-data/se.leap.bitmask-helper.plist" ${INST_DATA}
@go build -ldflags='-w -s' -o "${INST_ROOT}/post-install" "${TEMPLATES}/qtinstaller/osx-data/post-install.go"
@[ -f $(OPENVPN_BIN) ] && echo "OpenVPN already built at" $(OPENVPN_BIN) || ./branding/thirdparty/openvpn/build_openvpn.sh
@cp $(OPENVPN_BIN) ${INST_DATA}/openvpn.leap
@cp build/bin/${PLATFORM}/bitmask-helper ${INST_DATA}/
......
package main
import (
"bytes"
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"text/template"
)
/* Outline
* runs as root and setup the bitmask-helper privileged helper on macOS
* needs to perform the following steps:
* 1. check if running as root
* 2. setup the plist file with the correct path to bitmask-helper
* 3. install plist file in location
* 4. while doing the above make sure that existing helper is not running and removed
*/
const (
plistTemplate = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>WorkingDirectory</key>
<string>{{ .Path }}</string>
<key>StandardOutPath</key>
<string>{{ .Path }}/helper/bitmask-helper.log</string>
<key>StandardErrorPath</key>
<string>{{ .Path }}/helper/bitmask-helper-err.log</string>
<key>GroupName</key>
<string>daemon</string>
<key>RunAtLoad</key>
<true/>
<key>SessionCreate</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>ThrottleInterval</key>
<integer>5</integer>
<key>Label</key>
<string>se.leap.BitmaskHelper</string>
<key>Program</key>
<string>{{ .Path }}/bitmask-helper</string>
</dict>
</plist>`
plistPath = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
helperName = "bitmask-helper"
launchdDaemonLabel = "se.leap.BitmaskHelper"
// -action flag values
actionPostInstall = "post-install"
actionUninstall = "uninstall"
// -stage flag values
stagePre = "preinstall"
stageUninstall = "uninstall"
)
var (
curdir = func() string {
execPath, err := os.Executable()
if err != nil {
log.Printf("error getting executable path: %v", err)
return ""
}
return filepath.Dir(execPath)
}()
appBundlePath = func() string {
names, err := filepath.Glob(filepath.Join(curdir, "*VPN.app"))
if err != nil {
log.Printf("error finding .app bundle path: %v", err)
return ""
}
if len(names) >= 1 {
return names[0]
}
return ""
}()
// flags
installerAction string
installerStage string
)
func init() {
const (
action = "action"
stage = "stage"
)
var usageAction = fmt.Sprintf("the installer actions: %s", strings.Join([]string{actionPostInstall, actionUninstall}, ","))
var usageStage = fmt.Sprintf("the installer action stage: preinstall, uninstall")
flag.StringVar(&installerAction, action, "", usageAction)
flag.StringVar(&installerStage, stage, stageUninstall, usageStage)
flag.Parse()
}
func main() {
if os.Getuid() != 0 {
log.Fatal("not running as root")
}
switch installerAction {
case actionPostInstall:
if err := setupLogFile(filepath.Join(curdir, "post-install.log")); err != nil {
log.Fatal(err)
}
log.Println("running action: post-install")
if appBundlePath == "" {
log.Fatal("could not find path to .app bundle")
}
err := postInstall()
if err != nil {
log.Fatal(err)
}
case actionUninstall:
log.Println("running action: uninstall")
uninstall(installerStage)
default:
log.Fatal("unknown command supplied: %s", installerAction)
}
}
func setupLogFile(logFile string) error {
f, err := os.Create(logFile)
if err != nil {
return err
}
w := io.MultiWriter(os.Stdout, f)
log.SetOutput(w)
return nil
}
func postInstall() error {
if isHelperRunning() {
if err := unloadHelperPlist(); err != nil {
log.Println(err)
}
}
log.Println("Changing ownership of 'bitmask-helper'")
// change ownership of bitmask-helper to root
if err := os.Chown(filepath.Join(appBundlePath, helperName), 0, 0); err != nil {
log.Println("error while changing ownership of 'bitmask-helper': ", err)
}
// copy launchd plist file to target location /Library/LaunchDaemons
log.Println("Generate plist file for helper launchd daemon")
plist, err := generatePlist()
if err != nil {
return err
}
log.Println(plist)
log.Println("Writing plist content to file")
fout, err := os.OpenFile(plistPath, os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
return err
}
if n, err := io.WriteString(fout, plist); n < len(plist) || err != nil {
return fmt.Errorf("failed writing the plist file: %s: %v", fout.Name(), err)
}
// load the plist file onto launchd
log.Println("Loading plist file")
if err := loadHelperPlist(plistPath); err != nil {
log.Printf("error while loading launchd daemon: %s: %v\n", plistPath, err)
}
// change ownership of 'helper' dir
log.Println("Changing ownership of 'helper' dir")
if err := os.Chown(filepath.Join(appBundlePath, "helper"), 0, 0); err != nil {
log.Println("error while changing ownership of dir 'helper': ", err)
}
return nil
}
func uninstall(stage string) {
switch stage {
case stagePre, stageUninstall:
if err := setupLogFile(filepath.Join("/tmp", fmt.Sprintf("bitmask-%s.log", stage))); err != nil {
log.Fatal(err)
}
if appBundlePath == "" {
log.Fatal("could not find path to .app bundle")
}
default:
log.Fatal("unknow stage for uninstall: ", stage)
}
if isHelperRunning() {
if err := unloadHelperPlist(); err != nil {
log.Println("error while unloading launchd daemon: ", err)
}
}
if err := os.Remove(plistPath); err != nil {
log.Println("error while removing helper plist: ", err)
}
}
func isHelperRunning() bool {
cmd := exec.Command("ps", "-ceAo", "command")
out, err := cmd.Output()
if err != nil {
log.Println(err)
return false
}
processes := strings.Split(string(out), "\n")
for _, proc := range processes {
if strings.TrimSpace(proc) == "bitmask-helper" {
return true
}
}
return false
}
func loadHelperPlist(plistPath string) error {
cmd := exec.Command("launchctl", "load", plistPath)
_, err := cmd.Output()
if err != nil {
return err
}
return nil
}
func unloadHelperPlist() error {
cmd := exec.Command("launchctl", "unload", plistPath)
_, err := cmd.Output()
if err != nil {
return err
}
cmd = exec.Command("launchctl", "remove", launchdDaemonLabel)
_, _ = cmd.Output()
cmd = exec.Command("pkill", "-9", helperName)
_, err = cmd.Output()
return err
}
func generatePlist() (string, error) {
appPath := struct {
Path string
}{
Path: appBundlePath,
}
t, err := template.New("plist").Parse(plistTemplate)
if err != nil {
return "", err
}
plistContent := &bytes.Buffer{}
err = t.Execute(plistContent, appPath)
if err != nil {
return "", err
}
return plistContent.String(), nil
}
......@@ -143,7 +143,7 @@ function uninstallOSX() {
// TODO use installer filepath??
component.addElevatedOperation(
"Execute", "{0}",
"@TargetDir@/uninstall.py", "pre",
"@TargetDir@/post-install", "-action=uninstall", "-stage=preinstall",
"errormessage=There was an error during the pre-installation script, things might be broken. Please report this error and attach /tmp/bitmask-uninstall.log"
);
}
......@@ -152,10 +152,10 @@ function postInstallOSX() {
console.log("Post-installation for OSX");
component.addElevatedOperation(
"Execute", "{0}",
"@TargetDir@/post-install.py",
"@TargetDir@/post-install", "-action=post-install",
"errormessage=There was an error during the post-installation script, things might be broken. Please report this error and attach the post-install.log file.",
"UNDOEXECUTE",
"@TargetDir@/uninstall.py"
"@TargetDir@/post-install", "-action=uninstall"
);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment