civicrm/webform-mw/upload accepted any session-authenticated POST, called
civicrm_api3('Attachment','create') (which skips permission checks from
PHP) against any contact/activity id, and stored any client mime type.
- Require X-Requested-With: XMLHttpRequest (already sent by the app), so
cross-site form posts can't ride a logged-in staff session.
- Require EDIT permission on the target contact/activity.
- Enforce the same mime allowlist as the app's /api/upload route.
WebForm-mw — CiviCRM extension
Adds an Engagement Report tab to Organization contact-view pages that
embeds the FCI Co-op Survey staff report
(https://survey.fci.coop/staff/report) in an iframe. The tab shows the
report for the current organization, scoped by the contact id in the URL.
The embedded app handles its own auth via a shared staff secret. The extension is otherwise read-only and adds no Civi tables, custom fields, or scheduled jobs.
Install
- Copy the entire
webform-mw/directory to your CiviCRM extensions directory (typically<civi-root>/sites/default/ext/or wherever[civicrm.extensionsDir]points in yourcivicrm.settings.php).- The directory name on disk must be
webform-mw(matching<key>ininfo.xml).
- The directory name on disk must be
- In CiviCRM:
Administer → System Settings → Extensions → Add new → Refresh, then click Install next to "WebForm-mw". - Configure (see next section). The tab will be hidden until both settings are present.
Configuration
The extension reads two values, in this order:
-
Constants in
civicrm.settings.php(preferred):define('WEBFORM_MW_APP_URL', 'https://survey.fci.coop'); define('WEBFORM_MW_STAFF_KEY', '...the STAFF_REPORT_KEY shared with the app...'); -
Or environment variables (
WEBFORM_MW_APP_URL,WEBFORM_MW_STAFF_KEY) set wherever PHP-FPM / the web server reads its environment from.
WEBFORM_MW_STAFF_KEY must match the STAFF_REPORT_KEY configured on the
Next.js app (Amplify environment / SSM Parameter Store). The two are the
same shared secret; rotate them together.
WEBFORM_MW_APP_URL is the public base URL of the WebForm-mw deployment
(no trailing slash). Production: https://survey.fci.coop.
When either value is missing, the tab body shows a help banner with the exact configuration snippet to paste, so anyone installing the extension without prior context can self-serve.
Behaviour
- Tab title: Engagement Report.
- Visible only on Organization contacts (Individuals and Households see no tab). The check happens server-side in the tabset hook.
- Tab body is an iframe pointing at
${WEBFORM_MW_APP_URL}/staff/report?org=<cid>&exp=<unix>&sig=<hmac>&frame=1. frame=1tells the embedded app to suppress its site header/footer and emit apostMessage({type:"webform-mw-height", height})payload on render and on resize. The tab's small inline script listens for this message and auto-sizes the iframe so there's no nested scrollbar.- The script validates the postMessage
event.originagainst the configuredWEBFORM_MW_APP_URLorigin before resizing.
Security notes
- The shared secret never leaves the server. Each tab render mints a
signed token,
HMAC-SHA256(secret, "webform-mw.staff-report.v1:<org>:<exp>"), valid for one org for 8 hours. The app rejects tokens for other orgs, expired tokens, and anything valid for longer than 12 hours. - Tokens are only minted after
CRM_Contact_BAO_Contact_Permission::allow()confirms the current user can view the org, so Civi contact ACLs carry through to the embedded report. - Rotating the secret: change
WEBFORM_MW_STAFF_KEYand the app'sSTAFF_REPORT_KEYtogether; outstanding tokens stop working at once. - The extension uses
access CiviCRMas its access argument — anyone with that permission sees the tab on Organization contacts. Tighten by changing the<access_arguments>value inxml/Menu/webform_mw.xmlto a more specific permission (e.g.,view all contacts) and reinstalling. - The embedded app's CSP (
frame-ancestors) must include the CiviCRM origin or the iframe will refuse to render. The Next app readsCIVI_BASE_URLat build time and adds its origin to the staff route's CSP automatically. Confirm withcurl -I <app>/staff/reportafter deploy — you should seeContent-Security-Policy: ... frame-ancestors 'self' https://<your-civi-host> ....
Files
info.xml— extension manifest. Keywebform-mw, typemodule.webform_mw.php—hook_civicrm_tabset+ config readers.CRM/WebformMw/Page/Tab.php— page controller for the tab snippet.templates/CRM/WebformMw/Page/Tab.tpl— iframe + height-listener.xml/Menu/webform_mw.xml— registers thecivicrm/contact/view/engagement-reportURL.
Versions tested
- CiviCRM 5.50+
- PHP 7.4+ / 8.x
- Tested against Backdrop-as-host and Drupal-as-host CiviCRM deployments.
Uninstalling
Administer → Extensions → Disable, then Uninstall. Removes nothing
from the database; the extension stores no Civi data of its own.