2019-11-29 06:59:40 -05:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
2017-03-28 04:58:19 -04:00
package utils
import (
2018-02-07 12:05:46 -05:00
"crypto"
"crypto/rand"
"encoding/base64"
2018-02-02 08:29:11 -05:00
"fmt"
"html/template"
2017-03-28 04:58:19 -04:00
"net/http"
2017-04-20 09:55:02 -04:00
"net/url"
2018-06-21 14:31:51 -04:00
"path"
2024-04-04 07:44:03 -04:00
"slices"
2017-03-28 04:58:19 -04:00
"strings"
2017-04-20 09:55:02 -04:00
2023-06-11 01:24:35 -04:00
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/shared/i18n"
2017-03-28 04:58:19 -04:00
)
2017-11-22 16:58:03 -05:00
func CheckOrigin ( r * http . Request , allowedOrigins string ) bool {
2017-03-28 04:58:19 -04:00
origin := r . Header . Get ( "Origin" )
2018-08-24 06:09:48 -04:00
if origin == "" {
return true
}
2017-11-22 16:58:03 -05:00
if allowedOrigins == "*" {
2017-07-13 17:02:33 -04:00
return true
}
2025-07-18 06:54:51 -04:00
return slices . Contains ( strings . Split ( allowedOrigins , " " ) , origin )
2017-03-28 04:58:19 -04:00
}
2017-11-22 16:58:03 -05:00
func OriginChecker ( allowedOrigins string ) func ( * http . Request ) bool {
return func ( r * http . Request ) bool {
return CheckOrigin ( r , allowedOrigins )
2017-03-28 04:58:19 -04:00
}
}
2017-04-20 09:55:02 -04:00
2023-07-12 17:55:13 -04:00
// CheckEmbeddedCookie returns true if the MMEMBED cookie is set to 1.
// MMEMBED is set via any plugin that facilitates Mattermost embedded in an iframe (e.g. mattermost-plugin-msteams-sync).
func CheckEmbeddedCookie ( r * http . Request ) bool {
cookie , err := r . Cookie ( "MMEMBED" )
if err != nil {
return false
}
return cookie . Value == "1"
}
2018-06-21 14:31:51 -04:00
func RenderWebAppError ( config * model . Config , w http . ResponseWriter , r * http . Request , err * model . AppError , s crypto . Signer ) {
RenderWebError ( config , w , r , err . StatusCode , url . Values {
2018-02-07 12:05:46 -05:00
"message" : [ ] string { err . Message } ,
} , s )
}
2018-06-21 14:31:51 -04:00
func RenderWebError ( config * model . Config , w http . ResponseWriter , r * http . Request , status int , params url . Values , s crypto . Signer ) {
2018-02-07 12:05:46 -05:00
queryString := params . Encode ( )
2018-06-21 14:31:51 -04:00
subpath , _ := GetSubpathFromConfig ( config )
2018-02-07 12:05:46 -05:00
h := crypto . SHA256
sum := h . New ( )
2018-06-21 14:31:51 -04:00
sum . Write ( [ ] byte ( path . Join ( subpath , "error" ) + "?" + queryString ) )
2018-02-07 12:05:46 -05:00
signature , err := s . Sign ( rand . Reader , sum . Sum ( nil ) , h )
if err != nil {
http . Error ( w , "" , http . StatusInternalServerError )
return
2017-04-20 09:55:02 -04:00
}
2018-06-21 14:31:51 -04:00
destination := path . Join ( subpath , "error" ) + "?" + queryString + "&s=" + base64 . URLEncoding . EncodeToString ( signature )
2017-04-20 09:55:02 -04:00
2018-02-02 08:29:11 -05:00
if status >= 300 && status < 400 {
http . Redirect ( w , r , destination , status )
return
}
2018-03-14 18:09:04 -04:00
w . Header ( ) . Set ( "Content-Type" , "text/html" )
2018-02-02 08:29:11 -05:00
w . WriteHeader ( status )
fmt . Fprintln ( w , ` <!DOCTYPE html><html><head></head> ` )
fmt . Fprintln ( w , ` <body onload="window.location = ' ` + template . HTMLEscapeString ( template . JSEscapeString ( destination ) ) + ` '"> ` )
fmt . Fprintln ( w , ` <noscript><meta http-equiv="refresh" content="0; url= ` + template . HTMLEscapeString ( destination ) + ` "></noscript> ` )
2021-02-21 01:58:04 -05:00
fmt . Fprintln ( w , ` <!-- web error message --> ` )
2018-02-02 08:29:11 -05:00
fmt . Fprintln ( w , ` <a href=" ` + template . HTMLEscapeString ( destination ) + ` " style="color: #c0c0c0;">...</a> ` )
fmt . Fprintln ( w , ` </body></html> ` )
2017-04-20 09:55:02 -04:00
}
2021-01-19 10:46:22 -05:00
2021-02-18 09:36:56 -05:00
func RenderMobileAuthComplete ( w http . ResponseWriter , redirectURL string ) {
2021-05-12 10:56:15 -04:00
var link = template . HTMLEscapeString ( redirectURL )
2021-01-19 10:46:22 -05:00
RenderMobileMessage ( w , `
2021-05-12 10:56:15 -04:00
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 512 512" style = "width: 64px; height: 64px; fill: #3c763d" >
< ! -- Font Awesome Free 5.15 .3 by @ fontawesome - https : //fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->
< path stroke = "green" d = "M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" / >
< / svg >
2021-02-26 02:12:49 -05:00
< h2 > ` +i18n.T("api.oauth.auth_complete")+ ` < / h2 >
< p id = "redirecting-message" > ` +i18n.T("api.oauth.redirecting_back")+ ` < / p >
< p id = "close-tab-message" style = "display: none" > ` +i18n.T("api.oauth.close_browser")+ ` < / p >
2021-05-12 10:56:15 -04:00
< p > ` +i18n.T("api.oauth.click_redirect", model.StringInterface { "Link": link})+ ` < / p >
< meta http - equiv = "refresh" content = "2; url=`+link+`" >
2021-01-19 10:46:22 -05:00
< script >
window . onload = function ( ) {
setTimeout ( function ( ) {
document . getElementById ( ' redirecting - message ' ) . style . display = ' none ' ;
document . getElementById ( ' close - tab - message ' ) . style . display = ' block ' ;
} , 2000 ) ;
}
< / script >
` )
}
func RenderMobileError ( config * model . Config , w http . ResponseWriter , err * model . AppError , redirectURL string ) {
2022-11-22 08:43:26 -05:00
var link = template . HTMLEscapeString ( redirectURL )
2021-06-17 08:20:43 -04:00
u , redirectErr := url . Parse ( redirectURL )
2024-04-04 07:44:03 -04:00
if redirectErr != nil || ! slices . Contains ( config . NativeAppSettings . AppCustomURLSchemes , u . Scheme ) {
2021-06-17 08:20:43 -04:00
link = * config . ServiceSettings . SiteURL
}
2021-01-19 10:46:22 -05:00
RenderMobileMessage ( w , `
2021-05-12 10:56:15 -04:00
< svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 576 512" style = "width: 64px; height: 64px; fill: #ccc" >
< ! -- Font Awesome Free 5.15 .3 by @ fontawesome - https : //fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->
< path d = "M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z" / >
< / svg >
2021-02-26 02:12:49 -05:00
< h2 > ` +i18n.T("error")+ ` < / h2 >
2021-01-19 10:46:22 -05:00
< p > ` +err.Message+ ` < / p >
2021-06-17 08:20:43 -04:00
< a href = "`+link+`" >
2022-07-05 02:46:50 -04:00
` +i18n.T("api.back_to_app", map[string]any { "SiteName": config.TeamSettings.SiteName})+ `
2021-01-19 10:46:22 -05:00
< / a >
` )
}
func RenderMobileMessage ( w http . ResponseWriter , message string ) {
w . Header ( ) . Set ( "Content-Type" , "text/html" )
fmt . Fprintln ( w , `
< ! DOCTYPE html >
< html >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0, minimum-scale=1.0, user-scalable=yes, viewport-fit=cover" >
< style >
2021-05-12 10:56:15 -04:00
body {
color : # 333 ;
background - color : # fff ;
font - family : "Helvetica Neue" , Helvetica , Arial , sans - serif ;
font - size : 14 px ;
line - height : 1.42857143 ;
}
a {
color : # 337 ab7 ;
text - decoration : none ;
}
a : focus , a : hover {
color : # 23527 c ;
text - decoration : underline ;
}
h2 {
font - size : 30 px ;
margin : 20 px 0 10 px 0 ;
font - weight : 500 ;
line - height : 1.1
}
p {
margin : 0 0 10 px ;
}
2021-01-19 10:46:22 -05:00
. message - container {
color : # 555 ;
display : table - cell ;
padding : 5 em 0 ;
text - align : left ;
vertical - align : top ;
}
< / style >
< / head >
< body >
2021-02-21 01:58:04 -05:00
< ! -- mobile app message -- >
2021-05-12 10:56:15 -04:00
< div class = "message-container" >
` +message+ `
2021-01-19 10:46:22 -05:00
< / div >
< / body >
< / html >
` )
}