diff --git a/api/app/__init__.py b/api/app/__init__.py index 9fe3527e4..af986da30 100644 --- a/api/app/__init__.py +++ b/api/app/__init__.py @@ -1,5 +1,4 @@ from flask import Flask, g, url_for, redirect, render_template, request, flash -from flask_cors import CORS import flask_restful as restful from flask_sqlalchemy import SQLAlchemy from flask_bcrypt import Bcrypt @@ -15,12 +14,6 @@ app = Flask(__name__) app.config.from_object('config') -_allowed_origins = [ - app.config.get('BOABAB_HOST', 'http://localhost:8080').rstrip('/'), - 'http://localhost:3000', - 'http://localhost:8080', -] -CORS(app, resources={r"/api/*": {"origins": _allowed_origins}}, supports_credentials=True) print((app.config['SQLALCHEMY_DATABASE_URI'])) rest_api = restful.Api(app) db = SQLAlchemy(app) @@ -92,6 +85,30 @@ def populate_organisation(): domain = get_domain() g.organisation = OrganisationResolver.resolve_from_domain(domain) +CORS_ALLOWED_METHODS = 'GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS' + +@app.after_request +def set_cors_headers(response): + # populate_organisation() above already rejects any /api/* request whose + # Origin/Referer domain doesn't match a known Organisation, so reflecting + # the Origin back here is only ever done for domains we've already + # validated against the Organisation table - no separate allow-list to + # keep in sync with webapp/dispatch.yaml. + if not request.path.startswith('/api/') or getattr(g, 'organisation', None) is None: + return response + origin = request.environ.get('HTTP_ORIGIN', '') + if not origin: + return response + response.headers['Access-Control-Allow-Origin'] = origin + response.headers['Access-Control-Allow-Credentials'] = 'true' + response.headers.add('Vary', 'Origin') + if request.method == 'OPTIONS': + response.headers['Access-Control-Allow-Methods'] = CORS_ALLOWED_METHODS + requested_headers = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') + if requested_headers: + response.headers['Access-Control-Allow-Headers'] = requested_headers + return response + ## Flask Admin Config # set optional bootswatch theme diff --git a/api/app/invoice/invoice.pdf b/api/app/invoice/invoice.pdf new file mode 100644 index 000000000..d6a233865 Binary files /dev/null and b/api/app/invoice/invoice.pdf differ diff --git a/api/requirements.txt b/api/requirements.txt index 1adac31fc..a8f720a6a 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -24,7 +24,6 @@ pytest passlib pytz six -flask-cors python-dateutil gunicorn google-cloud-storage diff --git a/webapp/src/pages/eventHome/EventHome.js b/webapp/src/pages/eventHome/EventHome.js index d1e8149bc..4493b9893 100644 --- a/webapp/src/pages/eventHome/EventHome.js +++ b/webapp/src/pages/eventHome/EventHome.js @@ -43,7 +43,6 @@ import { useInstall } from '../../context/InstallContext'; import { EventAppProgramme, ProgrammeEditor, EventAppAnnouncements, AnnouncementDetail, AnnouncementsAdmin, MyTicket, CheckinConsole, BadgeExport, MyProfile, ViewMemberProfile, ProfileBrowser, ScanConnect, Connections, ConnectLanding, DiscussionBoard, DiscussionThread, NewDiscussionThread, DiscussionReportsAdmin } from '../eventApp'; import EventDashboard from '../eventDashboard'; import ResourceLinksAdmin from '../resourceLinks'; -import ConsentGate from '../../components/ConsentGate'; function iconCls(icon) { if (!icon) return null; @@ -931,7 +930,6 @@ class EventHome extends Component { /> )} /> - ); diff --git a/webapp/src/pages/review/Review.css b/webapp/src/pages/review/Review.css index 7c766e3d5..3a8670955 100644 --- a/webapp/src/pages/review/Review.css +++ b/webapp/src/pages/review/Review.css @@ -57,6 +57,7 @@ } .question.review { + position: relative; padding-left: 2em; }