-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- add QR generation - add daily passphrase reset - add config file support - add gallery feature - add settings feature for display brightness - add correct mime type for mobileconfig files
- Loading branch information
Showing
37 changed files
with
1,116 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
[kivy] | ||
keyboard_repeat_delay = 300 | ||
keyboard_repeat_rate = 30 | ||
log_dir = logs | ||
log_enable = 1 | ||
log_level = info | ||
log_name = kivy_%y-%m-%d_%_.txt | ||
window_icon = | ||
keyboard_mode = | ||
keyboard_layout = qwertz | ||
desktop = 1 | ||
exit_on_escape = 1 | ||
config_version = 10 | ||
|
||
[graphics] | ||
display = -1 | ||
fullscreen = no | ||
height = 600 | ||
left = 0 | ||
maxfps = 60 | ||
multisamples = 2 | ||
position = auto | ||
rotation = 0 | ||
show_cursor = 1 | ||
top = 0 | ||
width = 800 | ||
resizable = 1 | ||
|
||
[input] | ||
mouse = mouse | ||
mtdev_%(name)s = probesysfs,provider=mtdev | ||
hid_%(name)s = probesysfs,provider=hidinput | ||
|
||
[postproc] | ||
double_tap_distance = 20 | ||
double_tap_time = 250 | ||
ignore = [] | ||
jitter_distance = 0 | ||
jitter_ignore_devices = mouse,mactouch, | ||
retain_distance = 50 | ||
retain_time = 0 | ||
triple_tap_distance = 20 | ||
triple_tap_time = 375 | ||
|
||
[widgets] | ||
scroll_timeout = 250 | ||
scroll_distance = 20 | ||
scroll_friction = 1. | ||
scroll_stoptime = 300 | ||
scroll_moves = 5 | ||
|
||
[modules] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Guest Wifi Butler Change Log | ||
|
||
- **0.2.1** Add correct mime type "application/x-apple-aspen-config" for mobileconfig files | ||
|
||
- **0.2.0** Add settings feature for display brightness | ||
|
||
- **0.1.0** Initial Release | ||
- QR generation | ||
- daily passphrase reset | ||
- config file | ||
- Gallery feature |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
include requirements.txt | ||
include guest_wifi_butler/guest_wifi_config.ini | ||
include guest_wifi_butler/data/* | ||
include guest_wifi_butler/images/* | ||
include guest_wifi_butler/ui/*.kv | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# Guest WiFi Butler | ||
|
||
This project turns a Raspberry Pi with WiFi adapter and attached touchscreen into a WiFi access | ||
point. It is based on an idea from the german IT magazine c't. Your guests can easily connect to the | ||
WiFi by scanning a QR code. It is regenerated every day to ensure your guests do not have unlimited | ||
access. When the device is not requested to show the WiFi QR codes it turns into a digital photo | ||
frame that show a slideshow of your favorite photographs. | ||
|
||
## Build | ||
|
||
python setup.py sdist bdist_wheel | ||
|
||
## Installation | ||
|
||
The following instructions are copied from the [Kivy | ||
installation guide for Raspberry Pi](https://kivy.org/docs/installation/installation-rpi.html). | ||
|
||
sudo pip install -U Cython==0.28.2 | ||
sudo pip install git+https://github.com/kivy/kivy.git@master | ||
|
||
And finally we need to install the `guest_wifi_butler` package | ||
|
||
sudo pip install guest_wifi_butler-X.X.X.tar.gz | ||
|
||
## Enable Raspberry Pi Touchscreen | ||
|
||
By default Kivy will not work properly with the Raspberry Pi's touchscreen. | ||
To change that add these lines to `~/.kivy/config.ini` into input section | ||
|
||
mouse = mouse | ||
mtdev_%(name)s = probesysfs,provider=mtdev | ||
hid_%(name)s = probesysfs,provider=hidinput | ||
|
||
The config is the one of the non-root user e.g. `pi`, so in this case it | ||
would be `/home/pi/.kivy/config.ini`. | ||
|
||
## Configuration | ||
|
||
### Force the screen to stay on | ||
|
||
To force the Raspberry Pi's screen to stay on, adjust LightDM's | ||
configuration like this: | ||
|
||
sudo nano /etc/lightdm/lightdm.conf | ||
|
||
Add the following line to the `[SeatDefaults]` section: | ||
|
||
xserver-command=X -s 0 dpms | ||
|
||
### Access Point configuration | ||
|
||
In order to let bridged IP and ARP packets pass the access point, it is | ||
required to set the following sysctl variables either manually or persistent | ||
in `/etc/sysctl.conf`: | ||
|
||
net.bridge.bridge-nf-call-iptables=0 | ||
net.bridge.bridge-nf-call-arptables=0 | ||
net.bridge.bridge-nf-call-ip6tables=0 | ||
|
||
### Autostart on Boot | ||
|
||
To automatically start the guest wifi butler on Raspian startup create a file `~/.config/autostart/guest_wifi_butler.desktop` with the following content: | ||
|
||
[Desktop Entry] | ||
Encoding=UTF-8 | ||
Type=Application | ||
Name=Guest WiFi Butler | ||
Exec=sudo butler | ||
StartupNotify=false | ||
Hidden=false | ||
|
||
Once you reboot Raspian it will show the wifi butler after a few seconds. | ||
|
||
## Development guide | ||
|
||
Any help for this project will be appreciated. You can contribute through | ||
bug reports, ideas for new features or own pull requests. To make sure you | ||
did not break anything, you can run the (by far not complete) test suite. | ||
|
||
### Runs Tests | ||
|
||
pytest guest_wifi_butler\test | ||
|
||
### Code Coverage | ||
|
||
pytest --cov=guest_wifi_butler guest_wifi_butler\test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import os.path | ||
script_location = os.path.dirname(os.path.realpath(__file__)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import threading | ||
import subprocess | ||
import time | ||
import schedule | ||
import atexit | ||
import shutil | ||
import random | ||
import string | ||
import sys | ||
from guest_wifi_butler.ui.app import GuestWifiButlerApp | ||
from guest_wifi_butler.wifi_qr_generator import WifiQrGenerator | ||
from guest_wifi_butler.config.config_handler import ConfigHandler | ||
from guest_wifi_butler.config.hostapd_config_builder import HostapdConfigBuilder | ||
from guest_wifi_butler.ios.configuration_profile_creator import iOSConfigurationProfileCreator | ||
from guest_wifi_butler.ios.configuration_profile_server import iOSConfigurationProfileServer | ||
|
||
|
||
def hostapd_restart(): | ||
sys.stdout.write('Restarting Hostapd...') | ||
assert subprocess.call('/usr/sbin/service hostapd stop'.split(' '), | ||
shell=False) == 0, 'Cannot stop Hostapd service' | ||
time.sleep(8) | ||
assert subprocess.call('/usr/sbin/service hostapd start'.split(' '), | ||
shell=False) == 0, 'Cannot start Hostapd service' | ||
sys.stdout.write(' Done\n') | ||
|
||
|
||
def update_wifi_information(config): | ||
passphrase = generate_passphrase(config.passphrase_length) | ||
|
||
ios_config_creator = iOSConfigurationProfileCreator( | ||
config.config_directory) | ||
config_filename = ios_config_creator.generate(config.ssid, | ||
passphrase, | ||
config.identifier) | ||
config_uri = '%s://%s:%d/%s' % (config.public_protocol, | ||
config.public_domain, | ||
config.public_port, | ||
config_filename) | ||
# Is the mime types set correctly? | ||
|
||
wifi_qr_generator = WifiQrGenerator(config.temp_directory) | ||
wifi_qr_generator.generate_android( | ||
config.encryption, config.ssid, passphrase) | ||
wifi_qr_generator.generate_windows( | ||
config.encryption, config.ssid, passphrase) | ||
wifi_qr_generator.generate_ios(config_uri) | ||
|
||
HostapdConfigBuilder( | ||
'/etc/hostapd/hostapd.conf').generate(config.ssid, passphrase) | ||
hostapd_restart() | ||
return passphrase | ||
|
||
|
||
def start_task_scheduler(): | ||
def run(): | ||
while True: | ||
schedule.run_pending() | ||
time.sleep(1) | ||
|
||
scheduler_thread = threading.Thread(target=run) | ||
scheduler_thread.daemon = True | ||
scheduler_thread.start() | ||
|
||
|
||
def generate_passphrase(length): | ||
allowed_characters = string.letters + string.digits | ||
return ''.join(random.choice(allowed_characters) for _ in range(length)) | ||
|
||
|
||
def main(): | ||
config = ConfigHandler() | ||
passphrase = update_wifi_information(config) | ||
app = GuestWifiButlerApp(config, passphrase) | ||
|
||
server = iOSConfigurationProfileServer() | ||
server.startServer(config.listen_address, config.listen_port) | ||
|
||
def run_update_wifi(): | ||
passphrase = update_wifi_information(config) | ||
app.update_wifi_information(passphrase) | ||
|
||
schedule.every().day.at(config.update_passphrase_time).do(run_update_wifi) | ||
start_task_scheduler() | ||
|
||
def remove_temp_directory(): | ||
shutil.rmtree(config.temp_directory) | ||
|
||
atexit.register(remove_temp_directory) | ||
|
||
app.run() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env python | ||
import guest_wifi_butler.__main__ as guest_wifi_butler | ||
|
||
guest_wifi_butler.main() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import os | ||
from configparser import RawConfigParser | ||
from guest_wifi_butler import script_location | ||
|
||
|
||
DEFAULT_CONFIG = os.path.join(script_location, 'guest_wifi_config.ini') | ||
|
||
|
||
class ConfigHandler: | ||
def __init__(self, config_filepath=DEFAULT_CONFIG): | ||
config = RawConfigParser(allow_no_value=True) | ||
config.read(config_filepath) | ||
|
||
self.temp_directory = self.__assertWritableDirectory( | ||
config.get('general', 'temp_directory')) | ||
|
||
self.ssid = config.get('wifi', 'ssid') | ||
self.encryption = config.get('wifi', 'encryption') | ||
self.passphrase_length = config.getint('wifi', 'passphrase_length') | ||
self.update_passphrase_time = config.get( | ||
'wifi', 'update_passphrase_time') | ||
self.seconds_to_gallery = config.getint( | ||
'wifi', 'seconds_to_gallery') | ||
|
||
self.public_domain = config.get('ios_config_server', 'public_domain') | ||
self.public_protocol = config.get( | ||
'ios_config_server', 'public_protocol') | ||
self.public_port = config.getint('ios_config_server', 'public_port') | ||
|
||
self.listen_port = config.getint('ios_config_server', 'listen_port') | ||
self.listen_address = config.get('ios_config_server', 'listen_address') | ||
self.config_directory = self.__assertWritableDirectory( | ||
config.get('ios_config_server', 'config_directory')) | ||
self.identifier = '.'.join(self.public_domain.split('.')[::-1]) | ||
|
||
self.image_directory = self.__assertWritableDirectory( | ||
config.get('gallery', 'image_directory')) | ||
self.image_display_seconds = config.getint( | ||
'gallery', 'image_display_seconds') | ||
|
||
def __assertWritableDirectory(self, filepath): | ||
if not os.path.isabs(filepath): | ||
filepath = os.path.join(script_location, filepath) | ||
|
||
if not os.path.exists(filepath): | ||
os.mkdir(filepath) | ||
|
||
if not os.access(filepath, os.W_OK): | ||
raise OSError('Permission error. Cannot write to %s' % filepath) | ||
|
||
return filepath |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from string import Template | ||
from uuid import uuid4 | ||
from guest_wifi_butler import script_location | ||
import os | ||
|
||
|
||
class HostapdConfigBuilder: | ||
def __init__(self, config_filepath): | ||
self.__config_filepath = config_filepath | ||
|
||
def generate(self, ssid, passphrase): | ||
config_in_filename = 'hostapd.conf.in' | ||
config_in_filepath = os.path.join( | ||
script_location, 'data', config_in_filename) | ||
|
||
with open(config_in_filepath) as config_in_file, open(self.__config_filepath, 'w') as config_file: | ||
config_template = Template(config_in_file.read()) | ||
config = config_template.substitute( | ||
ssid=ssid, passphrase=passphrase) | ||
config_file.write(config) |
Oops, something went wrong.