Ditch authentication in favor of server launch option
This commit is contained in:
parent
6a92249ca2
commit
2605aa05a1
54
poetry.lock
generated
54
poetry.lock
generated
@ -25,30 +25,6 @@ dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxco
|
||||
docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
|
||||
dotenv = ["python-dotenv"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "User session management for Flask"
|
||||
name = "flask-login"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.5.0"
|
||||
|
||||
[package.dependencies]
|
||||
Flask = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Simple integration of Flask and WTForms."
|
||||
name = "flask-wtf"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.14.3"
|
||||
|
||||
[package.dependencies]
|
||||
Flask = "*"
|
||||
WTForms = "*"
|
||||
itsdangerous = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "WSGI HTTP Server for UNIX"
|
||||
@ -148,27 +124,11 @@ version = "1.0.1"
|
||||
dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
|
||||
watchdog = ["watchdog"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A flexible forms validation and rendering library for Python web development."
|
||||
name = "wtforms"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2.3.3"
|
||||
|
||||
[package.dependencies]
|
||||
MarkupSafe = "*"
|
||||
|
||||
[package.extras]
|
||||
email = ["email-validator"]
|
||||
ipaddress = ["ipaddress"]
|
||||
locale = ["Babel (>=1.3)"]
|
||||
|
||||
[extras]
|
||||
dev = ["gunicorn"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "e4930aaf62df0a261424129ab0d89af96ea4e19f80b76c7c6fbcb25c491a213d"
|
||||
content-hash = "4a6df8f74dbda5e091bc6a4f2240fa4276812f9830369848df1a5813e7a81b83"
|
||||
lock-version = "1.0"
|
||||
python-versions = "^3.8"
|
||||
|
||||
@ -181,14 +141,6 @@ flask = [
|
||||
{file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
|
||||
{file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
|
||||
]
|
||||
flask-login = [
|
||||
{file = "Flask-Login-0.5.0.tar.gz", hash = "sha256:6d33aef15b5bcead780acc339464aae8a6e28f13c90d8b1cf9de8b549d1c0b4b"},
|
||||
{file = "Flask_Login-0.5.0-py2.py3-none-any.whl", hash = "sha256:7451b5001e17837ba58945aead261ba425fdf7b4f0448777e597ddab39f4fba0"},
|
||||
]
|
||||
flask-wtf = [
|
||||
{file = "Flask-WTF-0.14.3.tar.gz", hash = "sha256:d417e3a0008b5ba583da1763e4db0f55a1269d9dd91dcc3eb3c026d3c5dbd720"},
|
||||
{file = "Flask_WTF-0.14.3-py2.py3-none-any.whl", hash = "sha256:57b3faf6fe5d6168bda0c36b0df1d05770f8e205e18332d0376ddb954d17aef2"},
|
||||
]
|
||||
gunicorn = [
|
||||
{file = "gunicorn-20.0.4-py2.py3-none-any.whl", hash = "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c"},
|
||||
{file = "gunicorn-20.0.4.tar.gz", hash = "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626"},
|
||||
@ -305,7 +257,3 @@ werkzeug = [
|
||||
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
|
||||
{file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
|
||||
]
|
||||
wtforms = [
|
||||
{file = "WTForms-2.3.3-py2.py3-none-any.whl", hash = "sha256:7b504fc724d0d1d4d5d5c114e778ec88c37ea53144683e084215eed5155ada4c"},
|
||||
{file = "WTForms-2.3.3.tar.gz", hash = "sha256:81195de0ac94fbc8368abbaf9197b88c4f3ffd6c2719b5bf5fc9da744f3d829c"},
|
||||
]
|
||||
|
@ -7,8 +7,6 @@ authors = ["Your Name <you@example.com>"]
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
flask = "^1.1.2"
|
||||
flask-login = "^0.5.0"
|
||||
flask_wtf = "^0.14.3"
|
||||
gunicorn = {version = "^20.0.4", optional = true}
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
@ -18,10 +18,6 @@ from flask import (
|
||||
safe_join,
|
||||
url_for,
|
||||
)
|
||||
from flask_login import login_user, logout_user, login_required, LoginManager, UserMixin
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import PasswordField, SubmitField
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
from redstring.library import generate_index_document, generate_default_document
|
||||
from redstring.parser import (
|
||||
@ -36,49 +32,16 @@ from redstring.parser import (
|
||||
)
|
||||
|
||||
|
||||
class Admin(UserMixin):
|
||||
def get_id(self):
|
||||
return 'admin'
|
||||
|
||||
|
||||
class LoginForm(FlaskForm):
|
||||
password = PasswordField('Password', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
CONFIG_ENVVAR = 'REDSTRING_CONFIG'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = ''.join(random.choices(string.ascii_uppercase + string.digits, k=32))
|
||||
|
||||
login_manager = LoginManager()
|
||||
login_manager.login_view = 'login'
|
||||
login_manager.init_app(app)
|
||||
|
||||
|
||||
def check_password(app, password):
|
||||
"""
|
||||
Checks if a password is correct
|
||||
"""
|
||||
password_file = app.config['password_file']
|
||||
if not os.path.isfile(password_file):
|
||||
logger.debug('Authentication failed: no password file found')
|
||||
with open(password_file) as f:
|
||||
real_password = f.read().strip()
|
||||
correct = password == real_password
|
||||
del real_password
|
||||
if correct:
|
||||
logger.debug('Authentication successful')
|
||||
else:
|
||||
logger.debug('Authentication failed: password incorrect')
|
||||
return correct
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_id):
|
||||
return Admin() if user_id == 'admin' else None
|
||||
@app.context_processor
|
||||
def inject_edit():
|
||||
return {'edit': current_app.config['edit']}
|
||||
|
||||
|
||||
@app.route('/', methods=['GET'])
|
||||
@ -102,25 +65,11 @@ def document(document_id):
|
||||
return render_template('doc.jinja', document=doc, index=False)
|
||||
|
||||
|
||||
@app.route('/login/', methods=['GET', 'POST'])
|
||||
def login():
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit() and check_password(current_app, form.password.data):
|
||||
login_user(Admin())
|
||||
return redirect(url_for('index'))
|
||||
return render_template('login.jinja', form=form)
|
||||
|
||||
|
||||
@app.route('/logout/')
|
||||
@login_required
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect(url_for('index'))
|
||||
|
||||
|
||||
@app.route('/new/', methods=['GET'])
|
||||
@login_required
|
||||
def new():
|
||||
if not current_app.config.get('edit'):
|
||||
return abort(404)
|
||||
|
||||
document_id = 'new'
|
||||
new_doc = generate_default_document(document_id)
|
||||
doc_path = safe_join(current_app.config['root'], f'{document_id}.json')
|
||||
@ -130,8 +79,10 @@ def new():
|
||||
|
||||
|
||||
@app.route('/edit/<document_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit(document_id):
|
||||
if not current_app.config.get('edit'):
|
||||
return abort(404)
|
||||
|
||||
doc_path = safe_join(current_app.config['root'], f'{document_id}.json')
|
||||
|
||||
# Check for content updates
|
||||
@ -214,7 +165,7 @@ def read_config(app, path):
|
||||
with open(path) as f:
|
||||
config = json.load(f)
|
||||
app.config['root'] = config['root']
|
||||
app.config['password_file'] = config['password_file']
|
||||
app.config['edit'] = config['edit']
|
||||
return config
|
||||
|
||||
|
||||
|
@ -38,14 +38,14 @@ window.onload = function () {
|
||||
<div id="{{ tab.name }}-page" class="tab-page{% if selected %} tab-page-selected{% endif %}">
|
||||
<table id="{{ tab.name }}-page-table" class="page-table">
|
||||
{% for tag in tab.tags %}
|
||||
{%- if not tag.options.private or current_user.is_authenticated -%}
|
||||
{%- if not tag.options.private or edit -%}
|
||||
<tr {% if tab.options.hide_names %}class="hide-tag-name"{% endif %}>
|
||||
<td>{{ tag.name }}</td>
|
||||
<td>{{ make_tag_value(tag) }}</td>
|
||||
</tr>
|
||||
{%- endif -%}
|
||||
{% for subtag in tag.subtags %}
|
||||
{%- if (not tag.options.private and not subtag.options.private) or current_user.is_authenticated -%}
|
||||
{%- if (not tag.options.private and not subtag.options.private) or edit -%}
|
||||
<tr {% if tab.options.hide_names %}class="hide-tag-name"{% endif %}>
|
||||
<td>{% if loop.last %}└{% else %}├{% endif %} {{ subtag.name }}</td>
|
||||
<td>{{ make_tag_value(subtag) }}</td>
|
||||
@ -69,18 +69,15 @@ window.onload = function () {
|
||||
{# TODO: tab.priority support #}
|
||||
{% block page_content %}
|
||||
<div id="tabs">
|
||||
{% if index and current_user.is_authenticated %}
|
||||
<div id="logout" class="tab tab-right"><a href="/logout/">logout</a></div>
|
||||
{% endif %}
|
||||
|
||||
{%- for tab in document -%}
|
||||
{%- if not tab.options.private or current_user.is_authenticated-%}
|
||||
{%- if not tab.options.private or edit-%}
|
||||
{{ make_content_tab(tab, loop.first) }}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
|
||||
{%- if not index -%}
|
||||
{% if current_user.is_authenticated %}
|
||||
{% if edit %}
|
||||
<div id="edit" class="tab tab-right"><a href="/edit/{{ document.get_tag_value('id') }}">edit</a></div>
|
||||
{% endif %}
|
||||
<div id="index" class="tab tab-right"><a href="/index/">index</a></div>
|
||||
|
@ -1,20 +0,0 @@
|
||||
{% extends 'base.jinja' %}
|
||||
|
||||
{% set page_title = 'Login' -%}
|
||||
|
||||
{% block page_content %}
|
||||
<div id="tabs">
|
||||
<div id="tab-login" class="tab tab-down">login</div>
|
||||
<div id="index" class="tab tab-right"><a href="/index/">index</a></div>
|
||||
</div>
|
||||
<div class="tab-page tab-page-selected">
|
||||
<form action="" method="post" novalidate>
|
||||
{{ form.hidden_tag() }}
|
||||
<p>{{ form.password.label }}<br>{{ form.password(size=32) }}
|
||||
{% for error in form.password.errors %}
|
||||
<br><span style="color: #ff0000">{{ error }}</span>
|
||||
{% endfor %}</p>
|
||||
<p>{{ form.submit() }}</p>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock page_content %}
|
Loading…
Reference in New Issue
Block a user