...
 
Commits (13)
......@@ -21,19 +21,31 @@ linux:
.PHONY: windows
windows:
rm -rf windows
VAGRANT_VAGRANTFILE=Vagrantfile.windows $(VAGRANT) up
VAGRANT_VAGRANTFILE=Vagrantfile.windows $(VAGRANT) provision --provision-with build
$(VAGRANT) up windows
$(VAGRANT) provision --provision-with build windows
while [ ! -f "windows/builddone" ]; do sleep 1; done
VAGRANT_VAGRANTFILE=Vagrantfile.windows $(VAGRANT) halt
$(VAGRANT) halt windows
.PHONY: windows-gui
windows-gui:
VAGRANT_VAGRANTFILE=Vagrantfile.windows vagrant rdp -- /cert-ignore
.PHONY: windows-halt
windows-halt:
VAGRANT_VAGRANTFILE=Vagrantfile.windows vagrant halt
.PHONY: windows-destroy
windows-destroy:
VAGRANT_VAGRANTFILE=Vagrantfile.windows vagrant destroy -f
$(VAGRANT) rdp windows -- /cert-ignore
.PHONY: macos
macos:
rm -rf macOS
$(VAGRANT) up macos
$(VAGRANT) provision --provision-with build macos
$(VAGRANT) ssh macos --no-tty -c "tar cf - -C /vagrant macOS" | tar xf -
$(VAGRANT) halt macos
.PHONY: macos-test #XXX Make this depend on the built .dmg!
macos-test:
rm -f macOS/tests_passed
$(VAGRANT) up macos
$(VAGRANT) provision --provision-with test macos
$(VAGRANT) ssh macos --no-tty -c "[ -f /vagrant/macOS/tests_passed ]"
$(VAGRANT) halt macos
.PHONY: macos-gui
macos-gui:
vinagre localhost
.PHONY: dev
dev:
......
......@@ -4,7 +4,7 @@ raise "Run: vagrant plugin install winrm-elevated" unless Vagrant.has_plugin?('w
Vagrant.configure("2") do |config|
config.vm.box = ""
config.vm.define "win", autostart: false do |win|
config.vm.define "windows", autostart: false do |win|
#2.2.0 or later: win.vagrant.plugins = ["winrm", "winrm-elevated"]
win.vm.provider "virtualbox" do |vb|
......@@ -79,31 +79,100 @@ Vagrant.configure("2") do |config|
#https://www.firegiant.com/wix/tutorial/net-and-net/bootstrapping/
end
config.vm.define "mac", autostart: false do |mac|
mac.vm.box = "ashiq/osx-10.14"
config.vm.define "macos", autostart: false do |mac|
mac.vm.box = "jhcook/macos-sierra"
mac.vm.network "forwarded_port", host: 5900, guest: 5900
mac.vm.provider "virtualbox" do |vb|
#vb.gui = true
vb.memory = "2048"
end
mac.vm.provider "virtualbox" do |vb|
vb.customize ['modifyvm', :id, '--ostype', 'MacOS_64']
vb.customize ['modifyvm', :id, '--paravirtprovider', 'default']
# Adjust CPU settings according to
# https://github.com/geerlingguy/macos-virtualbox-vm
vb.customize ['modifyvm', :id, '--cpuidset',
'00000001', '000306a9', '00020800', '80000201', '178bfbff']
# Disable USB variant requiring Virtualbox proprietary extension pack
vb.customize ["modifyvm", :id, '--usbehci', 'off', '--usbxhci', 'off']
vb.customize ['modifyvm', :id, '--usbxhci', 'off']
vb.customize ['modifyvm', :id, '--usbehci', 'off']
end
mac.vm.provision "prep", type: "shell", inline: <<-SHELL
pwd
mac.vm.synced_folder ".", "/vagrant", type: "rsync",
rsync__exclude: [".*"], rsync__chown: false
mac.vm.provision "prep", type: "shell", privileged: false, inline: <<-SHELL
set -e
echo " ****** Enabling VNC ******"
sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart \
-activate -configure -access -on \
-configure -allowAccessFor -allUsers \
-configure -restart -agent -privs -all
echo " ****** Installing git ******"
curl -# -L -o /tmp/git.dmg https://sourceforge.net/projects/git-osx-installer/files/git-2.22.0-intel-universal-mavericks.dmg/download?use_mirror=autoselect
VOL=`sudo hdiutil attach /tmp/git.dmg | grep /Volumes/ | cut -f3`
sudo installer -pkg "$VOL"/git-*.pkg -target /
sudo hdiutil detach "$VOL"
rm /tmp/git.dmg
echo " ****** Installing python ******"
curl -# -o /tmp/python3.pkg https://www.python.org/ftp/python/3.7.4/python-3.7.4-macosx10.9.pkg
sudo installer -pkg /tmp/python3.pkg -target /
rm /tmp/python3.pkg
echo " ****** Setting up python venv ******"
python3 -m venv venv
. venv/bin/activate
export PIP_DISABLE_PIP_VERSION_CHECK=1
echo " ****** Installing briefcase ******"
pip install briefcase
SHELL
mac.vm.provision "build", type: "shell", run: "never", privileged: false, inline: <<-SHELL
set -e
echo " ****** Activating python venv ******"
. venv/bin/activate
export PIP_DISABLE_PIP_VERSION_CHECK=1
sudo chown -R vagrant /vagrant #workaround needing 'rsync__chown: false'
cd /vagrant
echo " ****** Starting installer build ******"
rm -rf macOS
python setup.py macos --build
echo " ****** Build done *******"
SHELL
mac.vm.provision "build", type: "shell", run: "never", inline: <<-SHELL
echo "build"
mac.vm.provision "test", type: "shell", run: "never", privileged: false, inline: <<-SHELL
set -e
echo " ****** Install ZeroTier ******"
if [ -z "`which zerotier-cli`" ]; then
curl -# -L -o /tmp/zt.pkg https://download.zerotier.com/dist/ZeroTier%20One.pkg
sudo installer -pkg /tmp/zt.pkg -target /
rm /tmp/zt.pkg
fi
sudo chown -R vagrant /vagrant #workaround needing 'rsync__chown: false'
cd /vagrant
echo " ****** Install client ******"
VOL=`sudo hdiutil attach "/vagrant/macOS/Boundery Client.dmg" | grep /Volumes/ | cut -f3`
echo " ****** Run tests *******"
dd if=/dev/zero bs=512 count=2880 of=/tmp/msdos.img 2>&1
DEV=`hdid -nomount /tmp/msdos.img`
newfs_msdos -v BOUNDERYTST $DEV 2>&1
hdiutil detach $DEV -force
DEV=`hdid /tmp/msdos.img | cut -d ' ' -f 1`
sudo BOUNDERY_APP_TEST=1 "$VOL/Boundery Client.app/Contents/MacOS/Boundery Client"
touch /vagrant/macOS/tests_passed
hdiutil detach $DEV -force
echo " ****** Tests done, detaching .dmg *******"
sudo hdiutil detach "$VOL" -force
SHELL
end
end
raise "Run: vagrant plugin install winrm" unless Vagrant.has_plugin?('winrm')
raise "Run: vagrant plugin install winrm-elevated" unless Vagrant.has_plugin?('winrm-elevated')
Vagrant.configure("2") do |config|
#2.2.0 or later: config.vagrant.plugins = ["winrm", "winrm-elevated"]
config.vm.box = "opentable/win-2012r2-standard-amd64-nocm"
config.vm.network "forwarded_port", host: 33389, guest: 3389
config.vm.guest = :windows
config.vm.communicator = "winrm"
config.winrm.username = 'vagrant'
config.winrm.password = 'vagrant'
config.vm.provider "virtualbox" do |vb|
#vb.gui = true
vb.memory = "2048"
vb.name = "windows"
end
config.vm.provision "prep", type: "shell", inline: <<-SHELL
echo " ****** Installing chocolatey ******"
if (!(Test-Path "$env:SystemDrive\\ProgramData\\Chocolatey\\bin")) {
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
}
#Need to pull in the chocolatey profile so refreshenv works.
$env:ChocolateyInstall = Convert-Path "$((Get-Command choco).path)\\..\\.."
Import-Module "$env:ChocolateyInstall\\helpers\\chocolateyProfile.psm1"
refreshenv
echo " ****** Installing .Net 3.5 ******"
Install-WindowsFeature Net-Framework-Core
#dism.exe /online /enable-feature /featurename:NetFX3 /all
echo " ****** Installing needed choco packages ******"
choco install --forcex86 -y python
choco install -y wixtoolset
choco install -y git
refreshenv
echo " ****** Setting up python venv ******"
cd \\Users\\vagrant
python -m venv venv
. venv\\Scripts\\activate.ps1
echo " ****** Installing briefcase ******"
$env:PIP_DISABLE_PIP_VERSION_CHECK=1
pip install briefcase
SHELL
config.vm.provision "build", type: "shell", run: "never", inline: <<-SHELL
echo " ****** Activating python venv ******"
cd \\Users\\vagrant
. venv\\Scripts\\activate.ps1
$env:PIP_DISABLE_PIP_VERSION_CHECK=1
echo " ****** Copying source files ******"
rm -R -Fo client
mkdir client
cp -Ex .* \\vagrant\\* client
cp -R -Fo \\vagrant\\boundery client
cd client
echo " ****** Starting installer build ******"
$env:PYTHONIOENCODING="utf-8" #Workaround briefcase bug 179.
python setup.py windows --build
echo " ****** Copying build artifacts ******"
mkdir -Fo \\vagrant\\windows
cp -Fo windows\\Boundery* \\vagrant\\windows
echo " ****** Build done *******"
echo "" > \\vagrant\\windows\\builddone
SHELL
#Package up into an exe (also with zerotier's .msi?):
#https://www.firegiant.com/wix/tutorial/net-and-net/bootstrapping/
end
......@@ -53,7 +53,10 @@ def poll_ready():
webbrowser.open("http://localhost:%s/" % settings.PORT)
def main():
if "--privsub" in sys.argv:
if os.environ.get('BOUNDERY_APP_TEST', '') == '1':
from boundery import osal
sys.exit(osal.self_test())
elif "--privsub" in sys.argv:
enroll.privsub_run()
else:
if sys.executable.upper().endswith("\\PYTHONW.EXE"):
......
......@@ -2,13 +2,10 @@ import os, sys
if os.name == "posix":
if sys.platform.startswith("darwin"):
assert(False)
from .osal_macos import *
else:
from .osal_linux import *
else:
from .osal_windows import *
#XXX Get wifi password. Pypi has "ng" which claims to do so.
#https://stackoverflow.com/questions/5747007/get-root-dialog-in-python-on-mac-os-x-windows/31984663#31984663
#/Library/Application Support/ZeroTier/One/authtoken.secret
import sys
sys.path = sys.argv[sys.argv.index('--')+1:]
cmdargs = sys.argv[1:sys.argv.index('--')]
import time, os, subprocess
import appdirs
#briefcase's start.py adds app_packages to sys.path, which skips pywin32's .pth file. sitedirs don't.
import site
site.addsitedir(next(filter(lambda i: i.endswith('app_packages'), sys.path), ''))
out = open(os.path.join(appdirs.user_data_dir("boundery"), "elevate.log"), 'w')
if os.name == "nt":
import pywintypes, win32file, msvcrt
def pipe_client():
quit = False
while not quit:
try:
print("Connecting to named pipe", file=out, flush=True)
pipe = win32file.CreateFile(r'\\.\pipe\BounderySudo',
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
0, None, win32file.OPEN_EXISTING, 0, None)
print("Starting: '%s' -- '%s'" % (cmdargs, sys.path), file=out, flush=True)
stdin = open(msvcrt.open_osfhandle(pipe, os.O_RDONLY), 'r')
stdout = open(msvcrt.open_osfhandle(pipe, os.O_WRONLY), 'w')
subprocess.Popen(cmdargs, stdin=stdin, stdout=stdout, stderr=subprocess.STDOUT)
quit=True
except pywintypes.error as e:
if e.args[0] == 2:
print("no pipe, trying again in a sec", file=out, flush=True)
time.sleep(1)
elif e.args[0] == 109:
print("broken pipe, bye bye", file=out, flush=True)
quit = True
else:
print("other? %s" % e, file=out, flush=True)
quit = True
win32file.CloseHandle(pipe)
print("Done", file=out, flush=True)
elif os.name == "posix":
def pipe_client():
print("Connecting to fifos", file=out, flush=True)
boundery_dir = appdirs.user_data_dir("boundery")
topriv = open(os.path.join(boundery_dir, "topriv"), 'r')
frompriv = open(os.path.join(boundery_dir, "frompriv"), 'w')
print("Starting: '%s' -- '%s'" % (cmdargs, sys.path), file=out, flush=True)
subprocess.Popen(cmdargs, stdin=topriv, stdout=frompriv, stderr=subprocess.STDOUT)
print("Done", file=out, flush=True)
else:
assert(False)
if __name__ == '__main__':
try:
pipe_client()
except BaseException as e:
print("Exception: '%s'" % e, file=out, flush=True)
out.close()
import sys, os, subprocess, re, appdirs
from ctypes import cdll, util
from rubicon.objc import ObjCClass
#https://stackoverflow.com/questions/49171769/how-where-to-best-retrieve-sudo-password-via-a-native-gui-on-a-macos-python-ba
mount_re = re.compile(r'^/dev/[a-zA-Z0-9]+ on (/Volumes/[^/]+) [(](.+)[)]$')
def get_mounts():
ret = []
p = subprocess.run(["mount"], stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout.split('\n'):
match = mount_re.match(line)
if not match:
continue
mnt = match.groups()[0]
options = match.groups()[1].split(', ')
if "msdos" not in options:
continue
if not os.access(mnt, os.W_OK):
continue
ret.append(mnt)
return ret
#osascript's elevate command does weird stuff to stdin/stdout, so we use a pair of fifos.
def sudo(cmd, *args):
fullargs = [ os.path.join(os.path.dirname(__file__),
'osal_elevate.py'), cmd ]
fullargs.extend(args)
fullargs.append('--')
fullargs.extend(sys.path)
boundery_dir = appdirs.user_data_dir("boundery")
os.makedirs(boundery_dir, exist_ok=True)
scriptname = os.path.join(boundery_dir, "script.sh")
with open(scriptname, 'w') as script:
script.write('#!/bin/sh\n')
script.write('exec "%s" %s\n' % (sys.executable, ' '.join([ '"'+a+'"' for a in fullargs ])))
os.chmod(scriptname, 0o755)
#XXX Hack: we replace ' ' with '?' because I couldn't get osascript quoting right.
osascript = r"""do shell script "%s" with prompt "Create private networks" with administrator privileges""" % scriptname.replace(' ', '?')
topriv = os.path.join(boundery_dir, "topriv")
frompriv = os.path.join(boundery_dir, "frompriv")
try:
os.remove(topriv)
except FileNotFoundError:
pass
try:
os.remove(frompriv)
except FileNotFoundError:
pass
os.mkfifo(topriv, mode=0o700)
os.mkfifo(frompriv, mode=0o700)
p = subprocess.Popen(["osascript", "-e", osascript])
p.stdin = open(topriv, 'w')
p.stdout = open(frompriv, 'r')
p.stderr = p.stdout
return p
def get_zerotier_token_path():
return "/Library/Application Support/ZeroTier/One/authtoken.secret"
def get_ssids():
ssids = []
cdll.LoadLibrary(util.find_library('CoreWLAN'))
CWInterface = ObjCClass('CWInterface')
interface = CWInterface.interface()
if interface:
aps = interface.scanForNetworksWithName_includeHidden_error_(None, True, None)
for ap in aps.allObjects():
if str(ap.ssid) is None:
continue
if int(ap.ibss):
continue
#XXX Figure out which SSID client is currently connected to.
ssids.append((False, min(max(2 * (int(ap.rssiValue) + 100), 0), 100), str(ap.ssid)))
return ssids
def self_test():
import logging
try:
mounts = get_mounts()
if '/Volumes/BOUNDERYTST' not in mounts:
logging.error("get_mounts failed: '%s'" % mounts)
mp = sudo('cat', '/etc/master.passwd')
if len(mp.stdout.read()) == 0:
logging.error("sudo failed")
return 10
ssids = get_ssids()
except:
logging.error("foo", exc_info=True)
return 99
......@@ -35,7 +35,7 @@ def sudo(cmd, *args):
win32pipe.PIPE_WAIT, 1, 65536, 65536, 0, None)
fullargs = [ os.path.join(os.path.dirname(__file__),
'osal_windows_elevate.py'), cmd ]
'osal_elevate.py'), cmd ]
fullargs.extend(args)
fullargs.append('--')
fullargs.extend(sys.path)
......
import sys
sys.path = sys.argv[sys.argv.index('--')+1:]
cmdargs = sys.argv[1:sys.argv.index('--')]
import time, os, subprocess
import appdirs
#briefcase's start.py adds app_packages to sys.path, which skips pywin32's .pth file. sitedirs don't.
import site
site.addsitedir(next(filter(lambda i: i.endswith('app_packages'), sys.path), ''))
import pywintypes, win32file, msvcrt
out = open(os.path.join(appdirs.user_data_dir("boundery"), "elevate.log"), 'w')
def pipe_client():
quit = False
while not quit:
try:
print("Connecting to named pipe", file=out, flush=True)
pipe = win32file.CreateFile(r'\\.\pipe\BounderySudo',
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
0, None, win32file.OPEN_EXISTING, 0, None)
print("Starting: '%s' -- '%s'" % (cmdargs, sys.path), file=out, flush=True)
stdin = open(msvcrt.open_osfhandle(pipe, os.O_RDONLY), 'r')
stdout = open(msvcrt.open_osfhandle(pipe, os.O_WRONLY), 'w')
subprocess.Popen(cmdargs, stdin=stdin, stdout=stdout, stderr=subprocess.STDOUT)
quit=True
except pywintypes.error as e:
if e.args[0] == 2:
print("no pipe, trying again in a sec", file=out, flush=True)
time.sleep(1)
elif e.args[0] == 109:
print("broken pipe, bye bye", file=out, flush=True)
quit = True
else:
print("other? %s" % e, file=out, flush=True)
quit = True
win32file.CloseHandle(pipe)
print("Done", file=out, flush=True)
if __name__ == '__main__':
try:
pipe_client()
except BaseException as e:
print("Exception: %s" % e, file=out, flush=True)
out.close()
......@@ -49,6 +49,7 @@ setup(
# Desktop/laptop deployments
'macos': {
'app_requires': [
'rubicon-objc',
]
},
'linux': {
......