basic ldap support, needs SSL verify
parent
3cb096cc76
commit
c0e8cc2ccf
84
at.py
84
at.py
|
@ -4,6 +4,9 @@ import sqlite3
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
import json
|
import json
|
||||||
|
import requests
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
from flask import Flask, render_template, abort, g, \
|
from flask import Flask, render_template, abort, g, \
|
||||||
redirect, session, request, flash, url_for
|
redirect, session, request, flash, url_for
|
||||||
from werkzeug.contrib.fixers import ProxyFix
|
from werkzeug.contrib.fixers import ProxyFix
|
||||||
|
@ -44,6 +47,10 @@ def req_to_ctx():
|
||||||
def strfts(ts, format='%d/%m/%Y %H:%M'):
|
def strfts(ts, format='%d/%m/%Y %H:%M'):
|
||||||
return datetime.fromtimestamp(ts).strftime(format)
|
return datetime.fromtimestamp(ts).strftime(format)
|
||||||
|
|
||||||
|
@app.template_filter('wikiurl')
|
||||||
|
def wikiurl(user):
|
||||||
|
return config.wiki_url % { 'login': user }
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def make_connection():
|
def make_connection():
|
||||||
conn = sqlite3.connect(config.db)
|
conn = sqlite3.connect(config.db)
|
||||||
|
@ -56,18 +63,15 @@ def close_connection(exception):
|
||||||
g.db.close()
|
g.db.close()
|
||||||
|
|
||||||
DeviceInfo = namedtuple('DeviceInfo', ['hwaddr', 'name', 'owner', 'ignored'])
|
DeviceInfo = namedtuple('DeviceInfo', ['hwaddr', 'name', 'owner', 'ignored'])
|
||||||
User = namedtuple('User', ['id', 'login', 'passwd', 'url'])
|
|
||||||
|
|
||||||
def get_device_info(conn, hwaddr):
|
def get_device_info(conn, hwaddr):
|
||||||
return list(get_device_infos(conn, (hwaddrs,)))[0]
|
return list(get_device_infos(conn, (hwaddrs,)))[0]
|
||||||
|
|
||||||
def get_device_infos(conn, hwaddrs):
|
def get_device_infos(conn, hwaddrs):
|
||||||
stmt = '''select hwaddr, name, ignored, userid, login, url from
|
stmt = '''select hwaddr, name, ignored, owner from
|
||||||
devices left join users on devices.owner = users.userid
|
devices where devices.hwaddr in (''' + ','.join(['?'] * len(hwaddrs)) + ')'
|
||||||
where devices.hwaddr in (''' + ','.join(['?'] * len(hwaddrs)) + ')'
|
|
||||||
for row in conn.execute(stmt, hwaddrs):
|
for row in conn.execute(stmt, hwaddrs):
|
||||||
owner = User(row['userid'], row['login'], None, row['url']) \
|
owner = row['owner'] or ''
|
||||||
if row['login'] else None
|
|
||||||
ignored = row['ignored']
|
ignored = row['ignored']
|
||||||
yield DeviceInfo(row['hwaddr'], row['name'], owner, ignored)
|
yield DeviceInfo(row['hwaddr'], row['name'], owner, ignored)
|
||||||
|
|
||||||
|
@ -78,6 +82,7 @@ class Updater(threading.Thread):
|
||||||
self.lease_offset = lease_offset
|
self.lease_offset = lease_offset
|
||||||
self.active = {}
|
self.active = {}
|
||||||
threading.Thread.__init__(self, *a, **kw)
|
threading.Thread.__init__(self, *a, **kw)
|
||||||
|
self.daemon = True
|
||||||
def purge_stale(self):
|
def purge_stale(self):
|
||||||
now = time()
|
now = time()
|
||||||
for addr, (atime, ip, name) in self.active.items():
|
for addr, (atime, ip, name) in self.active.items():
|
||||||
|
@ -134,7 +139,6 @@ class MtimeUpdater(Updater):
|
||||||
def file_changed(self, f):
|
def file_changed(self, f):
|
||||||
pass
|
pass
|
||||||
def run(self):
|
def run(self):
|
||||||
import os
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
mtime = os.stat(self.lease_file).st_mtime
|
mtime = os.stat(self.lease_file).st_mtime
|
||||||
|
@ -190,10 +194,9 @@ def list_all():
|
||||||
result = now_at()
|
result = now_at()
|
||||||
def prettify_user((user, atime)):
|
def prettify_user((user, atime)):
|
||||||
return {
|
return {
|
||||||
'login': user.login,
|
'login': user,
|
||||||
'timestamp': atime,
|
'timestamp': atime,
|
||||||
'pretty_time': strfts(atime),
|
'pretty_time': strfts(atime),
|
||||||
'url': user.url,
|
|
||||||
}
|
}
|
||||||
result['users'] = map(prettify_user, result['users'])
|
result['users'] = map(prettify_user, result['users'])
|
||||||
result['unknown'] = len(result['unknown'])
|
result['unknown'] = len(result['unknown'])
|
||||||
|
@ -212,45 +215,18 @@ def now_at():
|
||||||
restrict_to_hs = restrict_ip(prefix=config.claimable_prefix,
|
restrict_to_hs = restrict_ip(prefix=config.claimable_prefix,
|
||||||
exclude=config.claimable_exclude)
|
exclude=config.claimable_exclude)
|
||||||
|
|
||||||
@app.route('/register', methods=['GET'])
|
|
||||||
@restrict_to_hs
|
|
||||||
def register_form():
|
|
||||||
return render_template('register.html', **req_to_ctx())
|
|
||||||
|
|
||||||
@app.route('/register', methods=['POST'])
|
|
||||||
@restrict_to_hs
|
|
||||||
def register():
|
|
||||||
login = request.form['login'].lower()
|
|
||||||
url = request.form['url']
|
|
||||||
if 'wiki' in request.form:
|
|
||||||
url = config.wiki_url % { 'login': login }
|
|
||||||
try:
|
|
||||||
g.db.execute('insert into users (login, url, pass) values (?, ?, ?)',
|
|
||||||
[login, url, sha256(request.form['password']).hexdigest()])
|
|
||||||
return redirect('/')
|
|
||||||
except sqlite3.Error as e:
|
|
||||||
flash('Cannot add user - username taken?', category='error')
|
|
||||||
return register_form()
|
|
||||||
|
|
||||||
@app.route('/login', methods=['GET'])
|
@app.route('/login', methods=['GET'])
|
||||||
def login_form():
|
def login_form():
|
||||||
return render_template('login.html', **req_to_ctx())
|
return render_template('login.html', **req_to_ctx())
|
||||||
|
|
||||||
def get_user(conn, login, password):
|
|
||||||
row = conn.execute('select userid, login, pass, url from users where\
|
|
||||||
login = ? and pass = ?', [login, sha256(password).hexdigest()]).fetchone()
|
|
||||||
return row and User(row['userid'], row['login'], None, row['url'])
|
|
||||||
|
|
||||||
@app.route('/login', methods=['POST'])
|
@app.route('/login', methods=['POST'])
|
||||||
def login():
|
def login():
|
||||||
login = request.form.get('login', '').lower()
|
login = request.form.get('login', '').lower()
|
||||||
pwd = request.form.get('password', '')
|
pwd = request.form.get('password', '')
|
||||||
goto = request.values.get('goto') or '/'
|
goto = request.values.get('goto') or '/'
|
||||||
user = get_user(g.db, login, pwd)
|
if requests.post('https://auth.hackerspace.pl', verify=False,
|
||||||
if user:
|
data = { 'login': login, 'password': pwd }).status_code == 200:
|
||||||
session['userid'] = user.id
|
session['login'] = login
|
||||||
session['login'] = user.login
|
|
||||||
session['user'] = user
|
|
||||||
return redirect(goto)
|
return redirect(goto)
|
||||||
else:
|
else:
|
||||||
flash('Username or password invalid', category='error')
|
flash('Username or password invalid', category='error')
|
||||||
|
@ -264,7 +240,7 @@ def logout():
|
||||||
def login_required(f):
|
def login_required(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def func(*a, **kw):
|
def func(*a, **kw):
|
||||||
if 'userid' not in session:
|
if 'login' not in session:
|
||||||
flash('You must log in to continue', category='error')
|
flash('You must log in to continue', category='error')
|
||||||
return redirect('/login?' +
|
return redirect('/login?' +
|
||||||
urlencode({'goto': request.path}))
|
urlencode({'goto': request.path}))
|
||||||
|
@ -287,10 +263,10 @@ def claim():
|
||||||
if not hwaddr:
|
if not hwaddr:
|
||||||
ctx = { 'error': 'Invalid device.' }
|
ctx = { 'error': 'Invalid device.' }
|
||||||
else:
|
else:
|
||||||
userid = session['userid']
|
login = session['login']
|
||||||
try:
|
try:
|
||||||
g.db.execute('insert into devices (hwaddr, name, owner, ignored)\
|
g.db.execute('insert into devices (hwaddr, name, owner, ignored)\
|
||||||
values (?, ?, ?, ?)', [hwaddr, request.form['name'], userid, False])
|
values (?, ?, ?, ?)', [hwaddr, request.form['name'], login, False])
|
||||||
ctx = {}
|
ctx = {}
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
ctx = { 'error': 'Could not add device! Perhaps someone claimed it?' }
|
ctx = { 'error': 'Could not add device! Perhaps someone claimed it?' }
|
||||||
|
@ -298,39 +274,28 @@ def claim():
|
||||||
|
|
||||||
def get_user_devices(conn, user):
|
def get_user_devices(conn, user):
|
||||||
devs = conn.execute('select hwaddr, name, ignored from devices where\
|
devs = conn.execute('select hwaddr, name, ignored from devices where\
|
||||||
owner = ?', [user.id])
|
owner = ?', [user])
|
||||||
return (DeviceInfo(row['hwaddr'], row['name'], user, row['ignored']) for
|
return (DeviceInfo(row['hwaddr'], row['name'], user, row['ignored']) for
|
||||||
row in devs)
|
row in devs)
|
||||||
|
|
||||||
def set_password(conn, user, password):
|
@app.route('/account', methods=['GET'])
|
||||||
return conn.execute('update users set pass = ? where userid = ?',
|
|
||||||
[sha256(password).hexdigest(), user.id])
|
|
||||||
|
|
||||||
@app.route('/account', methods=['GET','POST'])
|
|
||||||
@login_required
|
@login_required
|
||||||
def account():
|
def account():
|
||||||
if request.method == 'POST':
|
devices = get_user_devices(g.db, session['login'])
|
||||||
old = request.form['old']
|
|
||||||
if get_user(g.db, session['login'], old) and \
|
|
||||||
set_password(g.db, session['user'], request.form['new']):
|
|
||||||
flash('Password changed', category='message')
|
|
||||||
else:
|
|
||||||
flash('Could not change password!', category='error')
|
|
||||||
devices = get_user_devices(g.db, session['user'])
|
|
||||||
return render_template('account.html', devices=devices)
|
return render_template('account.html', devices=devices)
|
||||||
|
|
||||||
def set_ignored(conn, hwaddr, user, value):
|
def set_ignored(conn, hwaddr, user, value):
|
||||||
return conn.execute('update devices set ignored = ? where hwaddr = ? and owner = ?',
|
return conn.execute('update devices set ignored = ? where hwaddr = ? and owner = ?',
|
||||||
[value, hwaddr, user.id])
|
[value, hwaddr, user])
|
||||||
|
|
||||||
def delete_device(conn, hwaddr, user):
|
def delete_device(conn, hwaddr, user):
|
||||||
return conn.execute('delete from devices where hwaddr = ? and owner = ?',
|
return conn.execute('delete from devices where hwaddr = ? and owner = ?',
|
||||||
[hwaddr, user.id])
|
[hwaddr, user])
|
||||||
|
|
||||||
@app.route('/devices/<id>/<action>/')
|
@app.route('/devices/<id>/<action>/')
|
||||||
@login_required
|
@login_required
|
||||||
def device(id, action):
|
def device(id, action):
|
||||||
user = session['user']
|
user = session['login']
|
||||||
if action == 'hide':
|
if action == 'hide':
|
||||||
set_ignored(g.db, id, user, True)
|
set_ignored(g.db, id, user, True)
|
||||||
if action == 'show':
|
if action == 'show':
|
||||||
|
@ -341,7 +306,6 @@ def device(id, action):
|
||||||
|
|
||||||
port = 8080
|
port = 8080
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import logging
|
|
||||||
app.logger.setLevel(logging.DEBUG)
|
app.logger.setLevel(logging.DEBUG)
|
||||||
updater = DhcpdUpdater(config.lease_file, config.timeout, config.lease_offset)
|
updater = DhcpdUpdater(config.lease_file, config.timeout, config.lease_offset)
|
||||||
updater.start()
|
updater.start()
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
create table users (
|
|
||||||
userid integer primary key,
|
|
||||||
login varchar(50) unique not null,
|
|
||||||
pass character(64),
|
|
||||||
url varchar(300)
|
|
||||||
);
|
|
||||||
|
|
||||||
create table devices (
|
create table devices (
|
||||||
hwaddr character(17) primary key,
|
hwaddr character(17) primary key,
|
||||||
name varchar(50),
|
name varchar(50),
|
||||||
owner integer references users(userid),
|
owner varchar(100) not null,
|
||||||
ignored boolean
|
ignored boolean
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,27 +5,6 @@
|
||||||
{% for msg in get_flashed_messages(True) %}
|
{% for msg in get_flashed_messages(True) %}
|
||||||
<p class="{{ msg[0] }}">{{ msg[1] }}</p>
|
<p class="{{ msg[0] }}">{{ msg[1] }}</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<h3>Change password</h3>
|
|
||||||
<form action="" method="POST">
|
|
||||||
<table>
|
|
||||||
<label><tr>
|
|
||||||
<td>Current password:</td>
|
|
||||||
<td><input type="password" name="old"></td>
|
|
||||||
</tr></label>
|
|
||||||
<label><tr>
|
|
||||||
<td>New password:</td>
|
|
||||||
<td><input type="password" name="new"></td>
|
|
||||||
</tr></label>
|
|
||||||
<label><tr>
|
|
||||||
<td>Confirm new password:</td>
|
|
||||||
<td><input type="password" name="new2"></td>
|
|
||||||
</tr></label>
|
|
||||||
<label><tr>
|
|
||||||
<td></td>
|
|
||||||
<td><input type="submit" value="Save"></td>
|
|
||||||
</tr></label>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
<h3>Claimed devices</h3>
|
<h3>Claimed devices</h3>
|
||||||
<table class="devices">
|
<table class="devices">
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<a href="account">account</a> |
|
<a href="account">account</a> |
|
||||||
<a href="logout">log out</a>
|
<a href="logout">log out</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="login">login</a> | <a href="register">register</a>
|
<a href="login">login</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -8,11 +8,9 @@ Now at hackerspace
|
||||||
<ul>
|
<ul>
|
||||||
{% for user, timestamp in users %}
|
{% for user, timestamp in users %}
|
||||||
<li>
|
<li>
|
||||||
{% if user.url %}
|
<a href="{{ user | wikiurl }}">
|
||||||
<a href="{{ user.url }}">{% endif %}
|
{{ user }} ({{ timestamp|strfts() }})
|
||||||
{{ user.login }} ({{ timestamp|strfts() }})
|
</a>
|
||||||
{% if user.url %}</a>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
Loading…
Reference in New Issue