Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • m1ghtfr3e/bitmask-vpn
  • leap/bitmask-vpn
  • meskio/bitmask-vpn
  • kali/bitmask-vpn
  • nsheep/bitmask-vpn
  • nilesh/bitmask-vpn
  • micah/bitmask-vpn
  • kwadronaut/bitmask-vpn
  • th/bitmask-vpn
  • wxl/bitmask-vpn
  • Nowa-Ammerlaan/bitmask-vpn
  • elijah/bitmask-vpn
  • happysalada/bitmask-vpn
  • JUZZZEE/bitmask-vpn
  • jkito/bitmask-vpn
  • panetone/bitmask-vpn
  • hsilva/bitmask-vpn
  • S0b0tkaZ11gy/bitmask-vpn
  • polster/bitmask-vpn-pahoeohe
  • Kulibin/bitmask-vpn
  • TheMimoGz/bitmask-vpn
  • fifi/bitmask-vpn
  • fly/bitmask-vpn
  • VlKozlove/bitmask-vpn
  • DonMephedrone/bitmask-vpn
  • Arti/bitmask-vpn
  • annxxxxx/bitmask-vpn
  • Arti/arti-bitmask-vpn-fork
  • peanut2/bitmask-vpn
29 results
Show changes
Showing
with 1190 additions and 372 deletions
......@@ -4,9 +4,11 @@
<Version>$VERSION</Version>
<Title>$APPNAME Installer ($VERSION)</Title>
<Publisher>LEAP Encryption Access Project</Publisher>
<ProductUrl>https://leap.se</ProductUrl>
<AllowNonAsciiCharacters>false</AllowNonAsciiCharacters>
<Logo>installer-logo.png</Logo>
<InstallerApplicationIcon>installer-icon</InstallerApplicationIcon>
<ControlScript>script.qs</ControlScript>
<!--
<RemoteRepositories>
......
function Controller()
{
console.log("Controller script called")
}
Controller.prototype.ComponentSelectionPageCallback = function()
{
gui.clickButton(buttons.NextButton);
}
Controller.prototype.ReadyForInstallationPageCallback = function() {
console.log("Control script being called")
try {
var page = gui.pageWidgetByObjectName("DynamicInstallForAllUsersCheckBoxForm");
if(page) {
console.log("Control script being called")
var choice = page.installForAllCheckBox.checked ? "true" : "false";
installer.setValue("installForAllUsers", choice);
}
} catch(e) {
console.log(e);
}
}
\ No newline at end of file
!defined(INSTALLER, var):INSTALLER= "BitmaskVPN-Installer-git"
!defined(INSTALLER, var):INSTALLER= "Bitmask-Installer-git"
!defined(TARGET, var):TARGET= "bitmask-vpn"
TEMPLATE = aux
CONFIG -= debug_and_release
......@@ -8,29 +9,15 @@ inst.output = $$INSTALLER
inst.commands = binarycreator --ignore-translations -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT}
inst.CONFIG += target_predeps no_link combine
QMAKE_TARGET_BUNDLE_PREFIX = se.leap
QMAKE_BUNDLE = $$TARGET
QMAKE_EXTRA_COMPILERS += inst
OTHER_FILES += \
# watch out... it chokes with dashes in the path
packages/riseupvpn/meta/package.xml \
packages/riseupvpn/meta/install.js \
packages/riseupvpn/data/README.txt \
# OTHER_FILES += \
macx {
OTHER_FILES += "packages/riseupvpn/data/riseup-vpn.app"
OTHER_FILES += "packages/riseupvpn/data/bitmask-helper"
OTHER_FILES += "packages/riseupvpn/data/installer.py"
OTHER_FILES += "packages/riseupvpn/data/se.leap.bitmask-helper.plist"
OTHER_FILES += "packages/riseupvpn/data/openvpn.leap"
OTHER_FILES += "packages/riseupvpn/data/helper/bitmask.pf.conf"
OTHER_FILES += "packages/riseupvpn/data/client.up.sh"
OTHER_FILES += "packages/riseupvpn/data/client.down.sh"
}
linux {
OTHER_FILES += "packages/riseupvpn/data/riseup-vpn"
OTHER_FILES += "packages/riseupvpn/data/bitmask-helper"
}
win32{
OTHER_FILES += "packages/riseupvpn/data/riseup-vpn.exe"
OTHER_FILES += "packages/riseupvpn/data/helper.exe"
}
package main
import (
"bytes"
"errors"
"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>{{ .Label }}</string>
<key>ProgramArguments</key>
<array>
<string>{{ .Path }}/bitmask-helper</string>
<string>-socket-uid</string>
<string>{{.Uid}}</string>
<string>-socket-gid</string>
<string>{{.Gid}}</string>
</array>
</dict>
</plist>`
helperName = "bitmask-helper"
// -action flag values
actionPostInstall = "post-install"
actionUninstall = "uninstall"
// -stage flag values
stagePre = "preinstall"
stageUninstall = "uninstall"
// listening socket flag values
socketUid = "socket-uid"
socketGid = "socket-gid"
)
var (
curdir = func() string {
execPath, err := os.Executable()
if err != nil {
log.Printf("error getting executable path: %v", err)
return ""
}
return filepath.Dir(execPath)
}()
// flags
installerAction string
installerStage string
appName string
plistPath string
launchdDaemonLabel string
uid int
gid int
)
func init() {
const (
action = "action"
stage = "stage"
appname = "appname"
)
var usageAction = fmt.Sprintf("the installer actions: %s", strings.Join([]string{actionPostInstall, actionUninstall}, ","))
var usageStage = "the installer action stage: preinstall, uninstall"
var usageAppName = "name of the application being installed this is used to form the app bundle name by appending .app to it"
flag.StringVar(&installerAction, action, "", usageAction)
flag.StringVar(&installerStage, stage, stageUninstall, usageStage)
flag.StringVar(&appName, appname, "", usageAppName)
flag.IntVar(&uid, socketUid, 0, "Helper unix socket UID")
flag.IntVar(&gid, socketGid, 0, "Helper unix socket GID")
flag.Parse()
}
func main() {
if os.Getuid() != 0 {
log.Fatal("not running as root")
}
if appName == "" || installerAction == "" {
log.Fatal("-action and -appname flags cannot be empty")
}
plistPath = fmt.Sprintf("/Library/LaunchDaemons/se.leap.helper.%s.plist", appName)
launchdDaemonLabel = fmt.Sprintf("se.leap.Helper.%s", appName)
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.Fatalf("unknown command supplied: %s", installerAction)
}
}
func appBundlePath() string {
path := filepath.Join(curdir, appName+".app")
_, err := os.Stat(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
log.Printf("unable to find the app bundle path: %v", err)
return ""
}
}
return path
}
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
Label string
Uid int
Gid int
}{
Path: appBundlePath(),
Label: launchdDaemonLabel,
Uid: uid,
Gid: gid,
}
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
}
#!/usr/bin/env python
# Post installation script for BitmaskVPN.
# Please note that this installation will install ONE single helper with administrative privileges.
# This means that, for the time being, you can only install ONE of the BitmaskVPN derivatives at the same time.
# This might change in the future.
import os
import shutil
import sys
import subprocess
HELPER = "bitmask-helper"
HELPER_PLIST = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
_dir = os.path.dirname(os.path.realpath(__file__))
def main():
log = open(os.path.join(_dir, 'post-install.log'), 'w')
log.write('Checking for admin privileges...\n')
_id = os.getuid()
if _id != 0:
err = "error: need to run as root. UID: %s\n" % str(_id)
logErr(log, err)
# failure: sys.exit(1)
if isHelperRunning():
log.write("Trying to stop bitmask-helper...\n")
# if this fail, we can check if the HELPER_PLIST is there
ok = unloadHelper()
log.write("success: %s \n" % str(ok))
ok = fixHelperOwner(log)
log.write("chown helper: %s \n" % str(ok))
log.write("Copy launch daemon...\n")
copyLaunchDaemon()
log.write("Trying to launch helper...\n")
out = launchHelper()
log.write("result: %s \n" % str(out))
grantPermissionsOnLogFolder()
# all done
log.write('post-install script: done\n')
sys.exit(0)
def logErr(log, msg):
log.write(msg)
sys.exit(1)
def isHelperRunning():
ps = _getProcessList()
return HELPER in ps
def unloadHelper():
out = subprocess.call(["launchctl", "unload", HELPER_PLIST])
out2 = subprocess.call(["pkill", "-9", "bitmask-helper"]) # just in case
return out == 0
def fixHelperOwner(log):
path = os.path.join(_dir, HELPER)
try:
os.chown(path, 0, 0)
except OSError as exc:
log.write(str(exc))
return False
return True
def copyLaunchDaemon():
plist = "se.leap.bitmask-helper.plist"
path = os.path.join(_dir, plist)
_p = _dir.replace("/", "\/")
subprocess.call(["sed", "-i.back", "s/PATH/%s/" % _p, path])
shutil.copy(path, HELPER_PLIST)
def launchHelper():
out = subprocess.call(["launchctl", "load", HELPER_PLIST])
return out == 0
def grantPermissionsOnLogFolder():
helperDir = os.path.join(_dir, 'helper')
try:
os.makedirs(helperDir)
except Exception:
pass
os.chown(helperDir, 0, 0)
def _getProcessList():
_out = []
output = subprocess.Popen(["ps", "-ceA"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = output.communicate()
for line in stdout.split('\n'):
cmd = line.split(' ')[-1]
_out.append(cmd.strip())
return _out
if __name__ == "__main__":
main()
<?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>
#!/usr/bin/env python
# Uninstall script for BitmaskVPN.
import os
import shutil
import sys
import subprocess
HELPER = "bitmask-helper"
HELPER_PLIST = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
_dir = os.path.dirname(os.path.realpath(__file__))
def main():
log = open(os.path.join('/tmp', 'bitmask-uninstall.log'), 'w')
log.write('Checking for admin privileges...\n')
_id = os.getuid()
log.write("UID: %s\n" % str(_id))
if int(_id) != 0:
err = "error: need to run as root. UID: %s\n" % str(_id)
logErr(log, err)
# failure: sys.exit(1)
log.write('Checking if helper is running')
if isHelperRunning():
log.write("Trying to stop bitmask-helper...\n")
# if this fail, we can check if the HELPER_PLIST is there
ok = unloadHelper()
log.write("success: %s \n" % str(ok))
log.write("Removing LaunchDaemon")
out = removeLaunchDaemon()
log.write("result: %s \n" % str(out))
# all done
log.write('uninstall script: done\n')
sys.exit(0)
def logErr(log, msg):
log.write(msg)
sys.exit(1)
def isHelperRunning():
ps = _getProcessList()
return HELPER in ps
def unloadHelper():
out = subprocess.call(["launchctl", "unload", HELPER_PLIST])
out2 = subprocess.call(["pkill", "-9", "bitmask-helper"]) # just in case
return out == 0
def removeLaunchDaemon():
return subprocess.call(["rm", "-f", HELPER_PLIST])
def _getProcessList():
_out = []
output = subprocess.Popen(["ps", "-ceA"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = output.communicate()
for line in stdout.split('\n'):
cmd = line.split(' ')[-1]
_out.append(cmd.strip())
return _out
if __name__ == "__main__":
main()
......@@ -9,6 +9,15 @@ function majorVersion(str)
return parseInt(str.split(".", 1));
}
// from: https://forum.qt.io/topic/114975/qt-installerframework-is-altering-my-string-slashes
var Dir = new function () {
this.toNativeSeparator = function (path) {
if (installer.value("os") == "win")
return path.replace(/\//g, '\\');
return path;
}
};
function cancelInstaller(message)
{
installer.setDefaultPageVisible(QInstaller.Introduction, false);
......@@ -24,12 +33,31 @@ function cancelInstaller(message)
}
function Component() {
// Check whether OS is supported.
// start installer with -v to see debug output
if (systemInfo.productType === "macos") {
var uid = installer.execute("/usr/bin/id", ["-u"])[0]
var gid = installer.execute("/usr/bin/id", ["-g"])[0]
installer.setValue("HelperSocketUid", uid.trim())
installer.setValue("HelperSocketGid", gid.trim())
console.log("UID: " + uid)
console.log("GID: " + gid)
}
installer.gainAdminRights();
console.log("OS: " + systemInfo.productType);
console.log("Kernel: " + systemInfo.kernelType + "/" + systemInfo.kernelVersion);
installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
if (installer.isInstaller()) {
console.log("Checking for existing installation")
component.loaded.connect(this, Component.prototype.installerLoaded);
}
// Check whether OS is supported.
// start installer with -v to see debug output
var validOs = false;
if (systemInfo.kernelType === "winnt") {
......@@ -54,10 +82,19 @@ function Component() {
}
console.log("CPU Architecture: " + systemInfo.currentCpuArchitecture);
if (systemInfo.productType === "windows") {
installer.addWizardPage(component, "InstallForAllUsersCheckBoxForm", QInstaller.LicenseCheck);
}
}
Component.prototype.createOperations = function ()
{
if (systemInfo.productType === "macos") {
preInstallOSX();
}
if (systemInfo.productType === "windows") {
preInstallWindows();
}
// This will actually install the files
component.createOperations();
......@@ -67,55 +104,122 @@ Component.prototype.createOperations = function ()
// We can also use this to register different components (different architecture for instance)
// See https://doc.qt.io/qtinstallerframework/qt-installer-framework-systeminfo-packages-root-meta-installscript-qs.html
console.log("installForAllUsers value: " + installer.value("installForAllUsers"));
if (systemInfo.productType === "windows") {
postInstallWindows();
} else if (systemInfo.productType === "osx") {
if (installer.value("installForAllUsers") === "true") {
installForAllUsersWindows()
}
} else if (systemInfo.productType === "macos") {
uninstallOSX();
postInstallOSX();
} else {
postInstallLinux();
}
}
Component.prototype.installationFinished = function()
{
console.log("DEBUG: running installationFinished");
if (installer.isInstaller() && installer.status == QInstaller.Success) {
var argList = ["-a", "@TargetDir@/$APPNAME.app"];
try {
installer.execute("touch", ["/tmp/install-finished"]);
installer.execute("open", argList);
} catch(e) {
console.log(e);
Component.prototype.installerLoaded = function () {
var dir = installer.value("TargetDir")
var maintenancetoolPath = Dir.toNativeSeparator(dir + "/uninstall.exe")
if (systemInfo.productType == "macos") {
maintenancetoolPath = Dir.toNativeSeparator(dir + "/uninstall.app" + "/Contents/MacOS/uninstall")
}
if (installer.fileExists(dir) && installer.fileExists(maintenancetoolPath)) {
console.log("Found existing installation at: " + dir)
var result = QMessageBox.warning("uninstallprevious.critical", "Uninstall previous version", "To proceed existing installation needs to be removed. Click OK to remove existing installation.",
QMessageBox.Ok | QMessageBox.Cancel);
if (result == QMessageBox.Ok) {
console.log("Running uninstall using maintenance tool at: " + maintenancetoolPath)
installer.execute(maintenancetoolPath, ["purge", "-c"]);
}
if (result == QMessageBox.Cancel) {
cancelInstaller("Need to removed existing installation to proceed.");
}
}
}
function preInstallWindows() {
console.log("Pre-installation for Windows: check for running bitmask");
component.addOperation(
"Execute", "{1}", "powershell", "-NonInteractive", "-NoProfile", "-command", "try {Get-Process $BINNAME -ErrorAction Stop} catch { exit 1}",
"errormessage=It seems that an old $APPNAME client is running. Please exit the app and run this installer again.",
);
/* Remove-Service only introduced in PS 6.0 */
component.addElevatedOperation(
"Execute", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
"try {Get-Service bitmask-helper-v2} catch {exit 0}; try {Stop-Service bitmask-helper-v2} catch {}; try {$$srv = Get-Service bitmask-helper-v2; if ($$srv.Status -eq 'Running') {exit 1} else {exit 0};} catch {exit 0}",
"errormessage=It seems that bitmask-helper-v2 service is running, and we could not stop it. Please manually uninstall any previous $APPNAME client and run this installer again.",
);
}
function postInstallWindows() {
console.log("Installing OpenVPN tap driver");
component.addElevatedOperation("Execute", "@TargetDir@/tap-windows.exe", "/S", "/SELECT_UTILITIES=1"); /* TODO uninstall? */
console.log("Now trying to install our helper");
component.addElevatedOperation("Execute", "@TargetDir@/helper.exe", "install", "UNDOEXECUTE", "@TargetDir@/helper.exe", "remove");
component.addElevatedOperation("Execute", "@TargetDir@/helper.exe", "start", "UNDOEXECUTE", "@TargetDir@/helper.exe", "stop");
console.log("Adding shortcut entries/...");
// TODO - we probably need to package different flavors of the installer for windows 8, arm, i386 etc, and change the installer we ship too.
var openVpnMsi = Dir.toNativeSeparator(installer.value("TargetDir") + "/openvpn-installer.msi")
console.log("Installing OpenVPN binaries and service");
component.addElevatedOperation("Execute", "{0}", "msiexec", "/i", openVpnMsi, "ADDLOCAL=OpenVPN.Service,OpenVPN,Drivers,Drivers.TAPWindows6,Drivers.Wintun", "/passive")
console.log("Adding shortcut entries...");
component.addElevatedOperation("Mkdir", "@StartMenuDir@");
component.addElevatedOperation("CreateShortcut", "@TargetDir@/$BINNAME.exe", "@StartMenuDir@/$APPNAME.lnk", "workingDirectory=@TargetDir@", "iconPath=@TargetDir@/icon.ico", "description=Start $APPNAME");
component.addElevatedOperation("CreateShortcut", "@TargetDir@\\$BINNAME.exe", "@StartMenuDir@\\$APPNAME.lnk", "workingDirectory=@TargetDir@", "iconPath=@TargetDir@\\icon.ico", "description=Start $APPNAME");
// TODO I think this one is not being created because the path doesn't exist yet. We might want to do this by hooking on the installation finished signal instead.
component.addElevatedOperation(
"CreateShortcut",
"@TargetDir@/Uninstall-$APPNAME.exe",
"@StartMenuDir@/Uninstall.lnk"
"@TargetDir@\\Uninstall-$APPNAME.exe",
"@StartMenuDir@\\Uninstall.lnk"
);
}
function installForAllUsersWindows() {
component.addElevatedOperation(
"Execute", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
"try {New-LocalGroup -Name 'OpenVPN Administrators' -Description 'Group to allow use of openvpn' -ErrorAction Stop} catch [Microsoft.PowerShell.Commands.GroupExistsException] { exit 0 }",
"errormessage=Unable to create the 'OpenVPN Administrators' group.",
"UNDOEXECUTE", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
"try { Remove-LocalGroup -Name 'OpenVPN Administrators' -ErrorAction Stop } catch [Microsoft.PowerShell.Commands.GroupNotFoundException] { exit 0 }",
"errormessage=Unable to remove the 'OpenVPN Administrator' group."
);
component.addElevatedOperation(
"Execute", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
"$$users=(Get-LocalUser | Select-Object Name | where {$$_.Name -NotMatch 'Administrator' -and $$_.Name -NotMatch 'Guest' -and $$_.Name -NotMatch 'DefaultAccount' -and $$_.Name -NotMatch 'WDAGUtilityAccount'}); try {Add-LocalGroupMember -Group 'OpenVPN Administrators' -Member $$users -ErrorAction Stop} catch [Microsoft.PowerShell.Commands.MemberExistsException] {exit 0}",
"errormessage=Unable to add users to the 'OpenVPN Administrators' group."
);
}
function preInstallOSX() {
console.log("Pre-installation for OSX: check for running bitmask");
component.addOperation(
"Execute", "{1}", "pgrep", "bitmask-vpn$$", /* $$$$ is escaped by python template: the old app binary was called bitmask-vpn */
"errormessage=It seems that an old RiseupVPN client is running. Please exit the app and run this installer again.",
);
component.addOperation(
"Execute", "{1}", "pgrep", "bitmask$$", /* $$$$ is escaped by python template: we don't want to catch bitmask app */
"errormessage=It seems RiseupVPN, CalyxVPN or LibraryVPN are running. Please exit the app and run this installer again.",
"UNDOEXECUTE", "{1}", "pgrep", "bitmask$$", /* $$$$ is escaped: we dont want bitmask app */
"errormessage=It seems RiseupVPN, CalyxVPN or LibraryVPN are running. Please exit the app before trying to run the uninstaller again."
);
}
function uninstallOSX() {
console.log("Pre-installation for OSX: uninstall previous helpers");
// TODO use installer filepath??
component.addElevatedOperation(
"Execute", "{0}",
"@TargetDir@/post-install", "-action=uninstall", "-stage=preinstall", "-appname=@ProductName@",
"errormessage=There was an error during the pre-installation script, things might be broken. Please report this error and attach /tmp/bitmask-uninstall.log"
);
}
function postInstallOSX() {
var uid = installer.value("HelperSocketUid")
var gid = installer.value("HelperSocketGid")
console.log("Post-installation for OSX");
component.addElevatedOperation(
"Execute", "{0}",
"@TargetDir@/post-install.py",
"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.",
"Execute", "{0}",
"@TargetDir@/post-install", "-action=post-install", "-appname=@ProductName@", "-socket-uid=" + uid, "-socket-gid=" + gid,
"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", "-appname=@ProductName@"
);
}
......@@ -124,3 +228,12 @@ function postInstallLinux() {
console.log("Maybe you want to use your package manager instead?");
component.addOperation("AppendFile", "/tmp/bitmask-installer.log", "this is a test - written from the installer");
}
function uninstallWindows() {
console.log("uninstall for windows: remove openvpn administrators group")
component.addElevatedOperation(
"Execute", "{0}", "powershell", "-NonInteractive", "-NoProfile", "-command",
"Remove-LocalGroup -Name 'OpenVPN Administrator' -ErrorAction Ignore",
);
}
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>InstallForAllUsersCheckBoxForm</class>
<widget class="QWidget" name="InstallForAllUsersCheckBoxForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>412</width>
<height>179</height>
</rect>
</property>
<property name="windowTitle">
<string>Select Installation Mode</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>10</number>
</property>
<item>
<widget class="QCheckBox" name="installForAllCheckBox">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Install for All Users on this Computer</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="allUsersLabel">
<property name="text">
<string>The application will be installed for all users on this machine. All users will be added to the OpenVPN Administrators group to enable interaction with OpenVPN.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="indent">
<number>25</number>
</property>
</widget>
</item>
</layout>
</widget>
<resources />
<connections />
</ui>
\ No newline at end of file
......@@ -7,5 +7,11 @@
<Default>false</Default>
<RequiresAdminRights>true</RequiresAdminRights>
<Script>install.js</Script>
<Licenses>
<License name="License Agreement" file="LICENSE.txt" />
</Licenses>
<ForcedInstallation>true</ForcedInstallation>
<UserInterfaces>
<UserInterface>installforallcheckbox.ui</UserInterface>
</UserInterfaces>
</Package>
......@@ -6,11 +6,11 @@
# by the script at "snap/pre/pack_installers"
import subprocess
import os
from base64 import decodestring as decode
from base64 import decodebytes as decode
POLKIT = b'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBvbGljeWNv\nbmZpZyBQVUJMSUMKICItLy9mcmVlZGVza3RvcC8vRFREIFBvbGljeUtpdCBQb2xpY3kgQ29uZmln\ndXJhdGlvbiAxLjAvL0VOIgogImh0dHA6Ly93d3cuZnJlZWRlc2t0b3Aub3JnL3N0YW5kYXJkcy9Q\nb2xpY3lLaXQvMS9wb2xpY3ljb25maWcuZHRkIj4KPHBvbGljeWNvbmZpZz4KCiAgPHZlbmRvcj5M\nRUFQIFByb2plY3Q8L3ZlbmRvcj4KICA8dmVuZG9yX3VybD5odHRwOi8vbGVhcC5zZS88L3ZlbmRv\ncl91cmw+CgogIDxhY3Rpb24gaWQ9InNlLmxlYXAuYml0bWFzay5yaXNldXB2cG4ucG9saWN5Ij4K\nICAgIDxkZXNjcmlwdGlvbj5SdW5zIGJpdG1hc2sgaGVscGVyIHRvIGxhdW5jaCBmaXJld2FsbCBh\nbmQgb3BlbnZwbiAoUmlzZXVwVlBOKTwvZGVzY3JpcHRpb24+CiAgICA8ZGVzY3JpcHRpb24geG1s\nOmxhbmc9ImVzIj5FamVjdXRhIGVsIGFzaXN0ZW50ZSBkZSBiaXRtYXNrIHBhcmEgbGFuemFyIGVs\nIGZpcmV3YWxsIHkgb3BlbnZwbiAoUmlzZXVwVlBOKTwvZGVzY3JpcHRpb24+CiAgICA8bWVzc2Fn\nZT5SaXNldXBWUE4gbmVlZHMgdGhhdCB5b3UgYXV0aGVudGljYXRlIHRvIHN0YXJ0PC9tZXNzYWdl\nPgogICAgPG1lc3NhZ2UgeG1sOmxhbmc9ImVzIj5SaXNldXBWUE4gbmVjZXNpdGEgYXV0b3JpemFj\naW9uIHBhcmEgY29tZW56YXI8L21lc3NhZ2U+CiAgICA8aWNvbl9uYW1lPnBhY2thZ2UteC1nZW5l\ncmljPC9pY29uX25hbWU+IAogICAgPGRlZmF1bHRzPgogICAgICA8YWxsb3dfYW55PnllczwvYWxs\nb3dfYW55PgogICAgICA8YWxsb3dfaW5hY3RpdmU+eWVzPC9hbGxvd19pbmFjdGl2ZT4KICAgICAg\nPGFsbG93X2FjdGl2ZT55ZXM8L2FsbG93X2FjdGl2ZT4KICAgIDwvZGVmYXVsdHM+CiAgICA8YW5u\nb3RhdGUga2V5PSJvcmcuZnJlZWRlc2t0b3AucG9saWN5a2l0LmV4ZWMucGF0aCI+L3NuYXAvYmlu\nL3Jpc2V1cC12cG4uYml0bWFzay1yb290PC9hbm5vdGF0ZT4KICA8L2FjdGlvbj4KPC9wb2xpY3lj\nb25maWc+Cg==\n'
with open('/usr/share/polkit-1/actions/se.leap.bitmask.riseupvpn.policy', 'w') as polkit:
with open('/usr/share/polkit-1/actions/se.leap.bitmask.riseup-vpn.policy', 'w') as polkit:
lines = decode(POLKIT).split(b"\n")
for line in lines:
polkit.write(line.decode() + "\n")
......
#!/bin/sh
echo "Executing remove hook for RiseupVPN"
rm "/usr/share/polkit-1/actions/se.leap.bitmask.riseupvpn.policy"
rm "/usr/share/polkit-1/actions/se.leap.bitmask.riseup-vpn.policy"
unlink "/usr/share/applications/riseup-vpn.desktop" || echo "did not remove workaround for global desktop entry"
echo "done"
#!/usr/bin/env python3
import os
import subprocess
from base64 import encodestring as encode
from base64 import encodebytes as encode
HELPDIR = '../../../../../helpers'
INSTALL = '../../hooks/install'
......@@ -21,7 +21,7 @@ with open(INSTALL, 'w') as install:
install.write('# by the script at "snap/local/pre/pack_installers"\n')
install.write('import subprocess\n')
install.write('import os\n')
install.write('from base64 import decodestring as decode\n')
install.write('from base64 import decodebytes as decode\n')
install.write("""
POLKIT = {polkit}
......
......@@ -8,17 +8,21 @@ description: |
grade: stable
confinement: classic
icon: snap/gui/icon.svg
base: core20
base: core22
compression: lzo
parts:
architectures:
- build-on: amd64
- build-on: i386
parts:
bitmask-root:
plugin: dump
source: helpers
source: pkg
source-type: local
override-prime: |
mkdir -p bin
cp $SNAPCRAFT_PART_SRC/bitmask-root bin/
cp $SNAPCRAFT_PART_SRC/pickle/helpers/bitmask-root bin/
chmod +x bin/bitmask-root
openvpn:
......@@ -30,8 +34,12 @@ parts:
bitmask-vpn:
plugin: nil
build-attributes:
- enable-patchelf
source: .
source-type: local
build-environment:
- QMAKE: qmake6
stage:
- bin/${binaryName}
override-build: |
......@@ -39,90 +47,193 @@ parts:
# Maybe we just need to put the providers.json in the VENDOR_PATH
# and pass it to gui/providers from some path that snap can access.
# Same for the vendor.qrc
update-alternatives --install /usr/bin/gofmt gofmt /usr/lib/go-1.21/bin/gofmt 0
update-alternatives --install /usr/bin/go go /usr/lib/go-1.21/bin/go 0
ln -s $(qmake6 -query "QT_INSTALL_BINS")/lrelease /usr/local/bin/lrelease
mkdir -p $SNAPCRAFT_PART_INSTALL/snap/
mkdir -p $SNAPCRAFT_PRIME/snap/
echo ${version} > $SNAPCRAFT_PRIME/snap/version.txt
make build_golib
QT_SELECT=5 XBUILD=no TARGET=${binaryName} make build_gui
make vendor
make build
mkdir -p $SNAPCRAFT_PART_INSTALL/bin
mv build/qt/release/${binaryName} $SNAPCRAFT_PART_INSTALL/bin/
override-prime: |
rm -rf $SNAPCRAFT_PROJECT_DIR/snap/hooks/.mypy_cache
snapcraftctl prime
build-packages:
- pkg-config
- g++
- golang
- golang-1.21-go
- git
- make
- qt5-qmake
- qttools5-dev-tools
- qtdeclarative5-dev
stage-packages: # for some reason they're not picked from here - duplicating in desktop-qt5.
- libqt5qml5
- libqt5quick5
- qml-module-qtquick-controls
- qml-module-qtquick-dialogs
- qml-module-qtquick-extras
- qml-module-qt-labs-qmlmodels
- qml-module-qt-labs-platform
after: [desktop-qt5]
desktop-qt5:
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
source-subdir: qt
plugin: make
make-parameters: ["FLAVOR=qt5"]
build-packages:
- build-essential
- qtbase5-dev
- dpkg-dev
- qt6-tools-dev-tools
- qt6-tools-dev
- qml-module-qtquick-controls2
- libqt6qml6
- libqt6svg6-dev
- qt6-l10n-tools
- qt6-base-dev
- qt6-base-dev-tools
- qt6-declarative-dev
- qt6-declarative-dev-tools
- libgl1-mesa-dev
- libqt6core5compat6-dev
- libglu1-mesa-dev
- libqt6opengl6-dev
stage-packages:
- qml6-module-qtquick
- qml6-module-qt5compat-graphicaleffects
- qml6-module-qtquick-controls
- qml6-module-qtquick-dialogs
- qml6-module-qtquick-layouts
- qml6-module-qtqml-workerscript
- qml6-module-qtquick-templates
- qml6-module-qtquick-window
- qml6-module-qt-labs-platform
- qml6-module-qtcore
- qt6-wayland
- libopengl0
- libqt6core6
- libqt6dbus6
- libqt6gui6
- libqt6network6
- libqt6qml6
- libqt6widgets6
- libb2-1
- libdouble-conversion3
- libgomp1
- libmd4c0
- libpcre2-16-0
- libproxy1v5
- libxkbcommon0
- ttf-ubuntu-font-family
- dmz-cursor-theme
- light-themes
- adwaita-icon-theme
- gnome-themes-standard
- shared-mime-info
- locales-all
- xdg-user-dirs
- fcitx-frontend-qt5
- libxcb1
- libqt5gui5
# gsettings, pixbuf and immodules are not needed by all snaps,
# but they are so common a requirement include them here
gsettings+pixbuf+immodules:
plugin: nil
build-packages:
- libgdk-pixbuf2.0-0
- libqt5svg5
- libqt5qml5
- libqt5quick5
- qml-module-qtquick2
- qml-module-qtquick-controls
- qml-module-qtquick-dialogs
- qml-module-qtquick-extras
- qml-module-qt-labs-platform
- qml-module-qt-labs-qmlmodels
- try: [appmenu-qt5] # not available on core18
- librsvg2-common
- shared-mime-info
- libgtk-3-0
override-build: |
craftctl default
# Update mime database
update-mime-database ${CRAFT_PART_INSTALL}/usr/share/mime
# build immodules cache
mkdir -p ${CRAFT_PART_INSTALL}/usr/lib/${CRAFT_ARCH_TRIPLET}/gtk-3.0/3.0.0/
/usr/lib/${CRAFT_ARCH_TRIPLET}/libgtk-3-0/gtk-query-immodules-3.0 > ${CRAFT_PART_INSTALL}/usr/lib/${CRAFT_ARCH_TRIPLET}/gtk-3.0/3.0.0/immodules.cache
stage-packages:
- librsvg2-common
- gsettings-desktop-schemas
- libglib2.0-bin
override-prime: |
craftctl default
# Compile the gsettings schemas
/usr/lib/${CRAFT_ARCH_TRIPLET}/glib-2.0/glib-compile-schemas "$CRAFT_PRIME/usr/share/glib-2.0/schemas"
# Index the pixbuf loaders
LOADERS_PATH=$(echo ${CRAFT_PRIME}/usr/lib/${CRAFT_ARCH_TRIPLET}/gdk-pixbuf-2.0/*/loaders)
QUERY_LOADERS=/usr/lib/${CRAFT_ARCH_TRIPLET}/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders
GDK_PIXBUF_MODULEDIR=${LOADERS_PATH} ${QUERY_LOADERS} > ${LOADERS_PATH}/../loaders.cache
sed s!$CRAFT_PRIME!!g --in-place ${LOADERS_PATH}/../loaders.cache
setup:
plugin: dump
source: https://github.com/canonical/iot-example-graphical-snap.git
source-subdir: wayland-launch
override-build: |
# The plugs needed to run Wayland. (wayland-launch checks them, setup.sh connects them)
# You may add further plugs here if you want these options
PLUGS="opengl wayland graphics-core22"
sed --in-place "s/%PLUGS%/$PLUGS/g" $CRAFT_PART_BUILD/wayland-launch/bin/wayland-launch
sed --in-place "s/%PLUGS%/$PLUGS/g" $CRAFT_PART_BUILD/wayland-launch/bin/setup.sh
craftctl default
stage-packages:
- inotify-tools
apps:
graphics-core22:
after:
# Your application packaging
- gsettings+pixbuf+immodules
- setup
- bitmask-vpn
source: https://github.com/MirServer/graphics-core22.git
plugin: dump
override-prime: |
craftctl default
${CRAFT_PART_SRC}/bin/graphics-core22-cleanup mesa-core22 nvidia-core22
cd "$CRAFT_PRIME/usr/share/"
rm -rf bug drirc.d glvnd libdrm lintian man
rm -rf applications apport bash-completion dbus-1 doc-base doc gtk-doc\
help pkgconfig libthai metainfo themes thumbnailers xml
prime:
- bin/graphics-core22-wrapper
apps:
bitmask-root:
command: bin/bitmask-root
openvpn:
command: usr/sbin/openvpn
environment:
LD_LIBRARY_PATH: &library-path
$SNAP/lib:$SNAP/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/usr/lib:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET
launcher:
command: bin/${binaryName}
environment:
QT_PLUGIN_PATH: &path
$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/qml
LD_LIBRARY_PATH:
$SNAP/lib:$SNAP/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/usr/lib:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET:$LD_LIBRARY_PATH
QML2_IMPORT_PATH:
$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/qml
# debug -------------
#QT_DEBUG_PLUGINS: 1
SNAP_DESKTOP_DEBUG: 1
# debug -------------
command-chain: &_command-chain
- bin/graphics-core22-wrapper
- bin/wayland-launch
command: &_command bin/${binaryName}
plugs: &_plugs
- opengl
- wayland
environment: &_environment
# These environment variables are typically needed by Qt applications to ensue the snapped version of
# Qt components are found and used
QT_QPA_PLATFORM: wayland
QT_PLUGIN_PATH: ${SNAP}/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/qt6/plugins/
QT_QPA_PLATFORM_PLUGIN_PATH: ${SNAP}/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/qt6/plugins/platforms/
QML2_IMPORT_PATH: ${SNAP}/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/qt6/qml
daemon:
daemon: simple
restart-delay: 3s
restart-condition: always
command-chain: *_command-chain
command: *_command
plugs: *_plugs
environment: *_environment
# This is one of four snippets that relate to providing the userspace graphics needed by your application.
# You can treat this as "magic" so long as you don't need to make changes.
# On the Mir website there's a lot more detail on [the graphics-core22 Snap interface](https://mir-server.io/docs/the-graphics-core22-snap-interface) and it's use.
plugs:
graphics-core22:
interface: content
target: $SNAP/graphics
default-provider: mesa-core22
environment:
# Other, generally useful environment settings...
# XDG config
XDG_CACHE_HOME: $SNAP_USER_COMMON/.cache
XDG_CONFIG_HOME: $SNAP_USER_DATA/.config
XDG_CONFIG_DIRS: $SNAP/etc/xdg
XDG_DATA_DIRS: $SNAP/usr/local/share:$SNAP/usr/share
# XKB config
XKB_CONFIG_ROOT: $SNAP/usr/share/X11/xkb
# The `layout` ensures that files can be found by applications where they are expected by the toolkit or application.
layout:
/usr/share/libdrm:
bind: $SNAP/graphics/libdrm
/usr/share/drirc.d:
symlink: $SNAP/graphics/drirc.d
# Other, generally useful paths
/usr/share/fonts:
bind: $SNAP/usr/share/fonts
/usr/share/icons:
bind: $SNAP/usr/share/icons
/usr/share/sounds:
bind: $SNAP/usr/share/sounds
/etc/fonts:
bind: $SNAP/etc/fonts
# GTK
/usr/lib/$CRAFT_ARCH_TRIPLET/gdk-pixbuf-2.0:
bind: $SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/gdk-pixbuf-2.0
/usr/lib/${CRAFT_ARCH_TRIPLET}/gtk-3.0:
bind: $SNAP/usr/lib/${CRAFT_ARCH_TRIPLET}/gtk-3.0
/usr/share/mime:
bind: $SNAP/usr/share/mime
/etc/gtk-3.0:
bind: $SNAP/etc/gtk-3.0
......@@ -4,18 +4,21 @@
# Builds OpenVPN statically against mbedtls (aka polarssl).
# Requirements: cmake
# Output: ~/openvpn_build/sbin/openvpn-x.y.z
# License: GPLv3 or later
#############################################################################
set -e
#set -x
# [!] This needs to be updated for every release --------------------------
OPENVPN="openvpn-2.4.9"
MBEDTLS="mbedtls-2.24.0"
OPENVPN="openvpn-2.6.6"
OPENSSL="3.2.1"
MBEDTLS="2.25.0"
LZO="lzo-2.10"
ZLIB="zlib-1.2.11"
MBEDTLS_SHA512="5437ea57eb8b8af9446a796876aa2bfe3c59c88f926b1638c7e8a021a8bef9f4bc6cb1b254e7387e2afe095bd27c518060719726bbaf5478582a56c34315cfb8"
ZLIB="zlib-1.3.1"
LZO_SHA1="4924676a9bae5db58ef129dc1cebce3baa3c4b5d"
OPENSSL_SHA256="83c7329fe52c850677d75e5d0b0ca245309b97e8ecbcfdc1dfdc4ab9fac35b39"
MBEDTLS_SHA256="f838f670f51070bc6b4ebf0c084affd9574652ded435b064969f36ce4e8b586d"
# -------------------------------------------------------------------------
platform='unknown'
......@@ -35,7 +38,7 @@ mkdir -p $SRC
SHASUM="/usr/bin/shasum"
ZLIB_KEYS="https://keys.gnupg.net/pks/lookup?op=get&search=0x783FCD8E58BCAFBA"
ZLIB_KEYS="https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x5ed46a6721d365587791e2aa783fcd8e58bcafba"
OPENVPN_KEYS="https://swupdate.openvpn.net/community/keys/security.key.asc"
WGET="wget --prefer-family=IPv4"
......@@ -54,8 +57,8 @@ MAKE="make -j4"
function build_zlib()
{
gpg --fetch-keys $ZLIB_KEYS
mkdir $SRC/zlib && cd $SRC/zlib
gpg --fetch-keys $ZLIB_KEYS
mkdir -p $SRC/zlib && cd $SRC/zlib
if [ ! -f $ZLIB.tar.gz ]; then
$WGET https://zlib.net/$ZLIB.tar.gz
......@@ -75,43 +78,15 @@ function build_zlib()
make install DESTDIR=$BASE
}
########### ##################################################################
# MBEDTLS # ##################################################################
########### ##################################################################
function build_mbedtls()
{
mkdir -p $SRC/polarssl && cd $SRC/polarssl
if [ ! -f $MBEDTLS.tar.gz ]; then
$WGET https://github.com/ARMmbed/mbedtls/archive/$MBEDTLS.tar.gz
fi
sha512=`${SHASUM} -a 512 ${MBEDTLS}.tar.gz | cut -d' ' -f 1`
if [ "${MBEDTLS_SHA512}" = "${sha512}" ]; then
echo "[+] sha-512 verified ok"
else
echo "[!] problem with sha-512 verification"
exit 1
fi
tar zxvf $MBEDTLS.tar.gz
cd mbedtls-$MBEDTLS
mkdir -p build
cd build
cmake ..
$MAKE
make install DESTDIR=$BASE/install
}
######## ####################################################################
# LZO2 # ####################################################################
######## ####################################################################
function build_lzo2()
{
mkdir $SRC/lzo2 && cd $SRC/lzo2
mkdir -p $SRC/lzo2 && cd $SRC/lzo2
if [ ! -f $LZO.tar.gz ]; then
$WGET http://www.oberhumer.com/opensource/lzo/download/$LZO.tar.gz
$WGET https://www.oberhumer.com/opensource/lzo/download/$LZO.tar.gz
fi
sha1=`$SHASUM $LZO.tar.gz | cut -d' ' -f 1`
if [ "${LZO_SHA1}" = "${sha1}" ]; then
......@@ -133,15 +108,94 @@ function build_lzo2()
make install DESTDIR=$BASE
}
########### ##################################################################
# OPENSSL # ##################################################################
########### ##################################################################
function build_openssl()
{
cd $BASE
mkdir -p $SRC/openssl && cd $SRC/openssl/
if [ ! -f openssl-$OPENSSL.tar.gz ]; then
$WGET https://www.openssl.org/source/openssl-$OPENSSL.tar.gz
fi
sha256=`${SHASUM} -a 256 openssl-${OPENSSL}.tar.gz | cut -d' ' -f 1`
if [ "${OPENSSL_SHA256}" = "${sha256}" ]; then
echo "[+] sha-256 verified ok"
else
echo "[!] problem with sha-256 verification"
echo "[ ] expected: " ${OPENSSL_SHA256}
echo "[ ] got: " ${sha256}
exit 1
fi
local openssl_target_platform=""
case "$(uname -m)" in
"x86_64")
openssl_target_platform="darwin64-x86_64-cc"
if [ "$(uname)" == "Linux" ]; then
openssl_target_platform="linux-x86_64"
fi
;;
"arm64")
openssl_target_platform="darwin64-arm64-cc"
if [ "$(uname)" == "Linux" ]; then
openssl_target_platform="linux64-aarch64"
fi
;;
esac
tar zxvf openssl-$OPENSSL.tar.gz
cd openssl-$OPENSSL
# Kudos to Jonathan K. Bullard from Tunnelblick.
# TODO pass cc/arch if osx
./Configure ${openssl_target_platform} no-shared zlib no-asm --openssldir="$DEST"
make build_libs build_apps openssl.pc libssl.pc libcrypto.pc
make DESTDIR=$DEST install_sw
}
########### ##################################################################
# MBEDTLS # ##################################################################
########### ##################################################################
function build_mbedtls()
{
mkdir -p $SRC/mbedtls && cd $SRC/mbedtls
if [ ! -f v$MBEDTLS.tar.gz ]; then
$WGET https://github.com/ARMmbed/mbedtls/archive/v$MBEDTLS.tar.gz
fi
sha256=`${SHASUM} -a 256 v${MBEDTLS}.tar.gz | cut -d' ' -f 1`
if [ "${MBEDTLS_SHA256}" = "${sha256}" ]; then
echo "[+] sha-256 verified ok"
else
echo "[!] problem with sha-256 verification"
echo "[ ] expected: " ${MBEDTLS_SHA256}
echo "[ ] got: " ${sha256}
exit 1
fi
tar zxvf v$MBEDTLS.tar.gz
cd mbedtls-$MBEDTLS
#scripts/config.pl full ## available for mbedtls 2.16
scripts/config.py full ## available for mbedtls 2.25
mkdir -p build
cd build
cmake ..
$MAKE
make install DESTDIR=$DEST
}
########### #################################################################
# OPENVPN # #################################################################
# OPENSSL # #################################################################
########### #################################################################
function build_openvpn()
function build_openvpn_openssl()
{
mkdir $SRC/openvpn && cd $SRC/openvpn
mkdir -p $SRC/openvpn && cd $SRC/openvpn
gpg --fetch-keys $OPENVPN_KEYS
if [ ! -f $OPENVPN.tar.gz ]; then
if [ ! -f "$OPENVPN.tar.gz" ]; then
$WGET https://build.openvpn.net/downloads/releases/$OPENVPN.tar.gz
$WGET https://build.openvpn.net/downloads/releases/$OPENVPN.tar.gz.asc
fi
......@@ -149,17 +203,61 @@ function build_openvpn()
tar zxvf $OPENVPN.tar.gz
cd $OPENVPN
MBEDTLS_CFLAGS=-I$BASE/install/usr/local/include/ \
MBEDTLS_LIBS="$DEST/usr/local/lib/libmbedtls.a $DEST/usr/local/lib/libmbedcrypto.a $DEST/usr/local/lib/libmbedx509.a" \
CFLAGS="$CFLAGS -D __APPLE_USE_RFC_3542 -I$DEST/usr/local/include" \
LZO_CFLAGS="-I$DEST/include" \
LZO_LIBS="$DEST/lib/liblzo2.a" \
OPENSSL_CFLAGS=-I$DEST/usr/local/include/ \
OPENSSL_SSL_CFLAGS=-I$DEST/usr/local/include/ \
OPENSSL_LIBS="$DEST/usr/local/lib/libssl.a $DEST/usr/local/lib/libcrypto.a $DEST/lib/libz.a" \
OPENSSL_SSL_LIBS="$DEST/usr/local/lib/libssl.a" \
OPENSSL_CRYPTO_LIBS="$DEST/usr/local/lib/libcrypto.a" \
LDFLAGS=$LDFLAGS \
CPPFLAGS=$CPPFLAGS \
CFLAGS="$CFLAGS -I$BASE/install/usr/local/include" \
CXXFLAGS=$CXXFLAGS \
$CONFIGURE \
--disable-lz4 \
--disable-unit-tests \
--disable-plugin-auth-pam \
--with-crypto-library=mbedtls \
--enable-small \
--disable-debug
$MAKE LIBS="-all-static"
make install DESTDIR=$BASE/openvpn
mkdir -p $BASE/sbin/
cp $BASE/openvpn/install/sbin/openvpn $BASE/sbin/$OPENVPN
strip $BASE/sbin/$OPENVPN
}
########### #################################################################
# OPENVPN # #################################################################
# MBEDTLS # #################################################################
########### #################################################################
function build_openvpn_mbedtls()
{
mkdir -p $SRC/openvpn && cd $SRC/openvpn
gpg --fetch-keys $OPENVPN_KEYS
if [ ! -f $OPENVPN.tar.gz ]; then
$WGET https://build.openvpn.net/downloads/releases/$OPENVPN.tar.gz
$WGET https://build.openvpn.net/downloads/releases/$OPENVPN.tar.gz.asc
fi
gpg --verify $OPENVPN.tar.gz.asc && echo "[+] gpg verification ok"
tar zxvf $OPENVPN.tar.gz
cd $OPENVPN
MBEDTLS_CFLAGS=-I$DEST/usr/local/include/ \
MBEDTLS_LIBS="$DEST/usr/local/lib/libmbedtls.a $DEST/usr/local/lib/libmbedcrypto.a $DEST/usr/local/lib/libmbedx509.a" \
LDFLAGS=$LDFLAGS \
CPPFLAGS=$CPPFLAGS \
CFLAGS="$CFLAGS -I$DEST/usr/local/include" \
CXXFLAGS=$CXXFLAGS \
$CONFIGURE \
--disable-plugin-auth-pam \
--with-crypto-library=mbedtls
# TODO debug first
#--enable-small \
#--disable-debug
$MAKE LIBS="-all-static -lz -llzo2"
make install DESTDIR=$BASE/openvpn
......@@ -173,8 +271,10 @@ function build_all()
echo "[+] Building" $OPENVPN
build_zlib
build_lzo2
build_mbedtls
build_openvpn
build_openssl
build_openvpn_openssl
#build_mbedtls # broken, see #311
#build_openvpn_mbedtls
}
function main()
......
......@@ -16,7 +16,7 @@
package main
import (
"log"
"flag"
"path"
"0xacab.org/leap/bitmask-vpn/pkg/config"
......@@ -31,18 +31,24 @@ const (
var (
Version string
AppName string
socketUid int
socketGid int
)
func init() {
flag.IntVar(&socketUid, "socket-uid", 0, "The UID for the unix socket to listen on")
flag.IntVar(&socketGid, "socket-gid", 0, "The GID for the unix socket to listen on")
}
func main() {
logger, err := config.ConfigureLogger(path.Join(helper.LogFolder, logFile))
if err != nil {
log.Println("Can't configure logger: ", err)
} else {
defer logger.Close()
}
flag.Parse()
config.LogPath = path.Join(config.Path, logFile)
config.ConfigureLogger()
defer config.CloseLogger()
helper.Version = Version
helper.AppName = AppName
// StartHelper is the main entry point - it also handles cli args in windows, and starts the http server.
helper.StartHelper(preferredPort)
helper.StartHelper(preferredPort, socketUid, socketGid)
}
package main
import (
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"runtime"
"0xacab.org/leap/bitmask-vpn/pkg/backend"
)
func main() {
var c string
var installHelpers bool
flag.StringVar(&c, "c", "", "Config file")
flag.BoolVar(&installHelpers, "i", false, "Install helpers (asks for sudo)")
flag.Parse()
if installHelpers {
backend.InstallHelpers()
os.Exit(0)
}
if len(c) == 0 {
fmt.Println("Please setup a config file with -c")
os.Exit(1)
}
if _, err := os.Stat(c); err == nil {
log.Println("Loading config file from", c)
// all good. we could validate the json.
} else if errors.Is(err, os.ErrNotExist) {
fmt.Println("Cannot find file:", c)
os.Exit(1)
} else {
// Schrodinger: file may or may not exist.
log.Println("Error:", err)
}
providerDefinitionJSON, err := ioutil.ReadFile(c)
if err != nil {
fmt.Println("Error reading config file")
os.Exit(1)
}
// TODO daemonize, or run in foreground to debug.
log.Println("Starting bitmaskd...")
opts := backend.InitOptsFromJSON("riseup", string(providerDefinitionJSON))
opts.DisableAutostart = true
opts.Obfs4 = false
opts.StartVPN = "off"
backend.EnableWebAPI("8000")
backend.InitializeBitmaskContext(opts)
log.Println("Backend initialized")
runtime.Goexit()
fmt.Println("Exit")
}
snowflake-client
// Client transport plugin for the Snowflake pluggable transport.
package main
import (
"flag"
"io"
"io/ioutil"
"log"
"math/rand"
"net"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
pt "git.torproject.org/pluggable-transports/goptlib.git"
//sf "git.torproject.org/pluggable-transports/snowflake.git/client/lib"
sf "0xacab.org/leap/bitmask-vpn/pkg/snowflake/lib"
"git.torproject.org/pluggable-transports/snowflake.git/common/nat"
"git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
"github.com/pion/webrtc/v3"
)
const (
DefaultSnowflakeCapacity = 1
)
// Accept local SOCKS connections and pass them to the handler.
func socksAcceptLoop(ln *pt.SocksListener, tongue sf.Tongue, shutdown chan struct{}, wg *sync.WaitGroup) {
defer ln.Close()
for {
conn, err := ln.AcceptSocks()
if err != nil {
if err, ok := err.(net.Error); ok && err.Temporary() {
continue
}
log.Printf("SOCKS accept error: %s", err)
break
}
log.Printf("SOCKS accepted: %v", conn.Req)
go func() {
wg.Add(1)
defer wg.Done()
defer conn.Close()
err := conn.Grant(&net.TCPAddr{IP: net.IPv4zero, Port: 0})
if err != nil {
log.Printf("conn.Grant error: %s", err)
return
}
handler := make(chan struct{})
go func() {
err = sf.Handler(conn, tongue)
if err != nil {
log.Printf("handler error: %s", err)
}
close(handler)
return
}()
select {
case <-shutdown:
log.Println("Received shutdown signal")
case <-handler:
log.Println("Handler ended")
}
return
}()
}
}
// s is a comma-separated list of ICE server URLs.
func parseIceServers(s string) []webrtc.ICEServer {
var servers []webrtc.ICEServer
s = strings.TrimSpace(s)
if len(s) == 0 {
return nil
}
urls := strings.Split(s, ",")
for _, url := range urls {
url = strings.TrimSpace(url)
servers = append(servers, webrtc.ICEServer{
URLs: []string{url},
})
}
return servers
}
func main() {
iceServersCommas := flag.String("ice", "", "comma-separated list of ICE servers")
brokerURL := flag.String("url", "", "URL of signaling broker")
frontDomain := flag.String("front", "", "front domain")
logFilename := flag.String("log", "", "name of log file")
logToStateDir := flag.Bool("log-to-state-dir", false, "resolve the log file relative to tor's pt state dir")
keepLocalAddresses := flag.Bool("keep-local-addresses", false, "keep local LAN address ICE candidates")
unsafeLogging := flag.Bool("unsafe-logging", false, "prevent logs from being scrubbed")
max := flag.Int("max", DefaultSnowflakeCapacity,
"capacity for number of multiplexed WebRTC peers")
// Deprecated
oldLogToStateDir := flag.Bool("logToStateDir", false, "use -log-to-state-dir instead")
oldKeepLocalAddresses := flag.Bool("keepLocalAddresses", false, "use -keep-local-addresses instead")
flag.Parse()
log.SetFlags(log.LstdFlags | log.LUTC)
// Don't write to stderr; versions of tor earlier than about 0.3.5.6 do
// not read from the pipe, and eventually we will deadlock because the
// buffer is full.
// https://bugs.torproject.org/26360
// https://bugs.torproject.org/25600#comment:14
var logOutput = ioutil.Discard
if *logFilename != "" {
if *logToStateDir || *oldLogToStateDir {
stateDir, err := pt.MakeStateDir()
if err != nil {
log.Fatal(err)
}
*logFilename = filepath.Join(stateDir, *logFilename)
}
logFile, err := os.OpenFile(*logFilename,
os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
log.Fatal(err)
}
defer logFile.Close()
logOutput = logFile
}
if *unsafeLogging {
log.SetOutput(logOutput)
} else {
// We want to send the log output through our scrubber first
log.SetOutput(&safelog.LogScrubber{Output: logOutput})
}
log.Println("\n\n\n --- Starting Snowflake Client ---")
iceServers := parseIceServers(*iceServersCommas)
// chooses a random subset of servers from inputs
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(iceServers), func(i, j int) {
iceServers[i], iceServers[j] = iceServers[j], iceServers[i]
})
if len(iceServers) > 2 {
iceServers = iceServers[:(len(iceServers)+1)/2]
}
log.Printf("Using ICE servers:")
for _, server := range iceServers {
log.Printf("url: %v", strings.Join(server.URLs, " "))
}
// Use potentially domain-fronting broker to rendezvous.
broker, err := sf.NewBrokerChannel(
*brokerURL, *frontDomain, sf.CreateBrokerTransport(),
*keepLocalAddresses || *oldKeepLocalAddresses)
if err != nil {
log.Fatalf("parsing broker URL: %v", err)
}
go updateNATType(iceServers, broker)
// Create a new WebRTCDialer to use as the |Tongue| to catch snowflakes
dialer := sf.NewWebRTCDialer(broker, iceServers, *max)
// Begin goptlib client process.
ptInfo, err := pt.ClientSetup(nil)
if err != nil {
log.Fatal(err)
}
if ptInfo.ProxyURL != nil {
pt.ProxyError("proxy is not supported")
os.Exit(1)
}
listeners := make([]net.Listener, 0)
shutdown := make(chan struct{})
var wg sync.WaitGroup
for _, methodName := range ptInfo.MethodNames {
switch methodName {
case "snowflake":
// TODO: Be able to recover when SOCKS dies.
ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
if err != nil {
pt.CmethodError(methodName, err.Error())
break
}
log.Printf("Started SOCKS listener at %v.", ln.Addr())
go socksAcceptLoop(ln, dialer, shutdown, &wg)
pt.Cmethod(methodName, ln.Version(), ln.Addr())
listeners = append(listeners, ln)
default:
pt.CmethodError(methodName, "no such method")
}
}
pt.CmethodsDone()
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGTERM)
if os.Getenv("TOR_PT_EXIT_ON_STDIN_CLOSE") == "1" {
// This environment variable means we should treat EOF on stdin
// just like SIGTERM: https://bugs.torproject.org/15435.
go func() {
if _, err := io.Copy(ioutil.Discard, os.Stdin); err != nil {
log.Printf("calling io.Copy(ioutil.Discard, os.Stdin) returned error: %v", err)
}
log.Printf("synthesizing SIGTERM because of stdin close")
sigChan <- syscall.SIGTERM
}()
}
// Wait for a signal.
<-sigChan
log.Println("stopping snowflake")
// Signal received, shut down.
for _, ln := range listeners {
ln.Close()
}
close(shutdown)
wg.Wait()
log.Println("snowflake is done.")
}
// loop through all provided STUN servers until we exhaust the list or find
// one that is compatable with RFC 5780
func updateNATType(servers []webrtc.ICEServer, broker *sf.BrokerChannel) {
var restrictedNAT bool
var err error
for _, server := range servers {
addr := strings.TrimPrefix(server.URLs[0], "stun:")
restrictedNAT, err = nat.CheckIfRestrictedNAT(addr)
if err == nil {
if restrictedNAT {
broker.SetNATType(nat.NATRestricted)
} else {
broker.SetNATType(nat.NATUnrestricted)
}
break
}
}
if err != nil {
broker.SetNATType(nat.NATUnknown)
}
}
riseup-vpn/*
.debhelper/*