Ahoj Jardo,
už jsem myslel, že v patchi bude jen pár kosmetických nedostatků, které snadno opravím, ale ještě tam je pár zásadních problémů. Nejpodstatnější je asi mazání id. Viz níže.
-M.
On Fri, Mar 22 2019, Jaroslav Klapalek wrote:
Users can register multiple identifiers for a single account. Also they can rename identifiers (each identifier has its own name) and unregister/remove them from the account.
[...]
Possible TODOs:
- add option to merge two identifiers (e. g. if one is lost, it
should be possible to transfer all coffees to different one),
- divide identifiers to 2+ groups -- 'master key' and 'regular',
so the public ones (e. g. mugs) cannot remove identifiers from an account. Using e.g. "`status` INTEGER NOT NULL DEFAULT 0".
Změny oproti v3:
- nahrazení změny funkce updateRemote za proměnnou
- odebrání sloupce 'status'
app.py | 54 +++++++++++++++++++++++++++++++++++++------- coffee_db.py | 42 ++++++++++++++++++++++++++++++----- coffee_db.sql | 7 ++++++ templates/main.js | 64 ++++++++++++++++++++++++++++++++++++++++++++++------- templates/user.html | 21 ++++++++++++++++++ 5 files changed, 166 insertions(+), 22 deletions(-)
diff --git a/app.py b/app.py index 62f79b8..c5309b9 100644 --- a/app.py +++ b/app.py @@ -31,19 +31,28 @@ def hello():
@app.route('/login', methods=["POST"]) -@app.route('/login/<uid>') -def login(uid=None): +@app.route('/login/<iid>') +def login(iid=None): if request.method == "POST":
uid = request.data.decode("utf-8")
- if uid is not None:
db.add_user(uid)
session["uid"] = uid
iid = request.data.decode("utf-8")
- if iid is not None:
uid = db.get_uid(iid)
db.add_user_identifier(iid, iid, "Default")
session["iid"] = iid
if uid is None:
session["uid"] = iid
db.add_user(iid)
else:
return redirect(url_for('user'))session["uid"] = uid
@app.route('/logout') def logout(): session.pop('uid', None)
- session.pop('iid', None) return redirect(url_for('user'))
@@ -55,6 +64,8 @@ def user(): name=db.get_name(uid), flavors=[_name for (_name, _ord) in db.flavors()], count=db.coffee_count(uid, 0),
identifiers=db.list_user_identifiers(uid),
# TODO: Replace stamp parameter with proper cache control HTTPiid=session["iid"], stamp=time.time() )
@@ -71,6 +82,31 @@ def user_rename(): return redirect(url_for('user'))
+@app.route('/user/identifier/add', methods=["POST"]) +def user_add_identifier():
- if request.method == "POST":
json = request.json
db.add_user_identifier(session["uid"], json["id"], 'None')
- return redirect(url_for('user'))
+@app.route('/user/identifier/rename', methods=["POST"]) +def user_rename_identifier():
- if request.method == "POST":
json = request.json
db.rename_user_identifier(session["uid"], json["id"], json["name"])
- return redirect(url_for('user'))
+@app.route('/user/identifier/remove', methods=["POST"]) +def user_remove_identifier():
- if request.method == "POST":
json = request.json
db.remove_user_identifier(session["uid"], json["id"])
- return logout() # force logout
- #return redirect(url_for('user'))
@app.route("/coffee/graph_flavors") def coffee_graph_flavors(): days = request.args.get('days', default = 0, type = int) @@ -164,8 +200,10 @@ def coffee_graph_history(): def coffee_add(): if request.method == "POST": json = request.json
print("User '%(uid)s' had '%(flavor)s' at %(time)s" % json)
db.add_coffee(json["uid"], json["flavor"], json["time"])
# Check if identifier is valid for current user
if json["iid"] in [i[1] for i in db.list_user_identifiers(db.get_uid(json["iid"]))]:
Tohle nedává moc smysl. Použiješ iid k získání všech id uživatele a zkontroluješ, jestli je mezi nimi to stejné iid je? Asi jsi chtěl hledat podle uid.
Může tahle podmínka být někdy false? Myslím, že ne. A kdyby náhodou ano, uživateli se nezobrazí žádná chyba, jedině by si mohl všimnout, že se mu kafe neobjevilo na grafu.
A pokud to má být obrana proti "útočníkům", tak to také nepomůže, protože když útočník bude umět podvrhnout iid v /coffee/add, bude si ho moct podvrhnout i v /user/identifier/add.
Nebo mi něco uniká?
print("User '%(iid)s' had '%(flavor)s' at %(time)s" % json)
return redirect(url_for('user'))db.add_coffee(json["iid"], json["flavor"], json["time"])
diff --git a/coffee_db.py b/coffee_db.py index 348113a..04c9c38 100644 --- a/coffee_db.py +++ b/coffee_db.py @@ -25,6 +25,11 @@ def add_user(uid): c.execute("insert or ignore into users (id) values (?)", (uid,)) close_db(conn)
+def add_user_identifier(uid, iid, name):
- conn, c = open_db()
- c.execute("insert or ignore into identifiers (userid, id, name) values (?, ?, ?)", (uid, iid, name, ))
- close_db(conn)
def get_name(uid): conn, c = open_db() for name, in c.execute("select name from users where id = ?",(uid,)): @@ -33,18 +38,43 @@ def get_name(uid): close_db(conn) return None
+def get_uid(iid):
- conn, c = open_db()
- res = list(c.execute("""
select userid from identifiers where id = ?
""", (iid,)))
- return res[0][0] if len(res) > 0 else None
def name_user(uid, name): conn, c = open_db() c.execute("update users set name = ? where id = ?", (name, uid)) close_db(conn)
+def rename_user_identifier(uid, iid, name):
- conn, c = open_db()
- c.execute("update identifiers set name = ? where userid = ? and id = ?", (name, uid, iid, ))
- close_db(conn)
+def remove_user_identifier(uid, iid):
- conn, c = open_db()
- c.execute("delete from identifiers where userid = ? and id = ?", (uid, iid, ))
Kdo bude platit všechna moje kafe, když si smažu identifikátor (iid), na který jsou registrována? Buďto to chce kafe připisovat jako do teď na uid, která nejdou smazat (převod z iid na uid by se dělal až na serveru) a nebo je potřeba do tabulky identifikátorů přidat flag "valid" a mazání iid záznam nesmaže, ale jen zruší valid. Pokud pak iid zaregistruji k jinému uid, valid se zase obnoví.
Neřešil to ten status, který jsi ve v4 odebral?
- close_db(conn)
def list_users(): conn, c = open_db() for row in c.execute("select * from users"): print(row) close_db(conn)
+def list_user_identifiers(uid):
- conn, c = open_db()
- res = list(c.execute("""
select * from identifiers where userid = ?
""", (uid,)))
- close_db(conn)
- return res
def add_coffee(uid, flavor, time=None): conn, c = open_db() @@ -80,15 +110,15 @@ def coffee_flavors(uid=None, days=0, start=0): query += " where date(time) between date('now', 'localtime', '-"+ str(days+start-1) +" days') and date('now', 'localtime', '-"+ str(start) +" days')"
if uid is not None:
query += " and id = ?"
elif uid is not None:query += " and ids.userid = ?" variables.append(uid)
query += " where id = ?"
query += " where ids.userid = ?" variables.append(uid)
res = list(c.execute(""" select f.name, count(c.flavor) from flavors f
left join (select * from coffees
left join (select * from coffees co left join identifiers ids on co.id=ids.id """+query+""") c on f.name=c.flavor group by f.name order by f.ord asc
@@ -114,7 +144,7 @@ def coffee_history(uid=None): select strftime('%s', ds.d),count(c.flavor),c.flavor from (select num,date('now', 'localtime', -num || ' days') as d from days) ds left join
(select date(time, 'localtime') as time,flavor from coffees where id = ?) c
(select date(time, 'localtime') as time,flavor from coffees co left join identifiers ids on co.id = ids.id where ids.userid = ?) c on d = date(c.time) group by d, c.flavor """ , (uid,)))
@@ -129,7 +159,7 @@ def coffee_count(uid=None, start=None, stop=None): clauses = []
if uid is not None:
clauses.append("id = ?")
clauses.append("ids.userid = ?") args.append(uid)
if start is not None:
@@ -139,7 +169,7 @@ def coffee_count(uid=None, start=None, stop=None): clauses.append("date(time, 'localtime') <= date('now', 'localtime', '-%d days')" % int(stop))
for count, in c.execute(
"select count(*) from coffees where " +
"select count(*) from coffees co left join identifiers ids on co.id = ids.id where " + " and ".join(clauses) , args): res = count
diff --git a/coffee_db.sql b/coffee_db.sql index acb42a2..5d86ee9 100644 --- a/coffee_db.sql +++ b/coffee_db.sql @@ -35,3 +35,10 @@ create table if not exists days ( insert or ignore into days values (0),(1),(2),(3),(4),(5),(6) ;
+CREATE TABLE if not exists identifiers (
- `userid` varchar ( 24 ) NOT NULL,
- `id` varchar ( 24 ) NOT NULL UNIQUE,
- `name` varchar ( 24 ),
- FOREIGN KEY(`userid`) REFERENCES `users`(`id`)
+); diff --git a/templates/main.js b/templates/main.js index b28b826..5bb8bb4 100644 --- a/templates/main.js +++ b/templates/main.js @@ -2,11 +2,12 @@ var flask = "{{ url_for('hello', _external=True) }}"
// State variables
-var updateRemote = undefined; // defined iff remote server accessible -var timeToLogout = undefined; // defined during logout countdown +var updateRemote = undefined; // defined iff remote server accessible +var timeToLogout = undefined; // defined during logout countdown var logoutTimer; var reloadTimer = undefined; -var id_user; // ID of the user who is to be accounted for the next coffee +var id_user; // ID of the user who is to be accounted for the next coffee +var identifier_registration = false; // true if 'use ident
Ten komentář je nějaký useknutý, ne?
console.log("hello from flask"); //sendJSON("{"type":"empty"}"); @@ -62,22 +63,34 @@ function updateUI() function hiddenUpdateRemote(json, time = new Date()) { var msg = JSON.parse(json);
- var data = JSON.stringify({
Data se používá jen v case 'rfid', tak to nadefinuj až tam.
id: msg.uid,
uid: id_user
Server uid nepoužívá - bere ho z session.
- });
- switch(msg.type) { case "empty": break; case "rfid":
login(msg.uid);
(identifier_registration ? ajax("POST", "user/identifier/add", data, "user") : login(msg.uid)); break; case "keys":
var flavor = getFlavor(msg.key);
if (flavor !== "") {
addCoffee(flavor, time);
if (!identifier_registration) {
var flavor = getFlavor(msg.key);
if (flavor !== "") {
addCoffee(flavor, time);
}
Myslím, že tohle není třeba vůbec měnit. Kafe to může počítat i když jsi v módu přidávání.
} break; case "ajax_failure": ajax(msg.method, msg.route, msg.data, msg.id); break; }
- if (identifier_registration) {
addIdentifier_finish();
- }
A tohle bych dal taky do case 'rfid'. Když by ti za tvými zády někdo stiskl při přidávání id nějaké tlačítko na kávovaru, nové id by se ti nepřidalo.
- sendLog(json);
}
@@ -160,6 +173,8 @@ function logout() { ajax("GET", "logout", "", "user"); id_user = undefined; timeToLogout = undefined;
- updateRemote = hiddenUpdateRemote;
Tohle teď není potřeba.
- identifier_registration = false;
}
function countingTimeLogout(count_time) @@ -192,7 +207,7 @@ function addCoffee(flavor, time = new Date()) { var data = JSON.stringify({ time: time.toISOString(), flavor: flavor,
uid: id_user
}); if (id_user) { ajax("POST", "coffee/add", data, "user");iid: id_user
@@ -202,6 +217,39 @@ function addCoffee(flavor, time = new Date()) { } }
+function addIdentifier_start() {
- identifier_registration = true;
- document.getElementById("addIdentifier").disabled = true;
- document.getElementById("labelIdentifier").style.visibility = "visible";
- document.getElementById("abortIdentifier").disabled = false;
+}
+function addIdentifier_finish() {
- identifier_registration = false;
- document.getElementById("addIdentifier").disabled = false;
- document.getElementById("labelIdentifier").style.visibility = "hidden";
- document.getElementById("abortIdentifier").disabled = true;
+}
+function renameIdentifier(i) {
- var data = JSON.stringify({
id: document.getElementById("identifier_" + i).innerText,
uid: id_user,
UID se bere z session, takže se tu nemusí posílat.
name: document.getElementById("identifier_name_" + i).value
- });
- ajax("POST", "user/identifier/rename", data, "user");
+}
+function removeIdentifier(id) {
- var data = JSON.stringify({
id: id,
uid: id_user
Také se nepoužívá.
- });
- ajax("POST", "user/identifier/remove", data, "user");
+}
function sendLog(json) { ajax("POST", "log", json, "log"); } diff --git a/templates/user.html b/templates/user.html index 7e549b9..8577d15 100644 --- a/templates/user.html +++ b/templates/user.html @@ -25,10 +25,31 @@ </p> <p> <form>
<label for="username">Username:</label> <input id="username" type="text" name="name"> <input type="button" value="rename" onclick="renameUser()"> </form>
</p>
<form>
<table style="padding: 2px">
<tr>
<td colspan="4" align="center"><b>Identifiers:</b></td>
</tr>
{% for id in identifiers %}
<tr>
<td><input type="text" id="identifier_name_{{ loop.index }}" value="{{ id[2] }}" /></td>
<td {% if iid == id[1] %} style="font-weight: bold" {% endif %}>#<span id="identifier_{{ loop.index }}">{{ id[1] }}</span></td>
<td><input type="button" value="rename" onclick="renameIdentifier({{ loop.index }})" /></td>
<td><input type="button" value="remove" onclick="removeIdentifier({{ id[1] }})" /></td>
</tr>
{% endfor %}
<tr>
<td><input type="button" id="addIdentifier" value="add identifier" onclick="addIdentifier_start()" /></td>
<td colspan="2" style="visibility: hidden" id="labelIdentifier"><b>Use your identifier.</b></td>
<td><input type="button" id="abortIdentifier" value="abort" disabled onclick="addIdentifier_finish()" /></td>
</tr>
</table>
</form>
{% else %} <p>Use your card/token to log in...</p>
-- 2.7.4
Coffee mailing list Coffee@rtime.felk.cvut.cz https://rtime.felk.cvut.cz/mailman/listinfo/coffee