...
 
Commits (2)
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# OSX useful to ignore
*.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# IntelliJ Idea family of suites
.idea
*.iml
## File-based project format:
*.ipr
*.iws
## mpeltonen/sbt-idea plugin
.idea_modules/
# Briefcase build directories
iOS/
macOS/
windows/
android/
linux/
django/
include boundery/templates/*
include boundery/static/*
DOCKER=docker
#.PHONY: linux
#linux: DOCKER_EXTRA=$(shell [ -L build ] && P=$$(readlink build) && echo -v $$P/:$$P )
#linux:
# $(DOCKER) build --build-arg UID=$$(id -u) --build-arg GID=$$(id -g) \
# -t boundery-client-linux -f ./docker/Dockerfile.linux ./docker
# $(DOCKER) run -it --rm --user $$(id -u):$$(id -g) \
# -v `pwd`/:/home/build/src $(DOCKER_EXTRA) boundery-client-linux \
# python3 setup.py linux
.PHONY: linux
linux: DOCKER_EXTRA=$(shell [ -L build ] && P=$$(readlink build) && echo -v $$P/:$$P )
linux:
$(DOCKER) build --build-arg UID=$$(id -u) --build-arg GID=$$(id -g) \
-t boundery-client-linux -f ./docker/Dockerfile.linux ./docker
$(DOCKER) run -it --rm --user $$(id -u):$$(id -g) \
-v `pwd`/:/home/build/src $(DOCKER_EXTRA) boundery-client-linux \
python3 setup.py linux
#.PHONY: android
#android:
......
Boundery Client
===============
Clients for the various OS platforms.
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Examples of valid version strings
# __version__ = '1.2.3.dev1' # Development release 1
# __version__ = '1.2.3a1' # Alpha Release 1
# __version__ = '1.2.3b1' # Beta Release 1
# __version__ = '1.2.3rc1' # RC Release 1
# __version__ = '1.2.3' # Final Release
# __version__ = '1.2.3.post1' # Post Release 1
__version__ = '0.0.1'
from boundery.app import main
if __name__ == '__main__':
main()
......@@ -3,7 +3,7 @@ import requests
import webbrowser
from bottle import route, run, static_file, TEMPLATE_PATH
from threading import Thread
import settings
from boundery import settings
#XXX Add some APIKEY between browser and this server.
#XXX Add JS to make it quit the deamon when all browser tabs/windows are closed.
......@@ -18,7 +18,7 @@ if "--local" in sys.argv:
DEBUG = "--debug" in sys.argv
#Pull in the various routes.
import enroll
from boundery import enroll
@route('/static/<filename:path>')
def send_static(filename):
......@@ -42,12 +42,13 @@ def poll_ready():
time.sleep(POLL_INTERVAL)
webbrowser.open("http://localhost:%s/" % settings.PORT)
if "--privsub" in sys.argv:
enroll.privsub_run()
else:
poller = Thread(target=poll_ready, name="poll_ready", daemon=True)
poller.start()
if DEBUG:
run(host="localhost", port=settings.PORT, debug=True)
def main():
if "--privsub" in sys.argv:
enroll.privsub_run()
else:
run(host="localhost", port=settings.PORT, debug=False, server='waitress')
poller = Thread(target=poll_ready, name="poll_ready", daemon=True)
poller.start()
if DEBUG:
run(host="localhost", port=settings.PORT, debug=True)
else:
run(host="localhost", port=settings.PORT, debug=False, server='waitress')
......@@ -5,12 +5,16 @@ from base64 import standard_b64encode, standard_b64decode
from threading import Thread
from functools import reduce
from operator import add
from libnacl.secret import SecretBox
import libnacl
import libnacl.utils
try:
from nacl.secret import SecretBox
from nacl.utils import random
except ImportError:
from libnacl.secret import SecretBox
from libnacl import randombytes as random
from hkdf import hkdf_extract, hkdf_expand
import osal
from settings import CENTRAL_URL
import appdirs
from boundery import osal
from boundery.settings import CENTRAL_URL
#XXX Make sure this is restartable at any point, in case the client
# crashes/is shutdown/reloads HTML/etc.
......@@ -51,14 +55,15 @@ datacache = {}
def get_from_datadir(name):
if not name in datacache:
try:
datadir = osal.get_data_dir("boundery")
datadir = appdirs.user_data_dir("boundery")
with open(os.path.join(datadir, name), 'r') as f:
datacache[name] = f.read().strip()
except:
datacache.pop(name, None)
return datacache.get(name, None)
def save_to_datadir(name, val):
datadir = osal.get_data_dir("boundery")
datadir = appdirs.user_data_dir("boundery")
os.makedirs(datadir, exist_ok=True)
with open(os.path.join(datadir, name), 'w') as f:
f.write(val)
datacache[name] = val
......@@ -66,7 +71,7 @@ def save_to_datadir(name, val):
def get_subkey(keyname, salt = None):
b64_pairing_key = get_from_datadir("pairingkey")
if b64_pairing_key is None:
pairing_key = libnacl.randombytes(32)
pairing_key = random(32)
save_to_datadir("pairingkey",
standard_b64encode(pairing_key).decode('ascii'))
else:
......@@ -217,7 +222,7 @@ def step4_api1():
@post('/step4_api2')
def step4_api2():
hkdf_salt = libnacl.randombytes(32)
hkdf_salt = random(32)
nodeid = do_priv("get_nodeid")
to_server_key = get_subkey("to_server", hkdf_salt)
ciphertext = SecretBox(to_server_key).encrypt(nodeid.encode())
......
......@@ -25,20 +25,11 @@ def sudo(cmd, *args):
stdin=subprocess.PIPE,
bufsize=1, universal_newlines=True)
def get_data_dir(name):
xdg = os.environ.get("XDG_DATA_HOME", None)
if xdg and os.path.isdir(xdg):
datadir = os.path.join(xdg, name)
elif os.path.isdir(os.path.expanduser("~/.local/share")):
datadir = os.path.join(os.path.expanduser("~/.local/share"), name)
else:
datadir = os.path.join(os.path.expanduser("~/.%s" % name))
os.makedirs(datadir, exist_ok=True)
return datadir
def get_zerotier_token_path():
return "/var/lib/zerotier-one/authtoken.secret"
#XXX Support wicd.
#XXX Fallback to talking to the card directly.
def get_ssids():
p = subprocess.run(["nmcli", "-t", "-f", "mode,active,signal,ssid", "dev", "wifi"],
stdout=subprocess.PIPE, universal_newlines=True)
......
......@@ -3,16 +3,13 @@ FROM debian:stretch-slim
ARG UID
ARG GID
#python3-cairo \
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
python3-pip python3-wheel python3-setuptools python3-dev \
pkg-config git build-essential \
python3-gi \
libcairo2-dev libgtk-3-dev libgirepository1.0-dev \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install pycairo briefcase
RUN pip3 install briefcase
#Create a user to map the host user to.
RUN groupadd -o -g ${GID} build \
......@@ -22,5 +19,4 @@ ENV HOME /home/build
ENV USER build
WORKDIR /home/build/src
CMD [ "/bin/bash" ]
#!/usr/bin/env python
import io
import re
from setuptools import setup, find_packages
import sys
with io.open('./boundery/__init__.py', encoding='utf8') as version_file:
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file.read(), re.M)
if version_match:
version = version_match.group(1)
else:
raise RuntimeError("Unable to find version string.")
with io.open('README.md', encoding='utf8') as readme:
long_description = readme.read()
setup(
name='boundery',
version=version,
description='Client for the Boundery home server',
long_description=long_description,
author='Nolan Leake',
author_email='nolan@sigbus.net',
license='GNU General Public License v3 or later (GPLv3+)',
packages=find_packages(
exclude=[
'docs', 'tests',
'windows', 'macOS', 'linux',
'iOS', 'android',
'django'
]
),
include_package_data=True,
classifiers=[
'Development Status :: 1 - Planning',
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
],
install_requires=[
'hkdf', 'PyNaCl', 'bottle', 'waitress', 'appdirs'
],
options={
'app': {
'formal_name': 'Boundery Client',
'bundle': 'me.boundery'
},
# Desktop/laptop deployments
'macos': {
'app_requires': [
]
},
'linux': {
'app_requires': [
]
},
'windows': {
'app_requires': [
'pywin32',
]
},
# Mobile deployments
'ios': {
'app_requires': [
]
},
'android': {
'app_requires': [
]
},
# Web deployments
'django': {
'app_requires': [
]
},
}
)