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 1048 additions and 398 deletions
<?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,7 +8,7 @@ description: |
grade: stable
confinement: classic
icon: snap/gui/icon.svg
base: core20
base: core22
compression: lzo
architectures:
......@@ -18,11 +18,11 @@ architectures:
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:
......@@ -34,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: |
......@@ -43,206 +47,121 @@ 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
ln -fs /usr/lib/qt5/bin/lrelease /root/parts/qt5/install/usr/lib/qt5/bin/lrelease
QMAKE=/root/parts/qt5/install/usr/lib/qt5/bin/qmake LRELEASE=/usr/lib/qt5/bin/lrelease 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
- qttools5-dev-tools
- 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:
- qml-module-qt-labs-platform
after: [desktop-qt5]
desktop-integration:
plugin: nil
stage-packages:
- libx11-data
- libx11-xcb1
- xkb-data
desktop-qt5:
source: https://github.com/desktop-app/snapcraft-desktop-helpers.git
source-subdir: qt
plugin: make
make-parameters: ["FLAVOR=qt5"]
build-packages:
- build-essential
- dpkg-dev
stage-packages:
- libjpeg-turbo8
- 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
- libgdk-pixbuf2.0-0
- locales-all
- xdg-user-dirs
- fcitx-frontend-qt5
- libglib2.0-bin
stage:
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libjpeg.so.8.2.2
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libQt5Core.so.5
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libQt5DBus.so.5
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libQt5EglFSDeviceIntegration.so.5
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libQt5Gui.so.5
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libQt5Network.so.5
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libQt5XcbQpa.so.5
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/bearer/libqconnmanbearer.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/bearer/libqgenericbearer.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/bearer/libqnmbearer.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/egldeviceintegrations/libqeglfs-emu-integration.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/generic/libqevdevkeyboardplugin.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/generic/libqevdevmouseplugin.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/generic/libqevdevtabletplugin.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/generic/libqevdevtouchplugin.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/generic/libqtuiotouchplugin.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/imageformats/libqgif.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/imageformats/libqico.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/imageformats/libqjpeg.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforminputcontexts/libcomposeplatforminputcontextplugin.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforminputcontexts/libibusplatforminputcontextplugin.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforms/libqeglfs.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforms/libqlinuxfb.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforms/libqminimal.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforms/libqminimalegl.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforms/libqoffscreen.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforms/libqvnc.so
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforms/libqxcb.so
after:
- qt5
qt5:
# 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:
- libdbus-1-dev
- libegl-dev
- libfontconfig1-dev
- libfreetype-dev
- libgl-dev
- libglib2.0-dev
- libharfbuzz-dev
- libicu-dev
- libpcre2-dev
- libpng-dev
- libwayland-dev
- libx11-dev
- libx11-xcb-dev
- libxcb1-dev
- libxcb-glx0-dev
- libxcb-icccm4-dev
- libxcb-image0-dev
- libxcb-keysyms1-dev
- libxcb-randr0-dev
- libxcb-render0-dev
- libxcb-render-util0-dev
- libxcb-shape0-dev
- libxcb-shm0-dev
- libxcb-sync-dev
- libxcb-util-dev
- libxcb-xfixes0-dev
- libxcb-xinerama0-dev
- libxcb-xinput-dev
- libxcb-xkb-dev
- libxcursor-dev
- libxkbcommon-dev
- libxkbcommon-x11-dev
- zlib1g-dev
- libgdk-pixbuf2.0-0
- 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:
- libdbus-1-3
- libegl1
- libfontconfig1
- libfreetype6
- libgl1
- libglib2.0-0
- libharfbuzz0b
- libicu66
- libpcre2-16-0
- libpng16-16
#- libwayland-client0
#- libwayland-cursor0
#- libwayland-egl1
- libx11-6
- libx11-xcb1
- libxcb1
- libxcb-glx0
- libxcb-icccm4
- libxcb-image0
- libxcb-keysyms1
- libxcb-randr0
- libxcb-render0
- libxcb-render-util0
- libxcb-shape0
- libxcb-shm0
- libxcb-sync1
- libxcb-util1
- libxcb-xfixes0
- libxcb-xinerama0
- libxcb-xinput0
- libxcb-xkb1
- libxcursor1
- libxkbcommon0
- libxkbcommon-x11-0
- zlib1g
- try: [appmenu-qt5] # not available on core18
override-pull: |
QT=5_15_2
git clone -b v5.15.2 --depth=1 git://code.qt.io/qt/qt5.git .
perl init-repository --module-subset=qtbase,qtimageformats,qtsvg,qtdeclarative,qtgraphicaleffects,qtquickcontrols,qtquickcontrols2,qtscript
git submodule update qtbase qtimageformats qtsvg qtdeclarative qtgraphicaleffects qtquickcontrols qtquickcontrols2 qtscript
- 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: |
./configure \
-prefix /usr \
-bindir /usr/lib/qt5/bin \
-libdir /usr/lib/$SNAPCRAFT_ARCH_TRIPLET \
-docdir /usr/share/qt5/doc \
-headerdir /usr/include/$SNAPCRAFT_ARCH_TRIPLET/qt5 \
-datadir /usr/share/qt5 \
-archdatadir /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5 \
-plugindir /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins \
-importdir /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/imports \
-translationdir /usr/share/qt5/translations \
-hostdatadir /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5 \
-sysconfdir /etc/xdg \
-examplesdir /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/examples \
-release \
-opensource \
-confirm-license \
-no-gtk \
-no-feature-xcb-sm \
-no-openssl \
-nomake examples \
-nomake tests \
-opengl desktop \
-I $SNAPCRAFT_STAGE/usr/include \
-L $SNAPCRAFT_STAGE/usr/lib/$SNAPCRAFT_ARCH_TRIPLET
make -j$SNAPCRAFT_PARALLEL_BUILD_COUNT
make INSTALL_ROOT="$SNAPCRAFT_PART_INSTALL" install
stage:
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libjpeg.so.8.2.2
# 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
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:
- -./usr/include
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/cmake
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pkgconfig
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/bin
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/mkspecs
- -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/examples
- -./usr/lib/qt5
- -./usr/share
- bin/graphics-core22-wrapper
apps:
bitmask-root:
......@@ -252,17 +171,69 @@ apps:
command: usr/sbin/openvpn
launcher:
command: bin/${binaryName} -platform xcb
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:
QT_PLUGIN_PATH: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platforms:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/qml:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/qml/QtQuick/Controls.2/:$SNAP/usr/lib/x86_64-linux-gnu/qt5/plugins:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/xcbglintegrations
QT_QPA_PLATFORM_PLUGIN_PATH: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins:$SNAP/usr/lib/x86_64-linux-gnu/qt5/plugins/platforms
# QT_STYLE_OVERRIDE: Fusion
QML2_IMPORT_PATH: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/qml
DISABLE_WAYLAND: 1
LD_LIBRARY_PATH: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/dri
# debug -------------
# QT_OPENGL: software
# QT_DEBUG_PLUGINS: 1
SNAP_DESKTOP_DEBUG: 1
# debug -------------
# 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)
}
}
riseup-vpn (0.21.6~focal+5) focal; urgency=medium
riseup-vpn (0.21.11) hirsute; urgency=medium
* Release 0.21.6
* Release 0.21.11
-- Kali Kaneko (leap communications) <kali@leap.se> Tue, 22 Jun 2021 18:26:53 +0200
......
......@@ -16,7 +16,7 @@ Depends: ${misc:Depends}, libqt5core5a, libqt5gui5 | libqt5gui5-gles,
libqt5qml5, libqt5widgets5, libstdc++6,
qml-module-qtquick2, qml-module-qtquick-controls2, qml-module-qtquick-dialogs,
qml-module-qtquick-extras, qml-module-qt-labs-platform,
openvpn, policykit-1-gnome | polkit-1-auth-agent, python3
openvpn, policykit-1-gnome | polkit-1-auth-agent, python3, iptables
Description: Easy, fast, and secure VPN service from riseup.net.
.
The service does not require a user account, keep logs, or track you in any
......
From 82e3eda5709f1f8dd6bdb898a3c6b71a41cc4e62 Mon Sep 17 00:00:00 2001
From: jkito <belter@riseup.net>
Date: Sun, 25 Aug 2024 17:18:10 +0530
Subject: [PATCH] build: use qt5compat qml module to build on qt6.4 for ubuntu
and debian
---
bitmask.pro | 2 +-
gui/components/ErrorBox.qml | 2 +-
gui/components/Footer.qml | 14 ++++++--------
gui/components/Home.qml | 2 +-
gui/components/InitErrors.qml | 2 +-
gui/components/Locations.qml | 7 +++----
gui/components/MotdBox.qml | 2 +-
gui/components/Preferences.qml | 4 ++--
gui/components/SignalIcon.qml | 7 +++----
gui/components/Splash.qml | 2 +-
gui/components/StatusBox.qml | 2 +-
11 files changed, 21 insertions(+), 25 deletions(-)
diff --git a/bitmask.pro b/bitmask.pro
index bbeacb12..58ba5f2f 100644
--- a/bitmask.pro
+++ b/bitmask.pro
@@ -1,8 +1,8 @@
TARGET = $$TARGET
QT += quickcontrols2 svg
-CONFIG += qt staticlib
CONFIG += c++17 strict_c++
+CONFIG += qt staticlib core5compat
CONFIG += qtquickcompiler
RELEASE = $$RELEASE
diff --git a/gui/components/ErrorBox.qml b/gui/components/ErrorBox.qml
index 5667ed9d..ef8f58fb 100644
--- a/gui/components/ErrorBox.qml
+++ b/gui/components/ErrorBox.qml
@@ -1,6 +1,6 @@
import QtQuick
import QtQuick.Controls
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
import "../themes/themes.js" as Theme
Item {
diff --git a/gui/components/Footer.qml b/gui/components/Footer.qml
index d534f96a..9df6db62 100644
--- a/gui/components/Footer.qml
+++ b/gui/components/Footer.qml
@@ -2,7 +2,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
import "../themes/themes.js" as Theme
ToolBar {
@@ -49,7 +49,7 @@ ToolBar {
}
Image {
- id: lightning
+ id: lightning
smooth: true
visible: ctx != undefined & root.selectedGateway == "auto"
width: 16
@@ -61,11 +61,10 @@ ToolBar {
verticalCenter: gwButton.verticalCenter
}
}
- MultiEffect {
+ ColorOverlay{
anchors.fill: lightning
source: lightning
- colorizationColor: getLocationColor()
- colorization: 1.0
+ color: getLocationColor()
antialiasing: true
}
@@ -123,11 +122,10 @@ ToolBar {
rightMargin: 20
}
}
- MultiEffect {
+ ColorOverlay{
anchors.fill: gwQuality
source: gwQuality
- colorizationColor: getSignalColor()
- colorization: 1.0
+ color: getSignalColor()
antialiasing: false
}
}
diff --git a/gui/components/Home.qml b/gui/components/Home.qml
index f3bea85a..7830f46d 100644
--- a/gui/components/Home.qml
+++ b/gui/components/Home.qml
@@ -1,6 +1,6 @@
import QtQuick
import QtQuick.Controls
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
Page {
StatusBox {
diff --git a/gui/components/InitErrors.qml b/gui/components/InitErrors.qml
index aaf9897b..10b4755c 100644
--- a/gui/components/InitErrors.qml
+++ b/gui/components/InitErrors.qml
@@ -1,6 +1,6 @@
import QtQuick
import QtQuick.Controls
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
ErrorBox {
diff --git a/gui/components/Locations.qml b/gui/components/Locations.qml
index 2a188738..6228a58c 100644
--- a/gui/components/Locations.qml
+++ b/gui/components/Locations.qml
@@ -1,7 +1,7 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
import "../themes/themes.js" as Theme
@@ -81,11 +81,10 @@ ThemedPage {
//verticalCenterOffset: 3
}
}
- MultiEffect {
+ ColorOverlay{
anchors.fill: lightning
source: lightning
- colorizationColor: "black"
- colorization: 1.0
+ color: "black"
antialiasing: true
}
}
diff --git a/gui/components/MotdBox.qml b/gui/components/MotdBox.qml
index 2c8cdb8b..7b851c0c 100644
--- a/gui/components/MotdBox.qml
+++ b/gui/components/MotdBox.qml
@@ -1,6 +1,6 @@
import QtQuick
import QtQuick.Controls
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
import "../themes/themes.js" as Theme
Item {
diff --git a/gui/components/Preferences.qml b/gui/components/Preferences.qml
index d8ed6587..a0b6bba6 100644
--- a/gui/components/Preferences.qml
+++ b/gui/components/Preferences.qml
@@ -2,8 +2,8 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Controls.Material
-import QtQuick.Effects
-import QtCore
+import Qt5Compat.GraphicalEffects
+import Qt.labs.settings
import "../themes/themes.js" as Theme
diff --git a/gui/components/SignalIcon.qml b/gui/components/SignalIcon.qml
index 8747f054..38a23710 100644
--- a/gui/components/SignalIcon.qml
+++ b/gui/components/SignalIcon.qml
@@ -1,7 +1,7 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
import "../themes/themes.js" as Theme
@@ -41,11 +41,10 @@ Item {
]
}
}
- MultiEffect {
+ ColorOverlay{
anchors.fill: icon
source: icon
- colorizationColor: getQualityColor()
- colorization: 1.0
+ color: getQualityColor()
antialiasing: true
}
diff --git a/gui/components/Splash.qml b/gui/components/Splash.qml
index c9351804..d18cc3ba 100644
--- a/gui/components/Splash.qml
+++ b/gui/components/Splash.qml
@@ -1,6 +1,6 @@
import QtQuick
import QtQuick.Controls
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
import "../themes/themes.js" as Theme
Page {
diff --git a/gui/components/StatusBox.qml b/gui/components/StatusBox.qml
index d17c2fe0..24a1f8f2 100644
--- a/gui/components/StatusBox.qml
+++ b/gui/components/StatusBox.qml
@@ -1,6 +1,6 @@
import QtQuick
import QtQuick.Controls
-import QtQuick.Effects
+import Qt5Compat.GraphicalEffects
import QtQuick.Layouts
import QtQuick.Templates as T
import QtQuick.Controls.impl
--
2.46.0
# An image to build and package the BitmaskVPN (RiseupVPN and other branded builds)
# (c) LEAP Encryption Access Project 2018-2021
FROM ubuntu:20.04 as builder
FROM ubuntu:24.04 as builder
MAINTAINER LEAP Encryption Access Project <info@leap.se>
ARG GO_VERSION=1.22
LABEL Description="An image to build Bitmask Lite" Vendor="LEAP" Version="1.2"
ENV OSXSDK_SHA256="631b4144c6bf75bf7a4d480d685a9b5bda10ee8d03dbf0db829391e2ef858789" \
PATH="$PATH:/osxcross/target/bin:/usr/lib/go-1.14/bin"
PATH="$PATH:/osxcross/target/bin:/usr/lib/go-${GO_VERSION}/bin" \
QMAKE=qmake6
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get upgrade --yes && \
......@@ -16,7 +18,7 @@ RUN apt-get update && apt-get upgrade --yes && \
git curl wget \
libappindicator3-dev libgtk-3-dev \
webkit2gtk-4.0 \
mingw-w64 upx-ucl python snapd \
mingw-w64 upx-ucl python3 snapd \
unzip sudo locales \
devscripts fakeroot debhelper \
clang llvm-dev libxml2-dev uuid-dev \
......@@ -24,60 +26,58 @@ RUN apt-get update && apt-get upgrade --yes && \
xz-utils bzip2 gzip sed cpio libbz2-dev \
software-properties-common dh-golang \
jq \
squashfs-tools \
qtbase5-dev qttools5-dev-tools qt5-qmake g++ qtdeclarative5-dev qt5-default \
golang-1.14-go golang-go golang-golang-x-tools-dev && \
squashfs-tools libgl-dev \
qml-module-qtquick-controls2 libqt6qml6 libqt6svg6-dev qt6-l10n-tools \
qt6-tools-dev qt6-tools-dev-tools qt6-base-dev qt6-base-dev-tools \
qt6-declarative-dev qt6-declarative-dev-tools \
qml6-module-qt5compat-graphicaleffects libqt6core5compat6 libqt6core5compat6-dev \
golang golang-${GO_VERSION}-go golang-golang-x-tools-dev && \
rm -r /var/lib/apt/lists/*
RUN ln -s $(qmake6 -query "QT_INSTALL_BINS")/lrelease /usr/local/bin/lrelease
# osx cross compiling
RUN git clone https://github.com/tpoechtrager/osxcross && \
cd osxcross/tarballs && \
wget https://s3.dockerproject.org/darwin/v2/MacOSX10.10.sdk.tar.xz && \
echo "${OSXSDK_SHA256} *MacOSX10.10.sdk.tar.xz" | sha256sum -c - && \
cd .. && UNATTENDED=1 ./build.sh && \
ln -s /osxcross/target/SDK/MacOSX10.10.sdk/usr/include/objc/NSObjCRuntime.h /osxcross/target/SDK/MacOSX10.10.sdk/usr/include/objc/NSObjcRuntime.h
#RUN git clone https://github.com/tpoechtrager/osxcross && \
# cd osxcross/tarballs && \
# wget https://s3.dockerproject.org/darwin/v2/MacOSX10.10.sdk.tar.xz && \
# echo "${OSXSDK_SHA256} *MacOSX10.10.sdk.tar.xz" | sha256sum -c - && \
# cd .. && UNATTENDED=1 ./build.sh && \
# ln -s /osxcross/target/SDK/MacOSX10.10.sdk/usr/include/objc/NSObjCRuntime.h /osxcross/target/SDK/MacOSX10.10.sdk/usr/include/objc/NSObjcRuntime.h
# bomutils (for osx packaging)
RUN git clone https://github.com/hogliux/bomutils && \
cd bomutils && make && sudo make install
#RUN git clone https://github.com/hogliux/bomutils && \
# cd bomutils && make && sudo make install
# xar (for osx packaging)
RUN git clone https://github.com/VantaInc/xar && \
cd xar/xar && \
./autogen.sh && ./configure && \
make && sudo make install
#RUN git clone https://github.com/VantaInc/xar && \
# cd xar/xar && \
# ./autogen.sh && ./configure && \
# make && sudo make install
# Grab the core18 and core20 snap (which snapcraft uses as a base) from the stable channel
# and unpack it in the proper place, to speed up snapcraft builds in the containers.
RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/core18' | jq '.download_url' -r) --output core18.snap
RUN mkdir -p /snap/core18
RUN unsquashfs -d /snap/core18/current core18.snap
RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/core20' | jq '.download_url' -r) --output core20.snap
RUN mkdir -p /snap/core20
RUN unsquashfs -d /snap/core20/current core20.snap
# RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/core18' | jq '.download_url' -r) --output core18.snap
# RUN mkdir -p /snap/core18
# RUN unsquashfs -d /snap/core18/current core18.snap
# RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/core20' | jq '.download_url' -r) --output core20.snap
# RUN mkdir -p /snap/core20
# RUN unsquashfs -d /snap/core20/current core20.snap
# Grab the snapcraft snap from the stable channel and unpack it in the proper
# place.
RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/snapcraft?channel=stable' | jq '.download_url' -r) --output snapcraft.snap
RUN mkdir -p /snap/snapcraft
RUN unsquashfs -d /snap/snapcraft/current snapcraft.snap
# RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/snapcraft?channel=stable' | jq '.download_url' -r) --output snapcraft.snap
# RUN mkdir -p /snap/snapcraft
# RUN unsquashfs -d /snap/snapcraft/current snapcraft.snap
# Create a snapcraft runner (TODO: move version detection to the core of
# snapcraft).
RUN mkdir -p /snap/bin
RUN echo "#!/bin/sh" > /snap/bin/snapcraft
RUN snap_version="$(awk '/^version:/{print $2}' /snap/snapcraft/current/meta/snap.yaml)" && echo "export SNAP_VERSION=\"$snap_version\"" >> /snap/bin/snapcraft
RUN echo 'exec "$SNAP/usr/bin/python3" "$SNAP/bin/snapcraft" "$@"' >> /snap/bin/snapcraft
RUN chmod +x /snap/bin/snapcraft
RUN ln -s /snap/bin/snapcraft /bin/
# cache go modules
RUN rm -rf /gomods && mkdir -p /gomods/packages
WORKDIR /gomods
COPY mods/go.* /gomods/
COPY mods/packages/ /gomods/packages/
RUN go mod download
# RUN mkdir -p /snap/bin
# RUN echo "#!/bin/sh" > /snap/bin/snapcraft
# RUN snap_version="$(awk '/^version:/{print $2}' /snap/snapcraft/current/meta/snap.yaml)" && echo "export SNAP_VERSION=\"$snap_version\"" >> /snap/bin/snapcraft
# RUN echo 'exec "$SNAP/usr/bin/python3" "$SNAP/bin/snapcraft" "$@"' >> /snap/bin/snapcraft
# RUN chmod +x /snap/bin/snapcraft
# RUN ln -s /snap/bin/snapcraft /bin/
COPY builder.sh /
......
......@@ -6,7 +6,7 @@ export DESTDIR="${HOSTDIR}"/deploy/
rm -rf "${GUESTDIR}"
cp -r "${HOSTDIR}" "${GUESTDIR}"
cd "${GUESTDIR}"
make prepare
make vendor
case $TYPE in
snap)
echo "[+] Building SNAP"
......
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
\ No newline at end of file
# PPA How to
LEAP team maintains a [ppa repository](https://launchpad.net/~leapcodes) for the clients, pacakges are built for latest two LTS releases of ubuntu
## Pre-requisites
Ensure that all the build dependencies are already installed, you can use `make depends` on most ubuntu and debian version to have the machine
ready to build `bitmask-vpn` debian packages
If `make depends` do not work, it is useful to have the `devscripts` and `equivs` packages installed, these are needed later for building
the source package and installing build dependencies.
PPA expects a signed source package, we have to build this package and then upload to PPA the changes file using the [`dput`](https://manpages.ubuntu.com/manpages/xenial/man1/dput.1.html) tool.
Please refer to official [PPA documentation](https://help.launchpad.net/Packaging/PPA) for how to create an account and add SSH and GPG keys to be able to upload.
## Build signed source package
### Prepare the debian package from templates
```
$ export PROVIDER=riseup # can be riseup, bitmask or calyx
$ make vendor
$ BUILD_RELEASE=yes make prepare_deb
```
> **NOTE**: The above commands will generate a debian directory in `build/riseup/debian` the control file created there can be used to build a dependencies package
* If build depends are not yet installed, build a dependencies package with all the build and runtime dependencies of `bitmask-vpn`:
```
$ cd build/riseup/debian
$ mk-build-deps control
$ apt-get install -f ./riseup-vpn-build-deps_0.24.8_all.deb
```
* Add changes to changelog by copying the entries from the `CHANGELOG` file at the root of the repo
```
# example changelog file for 0.24.8 might look like
$ cd build/riseup/build/riseup-vpn_0.24.8/
$ cat debian/changelog
riseup-vpn (0.24.8~noble) noble; urgency=medium
* Reduces the size of splash screen image
* Disable obfs4 and kcp checkbox in preferences for riseup
* Removes duplicate languages in the language picker in preferences
* Language picker in preferences shows languages sorted alphabetically
* 0.24.8 ubuntu noble release
-- LEAP Encryption Access Project <debian@leap.se> Thu, 05 Sep 2024 03:06:54 +0800
riseup-vpn (0.24.8-6-g92db03c4) unstable; urgency=medium
* Initial package.
-- LEAP Encryption Access Project <debian@leap.se> Mon, 29 Jul 2019 10:00:00 +0100
```
* Bump native dot-version, change release
```
$ cd build/riseup/build/riseup-vpn_0.24.8
# to add a new entry for version 0.24.8 to the changelog file and update the release
$ dch -b -v 0.24.8~noble -D "noble" -m "riseup-vpn release 0.24.8"
```
> **NOTE:** The source tarball's name as set by the `make preapre_deb` step will not match the version we set in the changelog file, since
for PPAs we need to append the distribution name to the version, e.g to build `0.24.8` for `noble` the version is `0.24.8~noble`
> More details about versioning ppa can be found in the PPA docs [versioning section](https://help.launchpad.net/Packaging/PPA/BuildingASourcePackage#versioning)
* We need to rename the source tarball to match the version we set in the `changelog` file:
```
$ cd build/riseup/build
$ mv riseup-vpn_0.24.8.orig.tar.gz riseup-vpn_0.24.8~noble.orig.tar.gz
```
### Build signed source package
```
$ cd build/riseup/build/riseup-vpn_0.24.8
$ debuild -S -k=<key_id_for_signing>
```
### Upload changes file
```
$ cd build/riseup/build
$ dput ppa:leapcodes/ppa riseup-vpn_0.24.8~noble_source.changes
```