Skip to content

Commit

Permalink
PyBlack codebase for future PR diffs (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
LaikaN57 authored Jun 15, 2022
1 parent 2b150ec commit 4eff6d4
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 186 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ name: "CodeQL"

on:
push:
branches: [ master ]
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
branches: [ main ]
schedule:
- cron: '21 3 * * 6'

Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
SHELL=/bin/bash
SHA1 := $(shell git rev-parse --short HEAD)

DOCKER_IMAGE ?= gogo
Expand Down Expand Up @@ -42,9 +41,9 @@ test: stop

venv:
@echo "Creating and updating venv."
@python3.6 -m venv .venv
@python3 -m venv .venv
@if [ "$$(cat resources/requirements.txt | sort)" != "$$(.venv/bin/pip freeze)" ]; then \
.venv/bin/pip install -r resources/requirements.txt; \
.venv/bin/pip install -Ur resources/requirements.txt; \
fi

# Database.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Built with Flask, Python 3.6, with Postgres and Google OAuth.

Uses docker.

Run `make postgres` and `make psql-populate` to initialize the database first.
Run `make db` to initialize the database first.

OAuth is required. Secrets can be provided either by direct environment variables or by KMS blobs in environment variables. If using KMS, you'll need to be authenticated to AWS to decrypt the blobs. `~/.aws` is volume mounted.

Expand Down Expand Up @@ -57,10 +57,10 @@ OAuth: One of Built-In Google OAuth or Header-Based Auth must be used.
| `GOOGLE_CLIENT_ID` | Your Google App ID. |
| `GOOGLE_CLIENT_SECRET` | Your Google Client Secret. |
| `GOOGLE_CLIENT_SECRET_KMS_BLOB` | Alternative to `GOOGLE_CLIENT_SECRET` - KMS Encrypted Google Client Secret. |
| `AWS_DEFAULT_REGION` | Will be used to determine the AWS region in which to decrypt `*_KMS_BLOB` secrets. |
| `HOSTED_DOMAIN` | The email domain to use for Google accounts, like 'nextdoor.com'. |
| `SESSION_SECRET_KEY` | The secret key to encrypt the session cookie with. |
| `SESSION_SECRET_KEY_KMS_BLOB` | Alternative to `SESSION_SECRET_KEY` - KMS Encrypted Secret Key. |
| `AWS_DEFAULT_REGION` | Will be used to determine the AWS region in which to decrypt `*_KMS_BLOB` secrets. |

### If using Header-Based Auth:

Expand Down
53 changes: 33 additions & 20 deletions src/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

from flask import g, Flask
from flask import Flask, g
from werkzeug.contrib.fixers import ProxyFix
from werkzeug.routing import BaseConverter

Expand All @@ -9,15 +9,19 @@
import search
from models import db

app = Flask('gogo', template_folder='../templates', static_url_path='/static',
static_folder='../static')
app = Flask(
"gogo",
template_folder="../templates",
static_url_path="/static",
static_folder="../static",
)

app.config.from_object(os.environ['APP_SETTINGS'])
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config.from_object(os.environ["APP_SETTINGS"])
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URI']
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URI"]

if app.config['BEHIND_PROXY']:
if app.config["BEHIND_PROXY"]:
app.wsgi_app = ProxyFix(app.wsgi_app)


Expand All @@ -27,29 +31,38 @@ def __init__(self, url_map, *items):
self.regex = items[0]


app.url_map.converters['regex'] = RegexConverter
app.url_map.converters["regex"] = RegexConverter

if app.config['USE_GOOGLE_AUTH']:
if app.config["USE_GOOGLE_AUTH"]:
# If using Google Auth, the session cookie is the source of truth, so it should be encrypted.
app.secret_key = os.getenv('SESSION_SECRET_KEY')
app.secret_key = os.getenv("SESSION_SECRET_KEY")
# Register OAuth2 Callback URL for Google Auth.
app.add_url_rule('/oauth2/callback', view_func=auth.OAuth2Callback.as_view('oauth2_callback'))
app.add_url_rule(
"/oauth2/callback", view_func=auth.OAuth2Callback.as_view("oauth2_callback")
)

app.add_url_rule('/healthz', view_func=gogo.Healthz.as_view('healthz'))
app.add_url_rule("/healthz", view_func=gogo.Healthz.as_view("healthz"))

app.add_url_rule('/', view_func=gogo.DashboardView.as_view('dashboard'))
app.add_url_rule('/_list', view_func=gogo.ListView.as_view('list'))
app.add_url_rule('/_create', view_func=gogo.CreateShortcutView.as_view('create_shortcut'))
app.add_url_rule('/_delete', view_func=gogo.DeleteShortcutView.as_view('delete_shortcut'))
app.add_url_rule('/_edit', view_func=gogo.EditShortcutView.as_view('edit_shortcut'))
app.add_url_rule('/<regex(".+"):name>', view_func=gogo.ShortcutRedirectView.as_view('shortcut_redirect'))
app.add_url_rule("/", view_func=gogo.DashboardView.as_view("dashboard"))
app.add_url_rule("/_list", view_func=gogo.ListView.as_view("list"))
app.add_url_rule(
"/_create", view_func=gogo.CreateShortcutView.as_view("create_shortcut")
)
app.add_url_rule(
"/_delete", view_func=gogo.DeleteShortcutView.as_view("delete_shortcut")
)
app.add_url_rule("/_edit", view_func=gogo.EditShortcutView.as_view("edit_shortcut"))
app.add_url_rule(
'/<regex(".+"):name>',
view_func=gogo.ShortcutRedirectView.as_view("shortcut_redirect"),
)

app.add_url_rule('/_ajax/search', view_func=search.SearchView.as_view('search'))
app.add_url_rule("/_ajax/search", view_func=search.SearchView.as_view("search"))


db.init_app(app)

if __name__ == '__main__':
if __name__ == "__main__":
db.init_app(app)
auth.init_app(app)
app.run()
60 changes: 31 additions & 29 deletions src/auth.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
from functools import wraps
import httplib2

import flask
from flask.views import MethodView
import httplib2
from apiclient import discovery
from flask.views import MethodView
from oauth2client import client

flow = None


def init_app(app):
if app.config['USE_GOOGLE_AUTH']:
if app.config["USE_GOOGLE_AUTH"]:
global flow
flow = client.flow_from_clientsecrets(
'/app/resources/client_secrets.json',
scope=['https://www.googleapis.com/auth/userinfo.email'],
redirect_uri=app.config['REDIRECT_URI'])
flow.user_agent = 'Go Link Shortener'
"/app/resources/client_secrets.json",
scope=["https://www.googleapis.com/auth/userinfo.email"],
redirect_uri=app.config["REDIRECT_URI"],
)
flow.user_agent = "Go Link Shortener"


class NoLoginSetupConfigured(Exception):
Expand All @@ -26,23 +27,23 @@ class NoLoginSetupConfigured(Exception):
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if flask.current_app.config['SKIP_AUTH']:
if flask.current_app.config["SKIP_AUTH"]:
return f(*args, **kwargs)
elif flask.current_app.config['USE_HEADER_AUTH']:
elif flask.current_app.config["USE_HEADER_AUTH"]:
# Header login flow.
current_user = get_current_user_from_header()
if current_user is None:
return 'Unauthorized', 401
return "Unauthorized", 401
return f(*args, **kwargs)
elif flask.current_app.config['USE_GOOGLE_AUTH']:
elif flask.current_app.config["USE_GOOGLE_AUTH"]:
# Google login flow.
current_user = get_current_user_from_session()
if current_user is None:
# Redirect to oauth.
flask.session['after_auth'] = flask.request.url
flask.session["after_auth"] = flask.request.url
return flask.redirect(flow.step1_get_authorize_url())
if 'after_auth' in flask.session:
return flask.redirect(flask.session.pop('after_auth'))
if "after_auth" in flask.session:
return flask.redirect(flask.session.pop("after_auth"))
else:
raise NoLoginSetupConfigured
return f(*args, **kwargs)
Expand All @@ -54,41 +55,42 @@ class OAuth2Callback(MethodView):
"""Google OAuth2 Callback."""

def get(self):
code = flask.request.args.get('code')
code = flask.request.args.get("code")
if code is None:
return flask.redirect(flow.step1_get_authorize_url())
credentials = flow.step2_exchange(code)
try:
flask.session['user'] = query_user(
credentials, flask.current_app.config['HOSTED_DOMAIN'])
flask.session["user"] = query_user(
credentials, flask.current_app.config["HOSTED_DOMAIN"]
)
except ValueError:
flask.session.pop('after_auth')
return 'Unauthorized', 401
return flask.redirect('/')
flask.session.pop("after_auth")
return "Unauthorized", 401
return flask.redirect("/")


def query_user(credentials, hosted_domain):
http = credentials.authorize(httplib2.Http())
service = discovery.build('oauth2', 'v2', http=http)
service = discovery.build("oauth2", "v2", http=http)
result = service.userinfo().get().execute()
email = result['email']
if f'@{hosted_domain}' not in email:
raise ValueError(f'Must be a {hosted_domain} domain.')
return email.split(f'@{hosted_domain}')[0]
email = result["email"]
if f"@{hosted_domain}" not in email:
raise ValueError(f"Must be a {hosted_domain} domain.")
return email.split(f"@{hosted_domain}")[0]


def get_current_user():
if flask.current_app.config['USE_HEADER_AUTH']:
if flask.current_app.config["USE_HEADER_AUTH"]:
return get_current_user_from_header()
elif flask.current_app.config['USE_GOOGLE_AUTH']:
elif flask.current_app.config["USE_GOOGLE_AUTH"]:
return get_current_user_from_session()
# Shouldn't get here.
return None


def get_current_user_from_header():
return flask.request.headers.get(flask.current_app.config['AUTH_HEADER_NAME'])
return flask.request.headers.get(flask.current_app.config["AUTH_HEADER_NAME"])


def get_current_user_from_session():
return flask.session.get('user')
return flask.session.get("user")
Loading

0 comments on commit 4eff6d4

Please sign in to comment.