Compare commits
No commits in common. "02bf20921514fcb41b7f827bc3c2c492ba72bd64" and "236b2ebdcddd499585cc9a3786ecd0af44faacdf" have entirely different histories.
02bf209215
...
236b2ebdcd
5 changed files with 21 additions and 125 deletions
|
@ -1,7 +1,6 @@
|
||||||
from flask import render_template, redirect, request, url_for, flash, session, abort, current_app
|
from flask import render_template, redirect, request, url_for, flash, session, abort, current_app
|
||||||
from flask_login import login_required, login_user, logout_user, current_user
|
from flask_login import login_required, login_user, logout_user, current_user
|
||||||
from markupsafe import Markup, escape
|
from markupsafe import Markup, escape
|
||||||
from urllib.parse import urlencode
|
|
||||||
|
|
||||||
from . import auth
|
from . import auth
|
||||||
from .forms import LoginForm, TwoFAForm, RegistrationForm, ChangePasswordForm, PasswordResetRequestForm, PasswordResetForm
|
from .forms import LoginForm, TwoFAForm, RegistrationForm, ChangePasswordForm, PasswordResetRequestForm, PasswordResetForm
|
||||||
|
@ -13,91 +12,19 @@ from models import db, User
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import pyqrcode
|
import pyqrcode
|
||||||
|
|
||||||
@app.route('/authorize/<provider>')
|
def get_google_auth(state=None, token=None):
|
||||||
def oauth2_authorize(provider):
|
if token:
|
||||||
if not current_user.is_anonymous:
|
return OAuth2Session(current_app.config['CLIENT_ID'], token=token)
|
||||||
return redirect(url_for('index'))
|
if state:
|
||||||
|
return OAuth2Session(
|
||||||
provider_data = current_app.config['OAUTH2_PROVIDERS'].get(provider)
|
current_app.config['CLIENT_ID'],
|
||||||
if provider_data is None:
|
state=state,
|
||||||
abort(404)
|
redirect_uri=current_app.config['REDIRECT_URI'])
|
||||||
|
oauth = OAuth2Session(
|
||||||
# generate a random string for the state parameter
|
current_app.config['CLIENT_ID'],
|
||||||
session['oauth2_state'] = secrets.token_urlsafe(16)
|
redirect_uri=current_app.config['REDIRECT_URI'],
|
||||||
|
scope=current_app.config['SCOPE'])
|
||||||
# create a query string with all the OAuth2 parameters
|
return oauth
|
||||||
qs = urlencode({
|
|
||||||
'client_id': provider_data['client_id'],
|
|
||||||
'redirect_uri': url_for('oauth2_callback', provider=provider,
|
|
||||||
_external=True),
|
|
||||||
'response_type': 'code',
|
|
||||||
'scope': ' '.join(provider_data['scopes']),
|
|
||||||
'state': session['oauth2_state'],
|
|
||||||
})
|
|
||||||
|
|
||||||
# redirect the user to the OAuth2 provider authorization URL
|
|
||||||
return redirect(provider_data['authorize_url'] + '?' + qs)
|
|
||||||
|
|
||||||
@app.route('/callback/<provider>')
|
|
||||||
def oauth2_callback(provider):
|
|
||||||
if not current_user.is_anonymous:
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
|
|
||||||
provider_data = current_app.config['OAUTH2_PROVIDERS'].get(provider)
|
|
||||||
if provider_data is None:
|
|
||||||
abort(404)
|
|
||||||
|
|
||||||
# if there was an authentication error, flash the error messages and exit
|
|
||||||
if 'error' in request.args:
|
|
||||||
for k, v in request.args.items():
|
|
||||||
if k.startswith('error'):
|
|
||||||
flash(f'{k}: {v}')
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
|
|
||||||
# make sure that the state parameter matches the one we created in the
|
|
||||||
# authorization request
|
|
||||||
if request.args['state'] != session.get('oauth2_state'):
|
|
||||||
abort(401)
|
|
||||||
|
|
||||||
# make sure that the authorization code is present
|
|
||||||
if 'code' not in request.args:
|
|
||||||
abort(401)
|
|
||||||
|
|
||||||
# exchange the authorization code for an access token
|
|
||||||
response = requests.post(provider_data['token_url'], data={
|
|
||||||
'client_id': provider_data['client_id'],
|
|
||||||
'client_secret': provider_data['client_secret'],
|
|
||||||
'code': request.args['code'],
|
|
||||||
'grant_type': 'authorization_code',
|
|
||||||
'redirect_uri': url_for('oauth2_callback', provider=provider,
|
|
||||||
_external=True),
|
|
||||||
}, headers={'Accept': 'application/json'})
|
|
||||||
if response.status_code != 200:
|
|
||||||
abort(401)
|
|
||||||
oauth2_token = response.json().get('access_token')
|
|
||||||
if not oauth2_token:
|
|
||||||
abort(401)
|
|
||||||
|
|
||||||
# use the access token to get the user's email address
|
|
||||||
response = requests.get(provider_data['userinfo']['url'], headers={
|
|
||||||
'Authorization': 'Bearer ' + oauth2_token,
|
|
||||||
'Accept': 'application/json',
|
|
||||||
})
|
|
||||||
if response.status_code != 200:
|
|
||||||
abort(401)
|
|
||||||
email = provider_data['userinfo']['email'](response.json())
|
|
||||||
|
|
||||||
# find or create the user in the database
|
|
||||||
user = db.session.scalar(db.select(User).where(User.email == email))
|
|
||||||
if user is None:
|
|
||||||
#user = User(email=email, username=email.split('@')[0])
|
|
||||||
user = User(email=email)
|
|
||||||
db.session.add(user)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
# log the user in
|
|
||||||
login_user(user)
|
|
||||||
return redirect(url_for('index'))
|
|
||||||
|
|
||||||
@auth.before_app_request
|
@auth.before_app_request
|
||||||
def before_request():
|
def before_request():
|
||||||
|
|
|
@ -20,32 +20,3 @@ class Config(object):
|
||||||
MAIL_USE_TLS = f"{os.getenv('MAIL_USE_TLS')}"
|
MAIL_USE_TLS = f"{os.getenv('MAIL_USE_TLS')}"
|
||||||
ADMIN_MAIL = f"{os.getenv('ADMIN_MAIL')}"
|
ADMIN_MAIL = f"{os.getenv('ADMIN_MAIL')}"
|
||||||
ITEMS_PER_PAGE = f"{os.getenv('ITEMS_PER_PAGE')}"
|
ITEMS_PER_PAGE = f"{os.getenv('ITEMS_PER_PAGE')}"
|
||||||
OAUTH2_PROVIDERS = {
|
|
||||||
# Google OAuth 2.0 documentation:
|
|
||||||
# https://developers.google.com/identity/protocols/oauth2/web-server#httprest
|
|
||||||
'google': {
|
|
||||||
'client_id': os.environ.get('GOOGLE_CLIENT_ID'),
|
|
||||||
'client_secret': os.environ.get('GOOGLE_CLIENT_SECRET'),
|
|
||||||
'authorize_url': 'https://accounts.google.com/o/oauth2/auth',
|
|
||||||
'token_url': 'https://accounts.google.com/o/oauth2/token',
|
|
||||||
'userinfo': {
|
|
||||||
'url': 'https://www.googleapis.com/oauth2/v3/userinfo',
|
|
||||||
'email': lambda json: json['email'],
|
|
||||||
},
|
|
||||||
'scopes': ['https://www.googleapis.com/auth/userinfo.email'],
|
|
||||||
},
|
|
||||||
|
|
||||||
# GitHub OAuth 2.0 documentation:
|
|
||||||
# https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
|
|
||||||
'github': {
|
|
||||||
'client_id': os.environ.get('GITHUB_CLIENT_ID'),
|
|
||||||
'client_secret': os.environ.get('GITHUB_CLIENT_SECRET'),
|
|
||||||
'authorize_url': 'https://github.com/login/oauth/authorize',
|
|
||||||
'token_url': 'https://github.com/login/oauth/access_token',
|
|
||||||
'userinfo': {
|
|
||||||
'url': 'https://api.github.com/user/emails',
|
|
||||||
'email': lambda json: json[0]['email'],
|
|
||||||
},
|
|
||||||
'scopes': ['user:email'],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{% import "bootstrap/fixes.html" as fixes %}
|
{% import "bootstrap/fixes.html" as fixes %}
|
||||||
{% import "bootstrap/utils.html" as util %}
|
{% import "bootstrap/utils.html" as util %}
|
||||||
|
|
||||||
{% block title %}ForestNet{% endblock %}
|
{% block title %}Cloud Builder - Datapoint.bg{% endblock %}
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
|
|
|
@ -39,7 +39,13 @@
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#newsmenu').load('https://forest.deflax.net/news/latest');
|
$('#newsmenu').load('https://www.datapoint.bg/news/latest');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#livesupport').load('https://www.datapoint.bg/kiwi/');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -69,8 +75,6 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|
||||||
<br /><br /><br />
|
<br /><br /><br />
|
||||||
|
|
||||||
{% if not current_user.is_authenticated %}
|
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<form class="register-form" actoion="{{ url_for('auth.register') }}" method="POST">
|
<form class="register-form" actoion="{{ url_for('auth.register') }}" method="POST">
|
||||||
<input type="text" placeholder="name"/>
|
<input type="text" placeholder="name"/>
|
||||||
|
@ -87,7 +91,6 @@
|
||||||
<p class="message">Not registered? <a href="#">Create an account</a></p>
|
<p class="message">Not registered? <a href="#">Create an account</a></p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,11 +14,6 @@ POSTGRES_DB=forest_prod
|
||||||
PGADMIN_DEFAULT_EMAIL=mail@example.com
|
PGADMIN_DEFAULT_EMAIL=mail@example.com
|
||||||
PGADMIN_DEFAULT_PASSWORD=hackme
|
PGADMIN_DEFAULT_PASSWORD=hackme
|
||||||
|
|
||||||
GOOGLE_CLIENT_ID=changeme
|
|
||||||
GOOGLE_CLIENT_SECRET=changeme
|
|
||||||
GITHUB_CLIENT_ID=changeme
|
|
||||||
GITHUB_CLIENT_SECRET=changeme
|
|
||||||
|
|
||||||
MAIL_SENDER=mail@example.com
|
MAIL_SENDER=mail@example.com
|
||||||
MAIL_SUBJECT_PREFIX=ForestNet
|
MAIL_SUBJECT_PREFIX=ForestNet
|
||||||
MAIL_SERVER=smtp.gmail.com
|
MAIL_SERVER=smtp.gmail.com
|
||||||
|
|
Loading…
Reference in a new issue