2023-02-20 17:23:05 +09:00
|
|
|
# pylint: disable=wrong-import-order
|
|
|
|
|
|
2023-02-20 19:21:45 +09:00
|
|
|
import headscale, helper, json, os, pytz, renderer, secrets, datetime, flask
|
|
|
|
|
from flask import Flask, Markup, redirect, render_template, request, url_for, logging, jsonify
|
2023-02-15 19:32:27 +09:00
|
|
|
from dateutil import parser
|
2023-02-17 19:02:29 +09:00
|
|
|
from flask_executor import Executor
|
2023-02-06 04:58:09 +00:00
|
|
|
|
2023-02-20 19:44:50 +09:00
|
|
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
|
|
|
|
2023-02-06 04:58:09 +00:00
|
|
|
# Global vars
|
|
|
|
|
# Colors: https://materializecss.com/color.html
|
2023-02-17 19:27:24 +09:00
|
|
|
COLOR_NAV = "blue-grey darken-1"
|
|
|
|
|
COLOR_BTN = "blue-grey darken-3"
|
2023-02-20 19:39:36 +09:00
|
|
|
DEBUG_STATE = True
|
2023-02-17 19:27:24 +09:00
|
|
|
AUTH_TYPE = os.environ["AUTH_TYPE"].replace('"', '')
|
2023-02-17 19:58:50 +09:00
|
|
|
STATIC_URL_PATH = "/static"
|
2023-02-06 04:58:09 +00:00
|
|
|
|
2023-02-19 19:58:56 +09:00
|
|
|
# Initiate the Flask application:
|
|
|
|
|
app = Flask(__name__, static_url_path=STATIC_URL_PATH)
|
2023-02-20 19:44:50 +09:00
|
|
|
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
|
2023-02-19 20:20:55 +09:00
|
|
|
LOG = logging.create_logger(app)
|
2023-02-19 19:58:56 +09:00
|
|
|
executor = Executor(app)
|
|
|
|
|
|
2023-02-20 14:39:09 +09:00
|
|
|
########################################################################################
|
2023-02-16 20:17:36 +09:00
|
|
|
# Set Authentication type:
|
2023-02-20 14:39:09 +09:00
|
|
|
########################################################################################
|
2023-02-16 20:17:36 +09:00
|
|
|
if AUTH_TYPE.lower() == "oidc":
|
2023-02-20 18:47:19 +09:00
|
|
|
# https://flask-pyoidc.readthedocs.io/en/latest/
|
2023-02-19 19:58:56 +09:00
|
|
|
LOG.error("Loading OIDC libraries and configuring app...")
|
2023-02-19 20:25:33 +09:00
|
|
|
|
2023-02-20 18:47:19 +09:00
|
|
|
from flask_pyoidc import OIDCAuthentication
|
|
|
|
|
from flask_pyoidc.provider_configuration import ProviderConfiguration, ClientMetadata
|
|
|
|
|
from flask_pyoidc.user_session import UserSession
|
|
|
|
|
|
2023-02-19 19:58:56 +09:00
|
|
|
DOMAIN_NAME = os.environ["DOMAIN_NAME"]
|
|
|
|
|
BASE_PATH = os.environ["SCRIPT_NAME"] if os.environ["SCRIPT_NAME"] != "/" else ""
|
|
|
|
|
OIDC_ISSUER = os.environ["OIDC_ISSUER"].replace('"','')
|
|
|
|
|
OIDC_SECRET = os.environ["OIDC_CLIENT_SECRET"]
|
|
|
|
|
OIDC_CLIENT_ID = os.environ["OIDC_CLIENT_ID"]
|
2023-02-20 18:47:19 +09:00
|
|
|
REDIRECT_URI = DOMAIN_NAME+BASE_PATH+"/redirect_uri"
|
|
|
|
|
|
|
|
|
|
app.config.update(
|
|
|
|
|
{
|
|
|
|
|
'OIDC_REDIRECT_URI': REDIRECT_URI,
|
2023-02-20 19:32:11 +09:00
|
|
|
'SECRET_KEY': secrets.token_urlsafe(32),
|
2023-02-20 18:47:19 +09:00
|
|
|
'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days=7).total_seconds(),
|
|
|
|
|
'DEBUG': DEBUG_STATE
|
2023-02-19 19:58:56 +09:00
|
|
|
}
|
2023-02-20 18:47:19 +09:00
|
|
|
)
|
|
|
|
|
|
2023-02-20 19:12:47 +09:00
|
|
|
CLIENT_METADATA = ClientMetadata(
|
|
|
|
|
client_id=OIDC_CLIENT_ID,
|
|
|
|
|
client_secret=OIDC_SECRET,
|
|
|
|
|
post_logout_redirect_uris=[DOMAIN_NAME+'/logout'])
|
|
|
|
|
|
|
|
|
|
CONFIG = ProviderConfiguration(issuer=OIDC_ISSUER, client_metadata=CLIENT_METADATA)
|
|
|
|
|
auth = OIDCAuthentication({'default': CONFIG}, app)
|
2023-02-20 18:47:19 +09:00
|
|
|
|
|
|
|
|
# Testing another OIDC library
|
|
|
|
|
# if AUTH_TYPE.lower() == "oidc":
|
|
|
|
|
# # https://flask-oidc2.readthedocs.io/en/latest/#
|
|
|
|
|
# # https://gist.github.com/thomasdarimont/145dc9aa857b831ff2eff221b79d179a/
|
|
|
|
|
# # https://www.authelia.com/integration/openid-connect/introduction/
|
|
|
|
|
# LOG.error("Loading OIDC libraries and configuring app...")
|
|
|
|
|
#
|
|
|
|
|
# DOMAIN_NAME = os.environ["DOMAIN_NAME"]
|
|
|
|
|
# BASE_PATH = os.environ["SCRIPT_NAME"] if os.environ["SCRIPT_NAME"] != "/" else ""
|
|
|
|
|
# OIDC_ISSUER = os.environ["OIDC_ISSUER"].replace('"','')
|
|
|
|
|
# OIDC_SECRET = os.environ["OIDC_CLIENT_SECRET"]
|
|
|
|
|
# OIDC_CLIENT_ID = os.environ["OIDC_CLIENT_ID"]
|
|
|
|
|
# # Construct client_secrets.json:
|
|
|
|
|
# client_secrets = """
|
|
|
|
|
# {
|
|
|
|
|
# "web": {
|
|
|
|
|
# "issuer": \""""+OIDC_ISSUER+"""",
|
|
|
|
|
# "auth_uri": \""""+OIDC_ISSUER+"""/api/oidc/authorization",
|
|
|
|
|
# "client_id": \""""+OIDC_CLIENT_ID+"""",
|
|
|
|
|
# "client_secret": \""""+OIDC_SECRET+"""",
|
|
|
|
|
# "redirect_uris": [\""""+DOMAIN_NAME+BASE_PATH+"""/oidc_callback"],
|
|
|
|
|
# "userinfo_uri": \""""+OIDC_ISSUER+"""/api/oidc/userinfo",
|
|
|
|
|
# "token_uri": \""""+OIDC_ISSUER+"""/api/oidc/token",
|
|
|
|
|
# "token_introspection_uri": \""""+OIDC_ISSUER+"""/api/oidc/introspection"
|
|
|
|
|
# }
|
|
|
|
|
# }
|
|
|
|
|
# """
|
|
|
|
|
# LOG.error("Secrets")
|
|
|
|
|
# LOG.error(client_secrets)
|
|
|
|
|
# with open("/app/instance/secrets.json", "w+") as secrets_json:
|
|
|
|
|
# secrets_json.write(client_secrets)
|
|
|
|
|
#
|
|
|
|
|
# app.config.update({
|
|
|
|
|
# 'SECRET_KEY': secrets.token_urlsafe(32),
|
|
|
|
|
# 'TESTING': DEBUG_STATE,
|
|
|
|
|
# 'DEBUG': DEBUG_STATE,
|
|
|
|
|
# 'OIDC_CLIENT_SECRETS': '/app/instance/secrets.json',
|
|
|
|
|
# 'OIDC_ID_TOKEN_COOKIE_SECURE': False,
|
|
|
|
|
# 'OIDC_REQUIRE_VERIFIED_EMAIL': False,
|
|
|
|
|
# 'OIDC_USER_INFO_ENABLED': True,
|
|
|
|
|
# 'OIDC_OPENID_REALM': 'Headscale-WebUI',
|
|
|
|
|
# 'OIDC_SCOPES': ['openid', 'email', 'profile'],
|
|
|
|
|
# 'OIDC_INTROSPECTION_AUTH_METHOD': 'client_secret_post'
|
|
|
|
|
# })
|
|
|
|
|
# from flask_oidc import OpenIDConnect
|
|
|
|
|
# oidc = OpenIDConnect(app)
|
2023-02-19 15:25:08 +09:00
|
|
|
|
2023-02-17 12:30:52 +09:00
|
|
|
elif AUTH_TYPE.lower() == "basic":
|
2023-02-16 20:17:36 +09:00
|
|
|
# https://flask-basicauth.readthedocs.io/en/latest/
|
2023-02-19 19:58:56 +09:00
|
|
|
LOG.error("Loading basic auth libraries and configuring app...")
|
2023-02-16 20:44:33 +09:00
|
|
|
from flask_basicauth import BasicAuth
|
2023-02-19 19:58:56 +09:00
|
|
|
|
2023-02-16 20:44:33 +09:00
|
|
|
app.config['BASIC_AUTH_USERNAME'] = os.environ["BASIC_AUTH_USER"].replace('"', '')
|
|
|
|
|
app.config['BASIC_AUTH_PASSWORD'] = os.environ["BASIC_AUTH_PASS"]
|
2023-02-16 21:39:54 +09:00
|
|
|
app.config['BASIC_AUTH_FORCE'] = True
|
2023-02-16 20:44:33 +09:00
|
|
|
|
|
|
|
|
basic_auth = BasicAuth(app)
|
|
|
|
|
|
2023-02-13 20:56:31 +09:00
|
|
|
########################################################################################
|
|
|
|
|
# / pages - User-facing pages
|
|
|
|
|
########################################################################################
|
2023-02-20 18:47:19 +09:00
|
|
|
# Testing OIDC page...
|
|
|
|
|
@app.route('/oidctest')
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-20 18:47:19 +09:00
|
|
|
def oidctest_page():
|
|
|
|
|
user_session = UserSession(flask.session)
|
|
|
|
|
return jsonify(access_token=user_session.access_token,
|
|
|
|
|
id_token=user_session.id_token,
|
|
|
|
|
userinfo=user_session.userinfo)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/')
|
|
|
|
|
@app.route('/overview')
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def overview_page():
|
2023-02-16 20:17:36 +09:00
|
|
|
# Some basic sanity checks:
|
2023-02-16 21:39:54 +09:00
|
|
|
pass_checks = str(helper.load_checks())
|
2023-02-17 16:55:46 +09:00
|
|
|
if pass_checks != "Pass": return redirect(url_for(pass_checks))
|
2023-02-06 04:58:09 +00:00
|
|
|
|
|
|
|
|
return render_template('overview.html',
|
|
|
|
|
render_page = renderer.render_overview(),
|
|
|
|
|
COLOR_NAV = COLOR_NAV,
|
|
|
|
|
COLOR_BTN = COLOR_BTN
|
|
|
|
|
)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/machines', methods=('GET', 'POST'))
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def machines_page():
|
2023-02-16 20:17:36 +09:00
|
|
|
# Some basic sanity checks:
|
2023-02-16 21:39:54 +09:00
|
|
|
pass_checks = str(helper.load_checks())
|
2023-02-17 16:55:46 +09:00
|
|
|
if pass_checks != "Pass": return redirect(url_for(pass_checks))
|
2023-02-15 12:31:22 +09:00
|
|
|
|
2023-02-06 04:58:09 +00:00
|
|
|
cards = renderer.render_machines_cards()
|
|
|
|
|
return render_template('machines.html',
|
|
|
|
|
cards = cards,
|
|
|
|
|
headscale_server = headscale.get_url(),
|
|
|
|
|
COLOR_NAV = COLOR_NAV,
|
|
|
|
|
COLOR_BTN = COLOR_BTN
|
|
|
|
|
)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/users', methods=('GET', 'POST'))
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def users_page():
|
2023-02-16 20:17:36 +09:00
|
|
|
# Some basic sanity checks:
|
2023-02-16 21:39:54 +09:00
|
|
|
pass_checks = str(helper.load_checks())
|
2023-02-17 16:55:46 +09:00
|
|
|
if pass_checks != "Pass": return redirect(url_for(pass_checks))
|
2023-02-06 04:58:09 +00:00
|
|
|
|
|
|
|
|
cards = renderer.render_users_cards()
|
|
|
|
|
return render_template('users.html',
|
|
|
|
|
cards = cards,
|
|
|
|
|
headscale_server = headscale.get_url(),
|
|
|
|
|
COLOR_NAV = COLOR_NAV,
|
|
|
|
|
COLOR_BTN = COLOR_BTN
|
|
|
|
|
)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/settings', methods=('GET', 'POST'))
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def settings_page():
|
2023-02-16 20:17:36 +09:00
|
|
|
# Some basic sanity checks:
|
2023-02-16 21:39:54 +09:00
|
|
|
pass_checks = str(helper.load_checks())
|
2023-02-17 16:55:46 +09:00
|
|
|
if pass_checks != "Pass": return redirect(url_for(pass_checks))
|
2023-02-06 04:58:09 +00:00
|
|
|
|
2023-02-16 20:17:36 +09:00
|
|
|
return render_template('settings.html',
|
|
|
|
|
url = headscale.get_url(),
|
2023-02-15 12:31:22 +09:00
|
|
|
COLOR_NAV = COLOR_NAV,
|
|
|
|
|
COLOR_BTN = COLOR_BTN,
|
2023-02-17 19:30:29 +09:00
|
|
|
BUILD_DATE = os.environ["BUILD_DATE"],
|
|
|
|
|
APP_VERSION = os.environ["APP_VERSION"],
|
|
|
|
|
GIT_COMMIT = os.environ["GIT_COMMIT"],
|
|
|
|
|
GIT_BRANCH = os.environ["GIT_BRANCH"],
|
|
|
|
|
HS_VERSION = os.environ["HS_VERSION"]
|
2023-02-15 12:31:22 +09:00
|
|
|
)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/error')
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-15 12:31:22 +09:00
|
|
|
def error_page():
|
2023-02-16 21:42:54 +09:00
|
|
|
if helper.access_checks() == "Pass":
|
2023-02-15 14:29:14 +09:00
|
|
|
return redirect(url_for('overview_page'))
|
2023-02-15 13:59:45 +09:00
|
|
|
|
2023-02-15 12:31:22 +09:00
|
|
|
return render_template('error.html',
|
2023-02-16 21:42:54 +09:00
|
|
|
ERROR_MESSAGE = Markup(helper.access_checks())
|
2023-02-15 12:31:22 +09:00
|
|
|
)
|
2023-02-06 04:58:09 +00:00
|
|
|
|
|
|
|
|
########################################################################################
|
|
|
|
|
# /api pages
|
|
|
|
|
########################################################################################
|
|
|
|
|
|
|
|
|
|
########################################################################################
|
|
|
|
|
# Headscale API Key Endpoints
|
|
|
|
|
########################################################################################
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/test_key', methods=('GET', 'POST'))
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def test_key_page():
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
|
|
|
|
|
# Test the API key. If the test fails, return a failure.
|
|
|
|
|
status = headscale.test_api_key(url, api_key)
|
|
|
|
|
if status != 200: return "Unauthenticated"
|
|
|
|
|
|
|
|
|
|
renewed = headscale.renew_api_key(url, api_key)
|
2023-02-17 22:41:41 +09:00
|
|
|
LOG.warning("The below statement will be TRUE if the key has been renewed, ")
|
|
|
|
|
LOG.warning("or DOES NOT need renewal. False in all other cases")
|
|
|
|
|
LOG.warning("Renewed: "+str(renewed))
|
2023-02-06 04:58:09 +00:00
|
|
|
# The key works, let's renew it if it needs it. If it does, re-read the api_key from the file:
|
|
|
|
|
if renewed: api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
key_info = headscale.get_api_key_info(url, api_key)
|
|
|
|
|
|
|
|
|
|
# Set the current timezone and local time
|
2023-02-16 00:06:31 +09:00
|
|
|
timezone = pytz.timezone(os.environ["TZ"] if os.environ["TZ"] else "UTC")
|
2023-02-06 04:58:09 +00:00
|
|
|
|
|
|
|
|
# Format the dates for easy readability
|
|
|
|
|
expiration_parse = parser.parse(key_info['expiration'])
|
|
|
|
|
expiration_local = expiration_parse.astimezone(timezone)
|
|
|
|
|
expiration_time = str(expiration_local.strftime('%A %m/%d/%Y, %H:%M:%S'))+" "+str(timezone)
|
|
|
|
|
|
|
|
|
|
creation_parse = parser.parse(key_info['createdAt'])
|
|
|
|
|
creation_local = creation_parse.astimezone(timezone)
|
|
|
|
|
creation_time = str(creation_local.strftime('%A %m/%d/%Y, %H:%M:%S'))+" "+str(timezone)
|
|
|
|
|
|
|
|
|
|
key_info['expiration'] = expiration_time
|
|
|
|
|
key_info['createdAt'] = creation_time
|
|
|
|
|
|
|
|
|
|
message = json.dumps(key_info)
|
|
|
|
|
return message
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/save_key', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def save_key_page():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
api_key = json_response['api_key']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
file_written = headscale.set_api_key(api_key)
|
|
|
|
|
message = ''
|
|
|
|
|
|
|
|
|
|
if file_written:
|
|
|
|
|
# Re-read the file and get the new API key and test it
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
test_status = headscale.test_api_key(url, api_key)
|
|
|
|
|
if test_status == 200:
|
|
|
|
|
key_info = headscale.get_api_key_info(url, api_key)
|
|
|
|
|
expiration = key_info['expiration']
|
|
|
|
|
message = "Key: '"+api_key+"', Expiration: "+expiration
|
|
|
|
|
# If the key was saved successfully, test it:
|
|
|
|
|
return "Key saved and tested: "+message
|
|
|
|
|
else: return "Key failed testing. Check your key"
|
|
|
|
|
else: return "Key did not save properly. Check logs"
|
|
|
|
|
|
|
|
|
|
########################################################################################
|
|
|
|
|
# Machine API Endpoints
|
|
|
|
|
########################################################################################
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/update_route', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def update_route_page():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
route_id = json_response['route_id']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
current_state = json_response['current_state']
|
|
|
|
|
|
|
|
|
|
return headscale.update_route(url, api_key, route_id, current_state)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/machine_information', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def machine_information_page():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
machine_id = json_response['id']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.get_machine_info(url, api_key, machine_id)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/delete_machine', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def delete_machine_page():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
machine_id = json_response['id']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.delete_machine(url, api_key, machine_id)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/rename_machine', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def rename_machine_page():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
machine_id = json_response['id']
|
|
|
|
|
new_name = json_response['new_name']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.rename_machine(url, api_key, machine_id, new_name)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/move_user', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def move_user_page():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
machine_id = json_response['id']
|
|
|
|
|
new_user = json_response['new_user']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.move_user(url, api_key, machine_id, new_user)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/set_machine_tags', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def set_machine_tags():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
machine_id = json_response['id']
|
|
|
|
|
machine_tags = json_response['tags_list']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.set_machine_tags(url, api_key, machine_id, machine_tags)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/register_machine', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def register_machine():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
machine_key = json_response['key']
|
|
|
|
|
user = json_response['user']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return str(headscale.register_machine(url, api_key, machine_key, user))
|
|
|
|
|
|
|
|
|
|
########################################################################################
|
|
|
|
|
# User API Endpoints
|
|
|
|
|
########################################################################################
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/rename_user', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def rename_user_page():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
old_name = json_response['old_name']
|
|
|
|
|
new_name = json_response['new_name']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.rename_user(url, api_key, old_name, new_name)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/add_user', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def add_user():
|
|
|
|
|
json_response = json.dumps(request.get_json())
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.add_user(url, api_key, json_response)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/delete_user', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def delete_user():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
user_name = json_response['name']
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.delete_user(url, api_key, user_name)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/get_users', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def get_users_page():
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.get_users(url, api_key)
|
|
|
|
|
|
|
|
|
|
########################################################################################
|
|
|
|
|
# Pre-Auth Key API Endpoints
|
|
|
|
|
########################################################################################
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/add_preauth_key', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def add_preauth_key():
|
|
|
|
|
json_response = json.dumps(request.get_json())
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.add_preauth_key(url, api_key, json_response)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/expire_preauth_key', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def expire_preauth_key():
|
|
|
|
|
json_response = json.dumps(request.get_json())
|
|
|
|
|
url = headscale.get_url()
|
|
|
|
|
api_key = headscale.get_api_key()
|
|
|
|
|
|
|
|
|
|
return headscale.expire_preauth_key(url, api_key, json_response)
|
|
|
|
|
|
2023-02-17 19:58:50 +09:00
|
|
|
@app.route('/api/build_preauthkey_table', methods=['POST'])
|
2023-02-20 19:12:47 +09:00
|
|
|
@auth.oidc_auth('default')
|
2023-02-06 04:58:09 +00:00
|
|
|
def build_preauth_key_table():
|
|
|
|
|
json_response = request.get_json()
|
|
|
|
|
user_name = json_response['name']
|
|
|
|
|
|
|
|
|
|
return renderer.build_preauth_key_table(user_name)
|
|
|
|
|
|
|
|
|
|
########################################################################################
|
|
|
|
|
# Main thread
|
|
|
|
|
########################################################################################
|
2023-02-17 17:37:05 +09:00
|
|
|
if __name__ == '__main__':
|
2023-02-17 17:01:23 +09:00
|
|
|
app.run(host="0.0.0.0", debug=DEBUG_STATE)
|