Loading config.default.yml +9 −0 Original line number Diff line number Diff line Loading @@ -67,3 +67,12 @@ show_github_link: false # Integer: How many items to show per page in the admin interface # Default: 20 admin_links_per_page: 20 # List: IP ranges that are allowed to create new links. Everyone is allowed if unset. # Example: # allowed_ip_ranges: # - 127.0.0.1 # - 130.89.0.0/16 # - 2001:67c:2564::/48 # Default: unset allowed_ip_ranges: liteshort.py +27 −6 Original line number Diff line number Diff line Loading @@ -2,9 +2,10 @@ # This file is part of liteshort by 132ikl # This software is license under the MIT license. It should be included in your copy of this software. # A copy of the MIT license can be obtained at https://mit-license.org/ import ipaddress from flask import Flask, current_app, flash, g, jsonify, make_response, redirect, render_template, request, \ send_from_directory, url_for, session send_from_directory, url_for, session, abort import bcrypt import os import random Loading Loading @@ -157,6 +158,19 @@ def nested_list_to_dict(l): def response(rq, result, error_msg="Error: Unknown error"): # Only allow responses to whitelisted IP ranges whitelist_disabled = 'allowed_ip_ranges' not in app.config or app.config['allowed_ip_ranges'] is None if not whitelist_disabled: is_allowed = False for range in app.config['allowed_ip_ranges']: network = ipaddress.ip_network(range) remote = ipaddress.ip_address(request.remote_addr) if remote in network: is_allowed = True if not is_allowed: abort(403) if rq.form.get('api') and not rq.form.get('format') == 'json': return "Format type HTML (default) not support for API" # Future-proof for non-json return types if rq.form.get('format') == 'json': Loading Loading @@ -234,6 +248,11 @@ app.secret_key = app.config['secret_key'] app.config['SERVER_NAME'] = app.config['site_domain'] @app.errorhandler(403) def access_denied(e): return render_template("403_access_denied.html") @app.route('/favicon.ico', subdomain=app.config['subdomain']) def favicon(): return send_from_directory(os.path.join(app.root_path, 'static'), Loading Loading @@ -323,7 +342,8 @@ def main_post(): @app.route('/login', methods=['POST']) def login(): if 'admin_hashed_password' not in app.config or app.config['admin_hashed_password'] is None: if ('admin_hashed_password' not in app.config or app.config['admin_hashed_password'] is None) and ( 'admin_password' not in app.config or app.config['admin_password'] is None): raise AssertionError("Login is disabled.") if authenticate(request.form['username'], request.form['password']): Loading Loading @@ -361,12 +381,13 @@ def admin(): page = request.args.get('page', '1') try: page = int(page) except ValueError: page = 1 if page_count != 0: if page > page_count: return make_response(redirect(url_for('admin')+"?page="+str(page_count))) if page < 1: return make_response(redirect(url_for('admin')+"?page=1")) except ValueError: page = 1 urls = list_shortlinks_page(page, app.config['admin_links_per_page']) Loading templates/403_access_denied.html 0 → 100644 +73 −0 Original line number Diff line number Diff line <!-- Copyright (c) 2019 Steven Spangler <132@ikl.sh>, Kevin Alberts <kevin@kevinalberts.nl> This file is part of liteshort by 132ikl This software is license under the MIT license. It should be included in your copy of this software. A copy of the MIT license can be obtained at https://mit-license.org/ --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ config.site_name }}</title> <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"> <link rel="stylesheet" href="{{ url_for('static', filename='ia.css') }}"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id="top"> <div id="header"> <div id="logo" class="drop-shadow"> <a href="{{ url_for('main') }}"> <img src="{{ url_for('static', filename='ictsv-logo-white.svg') }}" alt="logo"> </a> </div> <div id="title" class="drop-shadow"> <a href="{{ url_for('main') }}"> I.C.T.S.V. URL Shortener </a> </div> </div> </div> <div id="middle"> <div id="content"> <div class="clearfix"></div> <div id="box" class="align-self-center col-xl-4 col-lg-4 col-md-6 col-sm-10 col-xs-12"> <div class="form"> <h3 id="box-title">Access Denied</h3> <p> Sorry, but you can only create new links on this URL shortener if you are connected to the University of Twente network. </p> <p> Please try again later if you are on that network again, or please activate a VPN connection to create a new link. </p> <p> If you think this is a mistake, please contact the Website committee of Inter-Actief. </p> </div> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} {% if category == 'error' %} <div class="error"> ✖ {{ message }} </div> {% endif %} {% endfor %} {% endif %} {% endwith %} <p id="copyright"> <span>This URL shortening service is provided by <a href="https://inter-actief.net/">I.C.T.S.V. Inter-<i>Actief</i></a>.</span> <span>URLs may be deleted or modified by us if deemed necessary.</span> <span>No personal information is processed by this application.</span> <span> </span> <span>© <a href="https://inter-actief.net/">I.C.T.S.V. Inter-<i>Actief</i></a> and <a href="https://gitlab.ia.utwente.nl/WWW/ia-short">individual contributors</a>. Based on <a href="https://github.com/132ikl/liteshort">liteshort</a>.</span> </p> </div> </div> </div> </body> </html> Loading
config.default.yml +9 −0 Original line number Diff line number Diff line Loading @@ -67,3 +67,12 @@ show_github_link: false # Integer: How many items to show per page in the admin interface # Default: 20 admin_links_per_page: 20 # List: IP ranges that are allowed to create new links. Everyone is allowed if unset. # Example: # allowed_ip_ranges: # - 127.0.0.1 # - 130.89.0.0/16 # - 2001:67c:2564::/48 # Default: unset allowed_ip_ranges:
liteshort.py +27 −6 Original line number Diff line number Diff line Loading @@ -2,9 +2,10 @@ # This file is part of liteshort by 132ikl # This software is license under the MIT license. It should be included in your copy of this software. # A copy of the MIT license can be obtained at https://mit-license.org/ import ipaddress from flask import Flask, current_app, flash, g, jsonify, make_response, redirect, render_template, request, \ send_from_directory, url_for, session send_from_directory, url_for, session, abort import bcrypt import os import random Loading Loading @@ -157,6 +158,19 @@ def nested_list_to_dict(l): def response(rq, result, error_msg="Error: Unknown error"): # Only allow responses to whitelisted IP ranges whitelist_disabled = 'allowed_ip_ranges' not in app.config or app.config['allowed_ip_ranges'] is None if not whitelist_disabled: is_allowed = False for range in app.config['allowed_ip_ranges']: network = ipaddress.ip_network(range) remote = ipaddress.ip_address(request.remote_addr) if remote in network: is_allowed = True if not is_allowed: abort(403) if rq.form.get('api') and not rq.form.get('format') == 'json': return "Format type HTML (default) not support for API" # Future-proof for non-json return types if rq.form.get('format') == 'json': Loading Loading @@ -234,6 +248,11 @@ app.secret_key = app.config['secret_key'] app.config['SERVER_NAME'] = app.config['site_domain'] @app.errorhandler(403) def access_denied(e): return render_template("403_access_denied.html") @app.route('/favicon.ico', subdomain=app.config['subdomain']) def favicon(): return send_from_directory(os.path.join(app.root_path, 'static'), Loading Loading @@ -323,7 +342,8 @@ def main_post(): @app.route('/login', methods=['POST']) def login(): if 'admin_hashed_password' not in app.config or app.config['admin_hashed_password'] is None: if ('admin_hashed_password' not in app.config or app.config['admin_hashed_password'] is None) and ( 'admin_password' not in app.config or app.config['admin_password'] is None): raise AssertionError("Login is disabled.") if authenticate(request.form['username'], request.form['password']): Loading Loading @@ -361,12 +381,13 @@ def admin(): page = request.args.get('page', '1') try: page = int(page) except ValueError: page = 1 if page_count != 0: if page > page_count: return make_response(redirect(url_for('admin')+"?page="+str(page_count))) if page < 1: return make_response(redirect(url_for('admin')+"?page=1")) except ValueError: page = 1 urls = list_shortlinks_page(page, app.config['admin_links_per_page']) Loading
templates/403_access_denied.html 0 → 100644 +73 −0 Original line number Diff line number Diff line <!-- Copyright (c) 2019 Steven Spangler <132@ikl.sh>, Kevin Alberts <kevin@kevinalberts.nl> This file is part of liteshort by 132ikl This software is license under the MIT license. It should be included in your copy of this software. A copy of the MIT license can be obtained at https://mit-license.org/ --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{ config.site_name }}</title> <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"> <link rel="stylesheet" href="{{ url_for('static', filename='ia.css') }}"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id="top"> <div id="header"> <div id="logo" class="drop-shadow"> <a href="{{ url_for('main') }}"> <img src="{{ url_for('static', filename='ictsv-logo-white.svg') }}" alt="logo"> </a> </div> <div id="title" class="drop-shadow"> <a href="{{ url_for('main') }}"> I.C.T.S.V. URL Shortener </a> </div> </div> </div> <div id="middle"> <div id="content"> <div class="clearfix"></div> <div id="box" class="align-self-center col-xl-4 col-lg-4 col-md-6 col-sm-10 col-xs-12"> <div class="form"> <h3 id="box-title">Access Denied</h3> <p> Sorry, but you can only create new links on this URL shortener if you are connected to the University of Twente network. </p> <p> Please try again later if you are on that network again, or please activate a VPN connection to create a new link. </p> <p> If you think this is a mistake, please contact the Website committee of Inter-Actief. </p> </div> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} {% if category == 'error' %} <div class="error"> ✖ {{ message }} </div> {% endif %} {% endfor %} {% endif %} {% endwith %} <p id="copyright"> <span>This URL shortening service is provided by <a href="https://inter-actief.net/">I.C.T.S.V. Inter-<i>Actief</i></a>.</span> <span>URLs may be deleted or modified by us if deemed necessary.</span> <span>No personal information is processed by this application.</span> <span> </span> <span>© <a href="https://inter-actief.net/">I.C.T.S.V. Inter-<i>Actief</i></a> and <a href="https://gitlab.ia.utwente.nl/WWW/ia-short">individual contributors</a>. Based on <a href="https://github.com/132ikl/liteshort">liteshort</a>.</span> </p> </div> </div> </div> </body> </html>