Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore iframe support #784

Merged
merged 5 commits into from
Feb 26, 2025
Merged

Restore iframe support #784

merged 5 commits into from
Feb 26, 2025

Conversation

lieut-data
Copy link
Member

@lieut-data lieut-data commented Feb 26, 2025

Summary

Bring back the ability to embed Mattermost inside Microsoft Teams. For now, we're exposing just the endpoint to support embedding Mattermost as an iframe, and handling the manifest generation elsewhere.

Ticket Link

N/A

@lieut-data lieut-data force-pushed the restore-iframe-support branch 2 times, most recently from ee5da18 to 26d31aa Compare February 26, 2025 18:22
Bring back support for embedding Mattermost inside Microsoft Teams.
@lieut-data lieut-data force-pushed the restore-iframe-support branch from 224fd21 to f0fa078 Compare February 26, 2025 19:03
@lieut-data lieut-data requested a review from wiggin77 February 26, 2025 19:05
@lieut-data lieut-data marked this pull request as ready for review February 26, 2025 19:05
@lieut-data lieut-data force-pushed the restore-iframe-support branch from f0fa078 to ff03992 Compare February 26, 2025 19:12
func (a *API) iFrame(w http.ResponseWriter, _ *http.Request) {
config := a.p.API.GetConfig()
siteURL := *config.ServiceSettings.SiteURL
if siteURL == "" {
Copy link

@enzowritescode enzowritescode Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we don't have much control over this, but I believe we can at least verify that the URL is valid and since we set MMEMBED to be Secure, we can check that the scheme is https.

Maybe something like:

parsedURL, err := url.Parse(siteURL)
if err != nil {
    a.p.API.LogError("Invalid SiteURL for MS Teams iFrame", "error", err.Error())
    http.Error(w, "Invalid SiteURL", http.StatusInternalServerError)
    return
}

if parsedURL.Scheme != "https" {
    a.p.API.LogError("SiteURL must use HTTPS for MS Teams iFrame", "scheme", parsedURL.Scheme)
    http.Error(w, "SiteURL must use HTTPS", http.StatusInternalServerError)
    return
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for checking a valid SiteURL, but any objections on skipping the explicit SSL check? (I'll need to rewrite the testing framework to allow us to unit test this the way things are currently setup.)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay that's fine


html := strings.ReplaceAll(iFrameHTML, "{{SITE_URL}}", siteURL)

w.Header().Set("Content-Type", "text/html")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should set some additional security headers here but we will want to test how it behaves in Teams. After some back and forth with Aider, here is some sample code (NOTE: it uses parsedURL from the validation code above):

// Get the origin (scheme + host) for CSP
origin := parsedURL.Scheme + "://" + parsedURL.Host

// Set a minimal CSP for the wrapper page
cspDirectives := []string{
    "default-src 'none'",           // Block all resources by default
    "frame-src " + origin,          // Only allow iframe to load content from Mattermost origin
    "style-src 'unsafe-inline'",    // Allow inline styles for the iframe positioning
}
w.Header().Set("Content-Security-Policy", strings.Join(cspDirectives, "; "))

// Set additional security headers w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "SAMEORIGIN") // This is for the outer page, not the iframe content
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")  

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The X-Frame-Options header failed to load the iFrame, I think because the outer isn't running on the same origin (it's on teams.microsoft.com?)

CleanShot 2025-02-26 at 18 29 51@2x

Removing it and the others worked.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to remove since it's covered in the CSP via frame-src (just repeating what I DMd you lol)

<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0">
</head>
<body>
<iframe

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I double checked that our content security policy allows us to be embedded in an iFrame within MS Teams (currently it has frame-ancestors 'self' teams.microsoft.com; which is good - although we can probably have it be https://teams.microsoft.com since I doubt Microsoft teams is ever over http. That code lives in mattermost/server/channels/web/handlers.go

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't be able to fix this as part of this PR, but it's something we can patch the core app with.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup just wanted to put that on your radar

@lieut-data lieut-data merged commit 240e366 into main Feb 26, 2025
11 checks passed
@lieut-data lieut-data deleted the restore-iframe-support branch February 26, 2025 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants