diff --git a/command.py b/command.py index f22ab74..4d29eba 100644 --- a/command.py +++ b/command.py @@ -65,7 +65,7 @@ def register_all_commands(bot): bot.register_command(constants.commands('delete_from_library'), cmd_delete_from_library) bot.register_command(constants.commands('drop_database'), cmd_drop_database, no_partial_match=True) bot.register_command(constants.commands('rescan'), cmd_refresh_cache, no_partial_match=True) - + bot.register_command(constants.commands('requests_webinterface_access'), cmd_web_access) # Just for debug use bot.register_command('rtrms', cmd_real_time_rms, True) #bot.register_command('loop', cmd_loop_state, True) @@ -1179,6 +1179,14 @@ def cmd_refresh_cache(bot, user, text, command, parameter): bot.mumble.users[text.actor].send_text_message(constants.strings('not_admin')) +def cmd_web_access(bot, user, text, command, parameter): + import secrets + import datetime + import json + token = secrets.token_urlsafe(5) + var.db.set("user", user, json.dumps({'token': token, 'datetime': str(datetime.datetime.now()), 'IP':''})) + bot.send_msg(constants.strings('webpage_token',token=token), text) + # Just for debug use def cmd_real_time_rms(bot, user, text, command, parameter): bot._display_rms = not bot._display_rms diff --git a/configuration.default.ini b/configuration.default.ini index 75c299d..24ff1e5 100644 --- a/configuration.default.ini +++ b/configuration.default.ini @@ -101,6 +101,10 @@ require_auth = False user = password = +# Set this option to match mumble user with token on flask and add a password to encrypt/sign cookies +flask_secret = ChangeThisPassword +match_mumble_user = False + [debug] # Set ffmpeg to True if you want to display DEBUG level log of ffmpeg. ffmpeg = False @@ -111,8 +115,7 @@ mumbleConnection = False [radio] ponyville = http://192.99.131.205:8000/stream.mp3 "Here a command of !radio comment" luna = http://radio.ponyvillelive.com:8002/stream "calm and orchestra music" -radiobrony = http://62.210.138.34:8000/live "Borny music of a friend" -celestiaradio = http://celestia.aiverse.org:8000/mp3_256 +radiobrony = http://62.210.138.34:8000/live "Brony music of a friend" jazz = http://jazz-wr04.ice.infomaniak.ch/jazz-wr04-128.mp3 "Jazz Yeah !" @@ -183,6 +186,8 @@ ducking_volume = duckv drop_database = dropdatabase rescan = rescan +requests_webinterface_access = web + [strings] current_volume = Current volume: {volume}. current_ducking_volume = Volume on ducking: {volume}. @@ -254,6 +259,7 @@ cleared_tags = Removed all tags from {song}. cleared_tags_from_all = Removed all tags from songs on the playlist. shortlist_instruction = Use !sl {indexes} to play the item you want. auto_paused = Use !play to resume music! +webpage_token= Your token to access the Bot webpage is {token}, short URL help =

Commands

Control diff --git a/configuration.example.ini b/configuration.example.ini index 3a3bd6c..72e21f9 100644 --- a/configuration.example.ini +++ b/configuration.example.ini @@ -129,6 +129,14 @@ port = 64738 #user = #password = +# Set this option to match mumble user with user on the webinterface +# It's working with an unique token an user can ask to the bot with token and to add music to the bot. +# It's also allow users to know who have add a music from the webinterface +# match_mumble_user = True + +# To use token (need session) flask need a password to encrypt/sign cookies used. !! YOU NEED TO CHANGE IT IF PREVIOUS OPTION IS TRUE!! +# flask_secret = ChangeThisPassword + # [debug] stores some debug settings. [debug] # 'ffmpeg': Set ffmpeg to True if you want to display DEBUG level log of ffmpeg. @@ -137,10 +145,8 @@ port = 64738 # [radio] is a list of default radio stations. [radio] -#ponyville = http://192.99.131.205:8000/stream.mp3 "Here a command of !radio comment" -#luna = http://radio.ponyvillelive.com:8002/stream "calm and orchestra music" -#radiobrony = http://62.210.138.34:8000/live "Borny music of a friend" -#celestiaradio = http://celestia.aiverse.org:8000/mp3_256 +# List of radio you want to have by default +# one line by entrie #jazz = http://jazz-wr04.ice.infomaniak.ch/jazz-wr04-128.mp3 "Jazz Yeah !" diff --git a/interface.py b/interface.py index 6ce5fea..99b4bda 100644 --- a/interface.py +++ b/interface.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 import sqlite3 from functools import wraps -from flask import Flask, render_template, request, redirect, send_file, Response, jsonify, abort +from flask import Flask, render_template, request, redirect, send_file, Response, jsonify, abort, session from werkzeug.utils import secure_filename import variables as var @@ -12,6 +12,7 @@ import os.path import errno from typing import Type import media +import json from media.item import dicts_to_items, dict_to_item, BaseItem from media.file import FileItem from media.url import URLItem @@ -65,7 +66,7 @@ class ReverseProxied(object): web = Flask(__name__) web.config['TEMPLATES_AUTO_RELOAD'] = True log = logging.getLogger("bot") -user = 'Remote Control' +user = 'webuser' def init_proxy(): @@ -107,6 +108,42 @@ def requires_auth(f): return decorated +def set_cookie_token(f): + @wraps(f) + def decorated(*args, **kwargs): + global log + if var.config.getboolean("webinterface", "match_mumble_user"): + users = var.db.items('user') + if users: + for user in users: + tp = json.loads(user[1]) + log.info(tp) + if tp['token'] == request.args.get('token'): + t_user = user[0] + log.info(f"web: token validated for the user: {t_user}") + session['user']=t_user + return f(*args, **kwargs) + log.info("web: Bad token used") + abort(403) + + return f(*args, **kwargs) + return decorated + + +def requires_token(f): + @wraps(f) + def decorated(*args, **kwargs): + global log, user + if var.config.getboolean("webinterface", "match_mumble_user"): + if 'user' in session: + log.debug(f"Request done by {session['user']}") + user = session['user'] + else: + abort(403) + return f(*args, **kwargs) + return decorated + + def tag_color(tag): num = hash(tag) % 8 if num == 0: @@ -153,6 +190,7 @@ def get_all_dirs(): @web.route("/", methods=['GET']) @requires_auth +@set_cookie_token def index(): while var.cache.dir_lock.locked(): time.sleep(0.1) @@ -167,6 +205,7 @@ def index(): @web.route("/playlist", methods=['GET']) @requires_auth +@requires_token def playlist(): if len(var.playlist) == 0: return ('', 204) @@ -262,6 +301,7 @@ def status(): @web.route("/post", methods=['POST']) @requires_auth +@requires_token def post(): global log @@ -480,6 +520,7 @@ def build_library_query_condition(form): @web.route("/library", methods=['POST']) @requires_auth +@requires_token def library(): global log ITEM_PER_PAGE = 10 @@ -581,6 +622,8 @@ def library(): @web.route('/upload', methods=["POST"]) +#@requires_auth missing here ? +@requires_token def upload(): global log diff --git a/mumbleBot.py b/mumbleBot.py index 8b5b53f..2c88b81 100644 --- a/mumbleBot.py +++ b/mumbleBot.py @@ -632,6 +632,7 @@ def start_web_interface(addr, port): interface.init_proxy() interface.web.env = 'development' + interface.web.secret_key = var.config.get('webinterface', 'flask_secret') interface.web.run(port=port, host=addr)