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 1031 additions and 325 deletions
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
......
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 glob
import os
import shutil
import sys
import subprocess
import time
HELPER = "bitmask-helper"
HELPER_PLIST = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
_dir = os.path.dirname(os.path.realpath(__file__))
_appdir = glob.glob('{}/*VPN.app'.format(_dir))[0]
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)
log.write(err)
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 isHelperRunning():
ps = _getProcessList()
return HELPER in ps
def unloadHelper():
out = subprocess.call(["launchctl", "unload", HELPER_PLIST])
time.sleep(0.5)
out2 = subprocess.call(["pkill", "-9", "bitmask-helper"]) # just in case
time.sleep(0.5)
return out == 0
def fixHelperOwner(log):
path = os.path.join(_appdir, HELPER)
try:
os.chown(path, 0, 0)
except OSError as exc:
log.write(str(exc))
return False
return True
def copyLaunchDaemon():
appDir = os.path.join(_dir, _appdir)
plist = "se.leap.bitmask-helper.plist"
plistFile = os.path.join(appDir, plist)
escapedPath = appDir.replace("/", "\/")
subprocess.call(["sed", "-i.back", "s/PATH/%s/g" % escapedPath, plistFile])
shutil.copy(plistFile, HELPER_PLIST)
def launchHelper():
out = subprocess.call(["launchctl", "load", HELPER_PLIST])
return out == 0
def grantPermissionsOnLogFolder():
helperDir = os.path.join(_appdir, '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
import time
HELPER = "bitmask-helper"
HELPER_PLIST = "/Library/LaunchDaemons/se.leap.bitmask-helper.plist"
_dir = os.path.dirname(os.path.realpath(__file__))
def main(stage="uninstall"):
logfile = "bitmask-{stage}.log".format(stage=stage)
log = open(os.path.join('/tmp', logfile), '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)
log.write(err)
sys.exit(1)
log.write('Checking if helper is running\n')
if isHelperRunning():
log.write("Trying to stop bitmask-helper...\n")
# if this fail, we can check if the HELPER_PLIST is there
try:
ok = unloadHelper()
except Exception as exc:
log.write('error: %v' % exc)
time.sleep(0.5)
log.write("success: %s \n" % str(ok))
log.write("Removing LaunchDaemon\n")
out = removeLaunchDaemon()
log.write("result: %s \n" % str(out))
# all done
log.write(stage + ' script: done\n')
sys.exit(0)
def isHelperRunning():
try:
pid = subprocess.check_output(['pgrep', HELPER])
if pid.strip() != '':
return True
except subprocess.CalledProcessError:
return False
return False
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])
if __name__ == "__main__":
stage="uninstall"
if len(sys.argv) == 2 and sys.argv[1] == "pre":
stage="preinstall"
main(stage)
......@@ -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,11 +82,14 @@ 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 === "osx") {
if (systemInfo.productType === "macos") {
preInstallOSX();
}
if (systemInfo.productType === "windows") {
......@@ -73,9 +104,13 @@ 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 {
......@@ -83,39 +118,71 @@ Component.prototype.createOperations = function ()
}
}
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} catch { exit 1}",
"errormessage=It seems that an old RiseupVPN client is running. Please exit the app and run this installer again.",
"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 RiseupVPN or CalyxVPN client and run this installer again.",
"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() {
// TODO - check if we're on Windows10 or older, and use the needed tap-windows installer accordingly.
console.log("Installing OpenVPN tap driver");
component.addElevatedOperation("Execute", "@TargetDir@/tap-windows.exe", "/S", "/SELECT_UTILITIES=1"); /* TODO uninstall */
/* remove an existing service, if it is stopped. Remove-Service is only in PS>6, and sc.exe delete leaves some garbage on the registry, so let's use the binary itself */
console.log("Removing any previously installer helper...");
component.addElevatedOperation("Execute", "{0,1}", "@TargetDir@/helper.exe", "remove");
console.log("Now trying to install latest 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."
);
}
......@@ -138,19 +205,21 @@ function uninstallOSX() {
// TODO use installer filepath??
component.addElevatedOperation(
"Execute", "{0}",
"@TargetDir@/uninstall.py", "pre",
"@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",
"@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@"
);
}
......@@ -159,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>
......@@ -10,7 +10,7 @@ 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"
......@@ -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-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
- qt5-style-plugins
- qml-module-qtquick2
- qml-module-qtquick-controls
- qml-module-qtquick-dialogs
- qml-module-qtquick-extras
- qml-module-qt-labs-platform
- 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:$SNAP/usr/lib/x86_64-linux-gnu/qt5/qml
# debug -------------
#QT_DEBUG_PLUGINS: 1
SNAP_DESKTOP_DEBUG: 1
QT_STYLE_OVERRIDE: Fusion
# 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
......@@ -11,13 +11,13 @@ set -e
#set -x
# [!] This needs to be updated for every release --------------------------
OPENVPN="openvpn-2.5.1"
OPENSSL="1.1.1j"
OPENVPN="openvpn-2.6.6"
OPENSSL="3.2.1"
MBEDTLS="2.25.0"
LZO="lzo-2.10"
ZLIB="zlib-1.2.11"
ZLIB="zlib-1.3.1"
LZO_SHA1="4924676a9bae5db58ef129dc1cebce3baa3c4b5d"
OPENSSL_SHA256="aaf2fcb575cdf6491b98ab4829abf78a3dec8402b8b81efc8f23c00d443981bf"
OPENSSL_SHA256="83c7329fe52c850677d75e5d0b0ca245309b97e8ecbcfdc1dfdc4ab9fac35b39"
MBEDTLS_SHA256="f838f670f51070bc6b4ebf0c084affd9574652ded435b064969f36ce4e8b586d"
# -------------------------------------------------------------------------
......@@ -38,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"
......@@ -57,7 +57,7 @@ MAKE="make -j4"
function build_zlib()
{
gpg --fetch-keys $ZLIB_KEYS
gpg --fetch-keys $ZLIB_KEYS
mkdir -p $SRC/zlib && cd $SRC/zlib
if [ ! -f $ZLIB.tar.gz ]; then
......@@ -86,7 +86,7 @@ function build_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
......@@ -129,11 +129,28 @@ function build_openssl()
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 darwin64-x86_64-cc no-shared zlib no-asm --openssldir="$DEST"
./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
}
......
......@@ -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)
}
}
The Debian Package riseup-vpn
----------------------------
riseup-vpn
-----------
Initial debianization of bitmask-vpn repo. This is a native package for
riseup-vpn, branded clients will use a template based on that one.
-- Kali Kaneko <kali@leap.se> Tue, 09 Feb 2021 20:26:52 +0100
-- kali kaneko <kali@leap.se> Tue, 09 Feb 2021 20:26:52 +0100
riseup-vpn for Debian
--------------------
<this file describes information about the source package, see Debian policy
manual section 4.14. You WILL either need to modify or delete this file>
-- Kali Kaneko <kali@leap.se> Tue, 09 Feb 2021 20:26:52 +0100
riseup-vpn (0.21.2) unstable; urgency=medium
riseup-vpn (0.21.11) hirsute; urgency=medium
* Release 0.21.11
-- Kali Kaneko (leap communications) <kali@leap.se> Tue, 22 Jun 2021 18:26:53 +0200
riseup-vpn (0.21.2.6) groovy; urgency=medium
* Initial Release.
-- Kali Kaneko <kali@leap.se> Tue, 09 Feb 2021 20:26:52 +0100
-- kali kaneko (leap communications) <kali@leap.se> Tue, 09 Feb 2021 20:26:52 +0100