Skip to content

Commit

Permalink
secure admin panel with basic auth
Browse files Browse the repository at this point in the history
  • Loading branch information
F-Node-Karlsruhe committed Jul 1, 2021
1 parent c548b6d commit 5c303cd
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 16 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Put the following code into the `post.hbs` of your ghost theme and replace `{{gh
```
Example file [ghost-integration/post.hbs](ghost-integration/post.hbs)

# Author address setup
## Author address setup
You can set `AUTHOR_ADDRESSES=true` in your `.env` file to allow authors to get paid individually.
If so, the authors can paste in their current IOTA address in the `location` field in their ghost admin panel.
When an article is requested, the ghost API is fetched to get the latest address. If there is none, there is a fallback to the last address used or if this is not the case, the default address specified in the `.env` file is used.
Expand All @@ -133,3 +133,7 @@ As an IOTA address is quite ugly in the location field of the author, you can mo
</iota-button></span>
{{/if}}
```

## Author address setup
You can set `ADMIN_PANEL=true` in your `.env` file to enable the admin panel on the `admin` path.
The admin panel is secured using basic authentication which credential are specified in the `.env` file as well.
53 changes: 45 additions & 8 deletions admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
from flask_admin import Admin
from flask_admin import Admin, AdminIndexView, BaseView, expose
from flask_basicauth import BasicAuth
from flask_admin.contrib.sqla import ModelView
from database.db import db
from database.models.access import Access
from database.models.authors import Author
from database.models.sessions import Session
from database.models.slugs import Slug

admin = Admin()

class PkModelView(ModelView):
column_display_pk = True
class AuthenticatedAdminView(AdminIndexView):

def is_accessible(self):
if not auth.authenticate():
return False
else:
return True

def inaccessible_callback(self, name, **kwargs):
return auth.challenge()

super(AdminIndexView)


class AuthenticatedModelView(ModelView):
def is_accessible(self):
if not auth.authenticate():
return False
else:
return True

def inaccessible_callback(self, name, **kwargs):
return auth.challenge()

super(ModelView)

admin.add_view(PkModelView(Access, db.session))
admin.add_view(PkModelView(Author, db.session))
admin.add_view(PkModelView(Session, db.session))
admin.add_view(PkModelView(Slug, db.session))
class HomeView(BaseView):
@expose('/')
def index(self):
arg1 = 'Hello'
return self.render('admin/myhome.html', arg1=arg1)


class PkModelView(AuthenticatedModelView):
column_display_pk = True

super(AuthenticatedModelView)


admin = Admin(index_view=AuthenticatedAdminView(), template_mode='bootstrap4')
auth = BasicAuth()

admin.add_view(PkModelView(Access, db.session, name='Access', category='Database'))
admin.add_view(PkModelView(Author, db.session, name='Authors', category='Database'))
admin.add_view(PkModelView(Session, db.session, name='Sessions', category='Database'))
admin.add_view(PkModelView(Slug, db.session, name='Posts', category='Database'))
14 changes: 12 additions & 2 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
import secrets
from utils.hash import hash_user_token
from services.ghost_api import get_post, get_post_payment
from config import SECRET_KEY, DATABASE_LOCATION, SESSION_LIFETIME, URL, ADMIN_PANEL
from config import (SECRET_KEY,
DATABASE_LOCATION,
SESSION_LIFETIME,
URL, ADMIN_PANEL,
ADMIN_USER,
ADMIN_PW)
import os
from services.iota import Listener
from datetime import datetime, timedelta
Expand All @@ -14,7 +19,7 @@
send_from_directory,
redirect)
from database.db import db
from admin import admin
from admin import admin, auth
from database.operations import (check_slug,
get_access,
get_slug_data,
Expand All @@ -31,6 +36,10 @@

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

app.config['BASIC_AUTH_USERNAME'] = ADMIN_USER

app.config['BASIC_AUTH_PASSWORD'] = ADMIN_PW

# create web socket for async communication
socketio = SocketIO(app, async_mode='threading', cors_allowed_origins="*")

Expand Down Expand Up @@ -137,6 +146,7 @@ def await_payment(data):

if ADMIN_PANEL:
admin.init_app(app)
auth.init_app(app)

socketio.start_background_task(iota_listener.start, app)
socketio.run(app, host='0.0.0.0')
Expand Down
6 changes: 5 additions & 1 deletion config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@

GHOST_ADMIN_KEY = getenv('GHOST_ADMIN_KEY')

ADMIN_PANEL = getenv('ADMIN_PANEL') == 'true'
ADMIN_PANEL = getenv('ADMIN_PANEL') == 'true'

ADMIN_USER = getenv('ADMIN_USER')

ADMIN_PW = getenv('ADMIN_PW')
1 change: 1 addition & 0 deletions database/models/authors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

class Author(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
iota_address = db.Column(db.String(64), default=DEFAULT_IOTA_ADDRESS)
6 changes: 3 additions & 3 deletions database/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def check_slug(slug, iota_listener):
# add author if not existant
if AUTHOR_ADDRESSES and not __exists(Author, post_data['primary_author']['id']):

add_author(post_data['primary_author']['id'], post_data['primary_author']['location'])
add_author(post_data['primary_author']['id'], post_data['primary_author']['name'], post_data['primary_author']['location'])

iota_listener.add_listening_address(post_data['primary_author']['location'])

Expand Down Expand Up @@ -114,9 +114,9 @@ def add_access(user_token_hash, exp_date=None):
db.session.commit()


def add_author(author_id, iota_address):
def add_author(author_id, name, iota_address):

author = Author(id=author_id, iota_address=iota_address)
author = Author(id=author_id, name=name, iota_address=iota_address)

db.session.add(author)
db.session.commit()
Expand Down
4 changes: 4 additions & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ AUTHOR_ADDRESSES=false

# allow admin access via flask-admin
ADMIN_PANEL=false

ADMIN_USER=admin

ADMIN_PW=secret_password
3 changes: 2 additions & 1 deletion services/iota.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ def on_mqtt_event(self, event):


def start(self, app):
self.client.subscribe_topics(get_iota_listening_addresses(), self.on_mqtt_event)
with app.app_context():
self.client.subscribe_topics(get_iota_listening_addresses(), self.on_mqtt_event)
self.mqtt_worker(app)


Expand Down
14 changes: 14 additions & 0 deletions templates/admin/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% extends 'admin/master.html' %}

{% block body %}
{{ super() }}
<div style="margin: auto; text-align: center;">
<img src="{{ url_for('static', filename='logo.png') }}" style="max-width: 200px;"/>
<h2>Ghost IOTA Pay</h2>
<h3>Admin Panel</h3>
<p>Pay per content gateway for <a href="https://ghost.org/">Ghost Blogs</a></p>
<div style="margin-top: 50px;">
<p><a href="https://github.com/F-Node-Karlsruhe/ghost-iota-pay"><img width="16" src="{{ url_for('static', filename='github.png') }}"/></a></p>
</div>
</div>
{% endblock body %}

0 comments on commit 5c303cd

Please sign in to comment.