Merge pull request #126 from GSA/open-api

Add OpenAPI spec for selected api endpoints
This commit is contained in:
Ryan Ahearn
2022-11-30 13:30:26 -05:00
committed by GitHub
11 changed files with 626 additions and 10 deletions

View File

@@ -134,6 +134,7 @@ def register_blueprint(application):
)
from app.billing.rest import billing_blueprint
from app.complaint.complaint_rest import complaint_blueprint
from app.docs import docs as docs_blueprint
from app.email_branding.rest import email_branding_blueprint
from app.events.rest import events as events_blueprint
from app.inbound_number.rest import inbound_number_blueprint
@@ -193,6 +194,9 @@ def register_blueprint(application):
status_blueprint.before_request(requires_no_auth)
application.register_blueprint(status_blueprint)
docs_blueprint.before_request(requires_no_auth)
application.register_blueprint(docs_blueprint)
# delivery receipts
ses_callback_blueprint.before_request(requires_no_auth)
application.register_blueprint(ses_callback_blueprint)

View File

@@ -132,8 +132,9 @@ def _decode_jwt_token(auth_token, api_keys, service_id=None):
try:
decode_jwt_token(auth_token, api_key.secret)
except TokenExpiredError:
err_msg = "Error: Your system clock must be accurate to within 30 seconds"
raise AuthError(err_msg, 403, service_id=service_id, api_key_id=api_key.id)
if not current_app.config.get('ALLOW_EXPIRED_API_TOKEN', False):
err_msg = "Error: Your system clock must be accurate to within 30 seconds"
raise AuthError(err_msg, 403, service_id=service_id, api_key_id=api_key.id)
except TokenAlgorithmError:
err_msg = "Invalid token: algorithm used is not HS256"
raise AuthError(err_msg, 403, service_id=service_id, api_key_id=api_key.id)

View File

@@ -1,14 +1,15 @@
import csv
import functools
import itertools
import os
import uuid
from datetime import datetime, timedelta
from os import getenv
import click
import flask
from click_datetime import Datetime as click_dt
from flask import current_app, json
from notifications_python_client.authentication import create_jwt_token
from notifications_utils.recipients import RecipientCSV
from notifications_utils.statsd_decorators import statsd
from notifications_utils.template import SMSMessageTemplate
@@ -86,7 +87,7 @@ class notify_command:
# in the test environment the app context is already provided and having
# another will lead to the test db connection being closed prematurely
if os.getenv('NOTIFY_ENVIRONMENT', '') != 'test':
if getenv('NOTIFY_ENVIRONMENT', '') != 'test':
# with_appcontext ensures the config is loaded, db connected, etc.
decorators.insert(0, flask.cli.with_appcontext)
@@ -111,7 +112,7 @@ def purge_functional_test_data(user_email_prefix):
users, services, etc. Give an email prefix. Probably "notify-tests-preview".
"""
if os.getenv('NOTIFY_ENVIRONMENT', '') not in ['development', 'test']:
if getenv('NOTIFY_ENVIRONMENT', '') not in ['development', 'test']:
current_app.logger.error('Can only be run in development')
return
@@ -726,7 +727,7 @@ def validate_mobile(ctx, param, value):
@click.option('-s', '--state', default="active")
@click.option('-d', '--admin', default=False, type=bool)
def create_test_user(name, email, mobile_number, password, auth_type, state, admin):
if os.getenv('NOTIFY_ENVIRONMENT', '') not in ['development', 'test']:
if getenv('NOTIFY_ENVIRONMENT', '') not in ['development', 'test']:
current_app.logger.error('Can only be run in development')
return
@@ -746,3 +747,22 @@ def create_test_user(name, email, mobile_number, password, auth_type, state, adm
except IntegrityError:
print("duplicate user", user.name)
db.session.rollback()
@notify_command(name='create-admin-jwt')
def create_admin_jwt():
if getenv('NOTIFY_ENVIRONMENT', '') != 'development':
current_app.logger.error('Can only be run in development')
return
print(create_jwt_token(current_app.config['SECRET_KEY'], current_app.config['ADMIN_CLIENT_ID']))
@notify_command(name='create-user-jwt')
@click.option('-t', '--token', required=True, prompt=False)
def create_user_jwt(token):
if getenv('NOTIFY_ENVIRONMENT', '') != 'development':
current_app.logger.error('Can only be run in development')
return
service_id = token[-73:-37]
api_key = token[-36:]
print(create_jwt_token(api_key, service_id))

View File

@@ -80,6 +80,7 @@ class Config(object):
('{"%s":["%s"]}' % (ADMIN_CLIENT_ID, getenv('ADMIN_CLIENT_SECRET')))
)
)
ALLOW_EXPIRED_API_TOKEN = False
# encyption secret/salt
SECRET_KEY = getenv('SECRET_KEY')
DANGEROUS_SALT = getenv('DANGEROUS_SALT')
@@ -367,6 +368,7 @@ class Development(Config):
DANGEROUS_SALT = 'dev-notify-salt'
SECRET_KEY = 'dev-notify-secret-key' # nosec B105 - this is only used in development
INTERNAL_CLIENT_API_KEYS = {Config.ADMIN_CLIENT_ID: ['dev-notify-secret-key']}
ALLOW_EXPIRED_API_TOKEN = getenv('ALLOW_EXPIRED_API_TOKEN', '0') == '1'
class Test(Development):

11
app/docs/__init__.py Normal file
View File

@@ -0,0 +1,11 @@
from os import path
from flask import Blueprint, current_app, send_file
docs = Blueprint('docs', __name__, url_prefix='/docs')
@docs.route('/openapi.yml', methods=['GET'])
def send_openapi():
openapi_schema = path.join(current_app.root_path, '../docs/openapi.yml')
return send_file(openapi_schema, mimetype='text/yaml'), 200