Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
|
c2bd5a1acc | |
|
771a3e3260 | |
|
a881b94396 | |
|
33c0e603f8 | |
|
9fcae05d20 | |
|
0409ac3d08 |
|
@ -266,3 +266,4 @@ tags
|
|||
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
||||
.flaskenv
|
||||
docker.env
|
||||
flask_session/
|
||||
|
|
|
@ -2,6 +2,7 @@ from flask import Flask, render_template, g
|
|||
from werkzeug.exceptions import HTTPException
|
||||
|
||||
from flask_mobility import Mobility
|
||||
from flask_session import Session
|
||||
|
||||
from . import filters
|
||||
from .lib import OIDCAuthentication
|
||||
|
@ -10,6 +11,8 @@ import os
|
|||
mobility = Mobility()
|
||||
|
||||
auth = OIDCAuthentication()
|
||||
# SESSION_TYPE = 'filesystem'
|
||||
sess = Session()
|
||||
|
||||
|
||||
def create_app(environment='development'):
|
||||
|
@ -50,6 +53,8 @@ def create_app(environment='development'):
|
|||
app.logger.info("jinja2 custom filters loaded")
|
||||
filters.init_app(app)
|
||||
|
||||
sess.init_app(app)
|
||||
|
||||
# Error handlers.
|
||||
@app.errorhandler(HTTPException)
|
||||
def handle_http_error(exc):
|
||||
|
|
27
app/lib.py
27
app/lib.py
|
@ -5,7 +5,7 @@ from flask import request, abort, current_app
|
|||
from flask import session as flask_session, jsonify
|
||||
from flask_pyoidc import OIDCAuthentication as _OIDCAuth
|
||||
from flask_pyoidc.user_session import UserSession
|
||||
from flask_pyoidc.provider_configuration import ProviderConfiguration, ClientMetadata
|
||||
from flask_pyoidc.provider_configuration import ProviderConfiguration, ClientMetadata, ProviderMetadata
|
||||
|
||||
from typing import Callable, List
|
||||
|
||||
|
@ -51,35 +51,36 @@ class OIDCAuthentication(_OIDCAuth):
|
|||
super().init_app(app)
|
||||
app.auth = self
|
||||
|
||||
@property
|
||||
def userinfo(self) -> dict:
|
||||
log.debug(flask_session.get('userinfo', {}))
|
||||
return flask_session.get('userinfo', {})
|
||||
|
||||
@property
|
||||
def username(self) -> str:
|
||||
userinfo = flask_session['userinfo']
|
||||
return userinfo['email'].split('@')[0]
|
||||
# This need to be changed after upgrading headscale version
|
||||
# when hs will use the preferred_username field as username
|
||||
return self.email.split('@')[0]
|
||||
|
||||
@property
|
||||
def email(self) -> str:
|
||||
userinfo = flask_session['userinfo']
|
||||
return userinfo['email']
|
||||
return self.userinfo.get('email', 'unknown')
|
||||
|
||||
@property
|
||||
def login_name(self) -> str:
|
||||
userinfo = flask_session['userinfo']
|
||||
return userinfo.get('preferred_username', self.username)
|
||||
return self.userinfo.get('preferred_username', self.username)
|
||||
|
||||
@property
|
||||
def full_name(self) -> str:
|
||||
userinfo = flask_session['userinfo']
|
||||
return userinfo.get('name')
|
||||
return self.userinfo.get('name', self.username)
|
||||
|
||||
@property
|
||||
def groups(self) -> list:
|
||||
userinfo = flask_session['userinfo']
|
||||
return userinfo.get('groups') or []
|
||||
return self.userinfo.get('groups', [])
|
||||
|
||||
@property
|
||||
def isAdmin(self) -> bool:
|
||||
userinfo = flask_session['userinfo']
|
||||
user_groups = userinfo.get('groups', [])
|
||||
user_groups = self.userinfo.get('groups', [])
|
||||
with current_app.app_context():
|
||||
admin_groups = current_app.config.get('ADMIN_GROUPS', [])
|
||||
admin_users = current_app.config.get('ADMIN_USERS', [])
|
||||
|
|
|
@ -101,7 +101,7 @@ function uploadACL(obj) {
|
|||
});
|
||||
|
||||
$.ajax({
|
||||
url: "/policy/upload",
|
||||
url: "policy/upload",
|
||||
type: "POST",
|
||||
xhrFields: {
|
||||
withCredentials: true,
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
{{policy.updatedAt | htime_dt }}
|
||||
</span>
|
||||
<div>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm plain"><a class="plain" href="/policy/view" target="_blank">View</a></button>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm plain"><a class="plain" href="/policy/download">Download</a></button>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm plain"><a class="plain" href="{{ url_for('main.policy', action='view') }}" target="_blank">View</a></button>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm plain"><a class="plain" href="{{ url_for('main.policy', action='download') }}">Download</a></button>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm plain" data-toggle="modal" data-target="#uploadACL">Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,8 +6,6 @@ from flask import render_template, Blueprint
|
|||
from flask import redirect, session, url_for
|
||||
from app import auth
|
||||
|
||||
# from ..lib import username
|
||||
|
||||
from flask import jsonify, make_response
|
||||
from flask_pyoidc.user_session import UserSession
|
||||
|
||||
|
@ -47,6 +45,8 @@ def index():
|
|||
@main_blueprint.route('/logout')
|
||||
@auth.oidc_logout
|
||||
def logout():
|
||||
# UserSession(session).clear()
|
||||
session.clear()
|
||||
return redirect(url_for('main.index'))
|
||||
|
||||
|
||||
|
@ -136,7 +136,6 @@ def routes():
|
|||
@main_blueprint.route('/policy/<action>', methods=['GET'])
|
||||
@auth.authorize_admins('default')
|
||||
def policy(action):
|
||||
log.debug(f"action: {action}")
|
||||
policy = Policy().get()
|
||||
if action == "view":
|
||||
return policy.json
|
||||
|
|
|
@ -13,8 +13,13 @@ class BaseConfig(object):
|
|||
APP_PREFIX = os.getenv('APP_PREFIX', '')
|
||||
DEBUG_TB_ENABLED = False
|
||||
WTF_CSRF_ENABLED = False
|
||||
# Session
|
||||
# We store sessions in filesystem, max 100 files, expire in 2 hours
|
||||
SESSION_TYPE = 'filesystem'
|
||||
SESSION_FILE_THRESHOLD = 100
|
||||
PERMANENT_SESSION_LIFETIME = 7200
|
||||
|
||||
# All the followinf vars can be overriden
|
||||
# All the following vars can be overriden
|
||||
# in the environment, using `HSMAN_` prefix
|
||||
SECRET_KEY = "secreto"
|
||||
ADMIN_GROUPS = "adminGroup"
|
||||
|
@ -22,6 +27,7 @@ class BaseConfig(object):
|
|||
OIDC_CLIENT_SECRET = 'client-secreto'
|
||||
OIDC_URL = "https://myidp.example.com/auth"
|
||||
OIDC_REDIRECT_URI = 'http://localhost:5000/auth'
|
||||
OIDC_CLOCK_SKEW = 30
|
||||
|
||||
# These are required by hsapi, should not be defined here
|
||||
# HSAPI_SERVER = "https://headscale.example.com"
|
||||
|
|
|
@ -17,7 +17,7 @@ RUN apk --update --no-cache add \
|
|||
libffi-dev \
|
||||
curl && \
|
||||
chmod g+w /run && \
|
||||
pip install poetry gunicorn
|
||||
pip install poetry gunicorn poetry-plugin-export
|
||||
|
||||
COPY . /hsman
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,11 @@
|
|||
[tool.poetry]
|
||||
name = "hsman"
|
||||
version = "0.9.21"
|
||||
version = "0.9.24"
|
||||
description = "Flask Admin webui for Headscale"
|
||||
authors = ["Andrea Mistrali <andrea@mistrali.pw>"]
|
||||
license = "BSD"
|
||||
readme = "README.md"
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.11,<4.0"
|
||||
|
@ -17,6 +18,7 @@ flask-pydantic = "^0.12.0"
|
|||
uvicorn = "^0.30.1"
|
||||
hsapi-client = "^0.9.9"
|
||||
# hsapi_client = { path = "../hsapi-client", develop = true }
|
||||
flask-session = "^0.8.0"
|
||||
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
|
|
Loading…
Reference in New Issue