diff --git a/docker/routlin-dash/app/pages/captiveportal/content.json b/docker/routlin-dash/app/pages/captiveportal/content.json index dc23f39..63b35c6 100644 --- a/docker/routlin-dash/app/pages/captiveportal/content.json +++ b/docker/routlin-dash/app/pages/captiveportal/content.json @@ -202,7 +202,7 @@ "input_type": "number", "min": 0, "value": "0", - "hint": "How long after creation an account is valid before it permanently expires. 0 = never expires." + "hint": "How long before account permanently expires. 0 = never expires." }, { "type": "field", diff --git a/docker/routlin-dash/app/pages/clientcredentials/content.json b/docker/routlin-dash/app/pages/clientcredentials/content.json index ad961b5..63d5fa3 100644 --- a/docker/routlin-dash/app/pages/clientcredentials/content.json +++ b/docker/routlin-dash/app/pages/clientcredentials/content.json @@ -201,7 +201,7 @@ "input_type": "number", "min": 0, "value": "0", - "hint": "How long after creation an account is valid before it permanently expires. 0 = never expires." + "hint": "How long before account permanently expires. 0 = never expires." }, { "type": "field", diff --git a/docker/routlin-dash/app/pages/radius/content.json b/docker/routlin-dash/app/pages/radius/content.json index 3979286..9fe51fc 100644 --- a/docker/routlin-dash/app/pages/radius/content.json +++ b/docker/routlin-dash/app/pages/radius/content.json @@ -251,7 +251,7 @@ "input_type": "number", "min": 0, "value": "%RADIUS_DEFAULT_EXPIRATION_VALUE%", - "hint": "How long after creation an account is valid before it permanently expires. 0 = never expires." + "hint": "How long before account permanently expires. 0 = never expires." }, { "type": "field", diff --git a/docker/routlin-portal/app/page.py b/docker/routlin-portal/app/page.py index 2257aa9..ea52e53 100644 --- a/docker/routlin-portal/app/page.py +++ b/docker/routlin-portal/app/page.py @@ -80,7 +80,10 @@ def _verify_credential(username, password, vlan_name): return False if row is None: return False - if row['session_seconds'] > 0 and (row['date_set'] + row['session_seconds']) < int(time.time()): + now = int(time.time()) + if row['session_seconds'] > 0 and (row['date_set'] + row['session_seconds']) < now: + return False + if row['expires_seconds'] > 0 and (row['date_set'] + row['expires_seconds']) < now: return False if row['digest_type'] == DIGEST_HASH_BCRYPT: try: diff --git a/routlin/check_captive_users.py b/routlin/check_captive_users.py index e03e2c5..b19b720 100755 --- a/routlin/check_captive_users.py +++ b/routlin/check_captive_users.py @@ -39,11 +39,23 @@ def main(): (now,), ) ] + account_expired_ips = [ + row["ip"] + for row in conn.execute( + """SELECT s.ip FROM sessions s + JOIN credentials c ON s.credential_id = c.id + WHERE c.expires_seconds > 0 + AND (c.date_set + c.expires_seconds) <= ?""", + (now,), + ) + ] except sqlite3.OperationalError: conn.close() return - if not expired_ips: + all_ips = list(set(expired_ips + account_expired_ips)) + + if not all_ips: conn.close() return @@ -51,14 +63,24 @@ def main(): "DELETE FROM sessions WHERE expires_at IS NOT NULL AND expires_at <= ?", (now,), ) + if account_expired_ips: + conn.execute( + """DELETE FROM sessions WHERE id IN ( + SELECT s.id FROM sessions s + JOIN credentials c ON s.credential_id = c.id + WHERE c.expires_seconds > 0 + AND (c.date_set + c.expires_seconds) <= ?)""", + (now,), + ) conn.commit() conn.close() - lines = "".join(f"disallow {ip}\n" for ip in expired_ips) + lines = "".join(f"disallow {ip}\n" for ip in all_ips) with open(QUEUE_FILE, "a") as f: f.write(lines) - print(f"check_captive_users: queued disallow for {len(expired_ips)} expired session(s).") + print(f"check_captive_users: queued disallow for {len(all_ips)} expired session(s) " + f"({len(expired_ips)} session timeout, {len(account_expired_ips)} account expired).") if __name__ == "__main__":