diff --git a/kobo/settings/base.py b/kobo/settings/base.py index 4f955ff482..c093961bd0 100644 --- a/kobo/settings/base.py +++ b/kobo/settings/base.py @@ -1051,6 +1051,7 @@ def __init__(self, *args, **kwargs): DEFAULT_SUBMISSIONS_COUNT_NUMBER_OF_DAYS = 31 GOOGLE_ANALYTICS_TOKEN = os.environ.get('GOOGLE_ANALYTICS_TOKEN') +HUBSPOT_ID = '21396257' # TODO: parameterize. SENTRY_JS_DSN = None if SENTRY_JS_DSN_URL := env.url('SENTRY_JS_DSN', default=None): SENTRY_JS_DSN = SENTRY_JS_DSN_URL.geturl() @@ -1186,6 +1187,80 @@ def dj_stripe_request_callback_method(): stripe_domain = 'https://js.stripe.com' CSP_SCRIPT_SRC.append(stripe_domain) CSP_FRAME_SRC.append(stripe_domain) +if HUBSPOT_ID: + # https://knowledge.hubspot.com/domains-and-urls/ssl-and-domain-security-in-hubspot#content-security-policy + CSP_CONNECT_SRC.extend([ + '*.hubapi.com', # API calls (HubDB, form submissions) + '*.hs-banner.com', # Cookie banner + '*.hscollectedforms.net', # Forms (non-HubSpot forms) + 'js.hscta.net', # Calls-to-action (button) + 'js-eu1.hscta.net', # Calls-to-action (button) (European data hosting only) + '*.hubspot.com', # Calls-to-action (pop-up), chatflows + '*.hsforms.com', # Forms, surveys + ]) + CSP_FRAME_SRC.extend([ + '*.hs-sites.com', # Calls-to-action (pop-up) + '*.hs-sites-eu1.com', # Calls-to-action (pop-up) (European data hosting only) + 'play.hubspotvideo.com', # Files (videos) + 'play-eu1.hubspotvideo.com', # Files (videos) (European data hosting only) + '*.kbtdev.org', # Files, stylesheets. TODO: configured for dev server, adjust for production before merging! + '*.hubspot.com', # Calls-to-action (pop-up), chatflows + '*.hubspot.net', # Files + '*.hsforms.net', # Forms, surveys + '*.hsforms.com', # Forms, surveys + ]) + CSP_STYLE_SRC.extend([ + '*.kbtdev.org', # Files, stylesheets. TODO: configured for dev server, adjust for production before merging! + 'cdn2.hubspot.net', # Files, stylesheets + '*.hubspotusercontent00.net', # Files + '*.hubspotusercontent10.net', # Files + '*.hubspotusercontent20.net', # Files + '*.hubspotusercontent30.net', # Files + '*.hubspotusercontent40.net', # Files + ]) + CSP_IMG_SRC.extend([ + 'no-cache.hubspot.com', # Calls-to-action (button) + 'cdn2.hubspot.net', # Files, stylesheets + 'js.hscta.net', # Calls-to-action (button) + 'js-eu1.hscta.net', # Calls-to-action (button) (European data hosting only) + '*.hubspot.com', # Calls-to-action (pop-up), chatflows + '*.hubspot.net', # Files + '*.hsforms.net', # Forms, surveys + '*.hsforms.com', # Forms, surveys + '*.hubspotusercontent00.net', # Files + '*.hubspotusercontent10.net', # Files + '*.hubspotusercontent20.net', # Files + '*.hubspotusercontent30.net', # Files + '*.hubspotusercontent40.net', # Files + ]) + CSP_SCRIPT_SRC.extend([ + '*.kbtdev.org', # Files, stylesheets. TODO: configured for dev server, adjust for production before merging! + '*.hsadspixel.net', # Ads + 'static.hsappstatic.net', # Content (sprocket menu, video embedding) + '*.usemessages.com', # Conversations, chatflows + '*.hsleadflows.net', # Forms (pop-up forms) + '*.hs-scripts.com', # HubSpot tracking code + '*.hubspotfeedback.com', # Surveys + 'feedback.hubapi.com', # Surveys + 'feedback-eu1.hubapi.com', # Surveys (European data hosting only) + '*.hs-analytics.net', # Analytics + '*.hs-banner.com', # Cookie banner + '*.hscollectedforms.net', # Forms (non-HubSpot forms) + 'js.hscta.net', # Calls-to-action (button) + 'js-eu1.hscta.net', # Calls-to-action (button) (European data hosting only) + '*.hubspot.com', # Calls-to-action (pop-up), chatflows + '*.hubspot.net', # Files + '*.hsforms.net', # Forms, surveys + '*.hsforms.com', # Forms, surveys + '*.hubspotusercontent00.net', # Files + '*.hubspotusercontent10.net', # Files + '*.hubspotusercontent20.net', # Files + '*.hubspotusercontent30.net', # Files + '*.hubspotusercontent40.net', # Files + ]) + CSP_CONNECT_SRC.extend([ + '*.hsforms.com', # Forms, surveys + ]) csp_report_uri = env.url('CSP_REPORT_URI', None) if csp_report_uri: # Let environ validate uri, but set as string @@ -1301,7 +1376,7 @@ def dj_stripe_request_callback_method(): }, # Schedule every day at midnight UTC 'mass-email-record-mark-as-failed': { - 'task': 'kobo.apps.mass_emails.tasks.mark_old_enqueued_mass_email_record_as_failed', # noqa + 'task': 'kobo.apps.mass_emails.tasks.mark_old_enqueued_mass_email_record_as_failed', # noqa 'schedule': crontab(minute=0, hour=0), 'options': {'queue': 'kpi_low_priority_queue'} }, diff --git a/kpi/templates/index.html b/kpi/templates/index.html index 05c0437961..27751fbe3a 100644 --- a/kpi/templates/index.html +++ b/kpi/templates/index.html @@ -57,4 +57,8 @@ {% endif %} + + + + {% endblock %}