2017-04-12 08:27:57 -04:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2019-11-29 06:59:40 -05:00
// See LICENSE.txt for license information.
2015-06-15 03:53:32 -04:00
package web
import (
2016-02-08 07:26:10 -05:00
"net/http"
2018-06-21 14:31:51 -04:00
"path"
2016-02-08 07:26:10 -05:00
"strings"
2026-03-25 09:41:33 -04:00
"github.com/Masterminds/semver/v3"
2018-03-06 16:22:07 -05:00
"github.com/avct/uasurfer"
2018-05-14 10:24:58 -04:00
"github.com/gorilla/mux"
2016-03-16 23:00:33 -04:00
2023-06-11 01:24:35 -04:00
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/shared/mlog"
"github.com/mattermost/mattermost/server/v8/channels/app"
"github.com/mattermost/mattermost/server/v8/channels/utils"
2015-06-15 03:53:32 -04:00
)
2018-05-14 10:24:58 -04:00
type Web struct {
2021-10-15 10:27:05 -04:00
srv * app . Server
2021-05-11 06:00:44 -04:00
MainRouter * mux . Router
2018-05-14 10:24:58 -04:00
}
2017-09-15 08:51:46 -04:00
2021-10-15 10:27:05 -04:00
func New ( srv * app . Server ) * Web {
2018-05-14 10:24:58 -04:00
mlog . Debug ( "Initializing web routes" )
2015-07-08 11:50:10 -04:00
2018-05-14 10:24:58 -04:00
web := & Web {
2021-10-15 10:27:05 -04:00
srv : srv ,
MainRouter : srv . Router ,
2016-03-16 23:00:33 -04:00
}
2015-06-15 03:53:32 -04:00
2019-08-15 08:45:31 -04:00
web . InitOAuth ( )
2018-05-14 10:24:58 -04:00
web . InitWebhooks ( )
2018-05-14 11:27:30 -04:00
web . InitSaml ( )
2025-11-20 08:06:23 -05:00
web . InitMagicLink ( )
2018-05-21 10:15:23 -04:00
web . InitStatic ( )
2016-07-15 08:57:52 -04:00
2018-05-14 10:24:58 -04:00
return web
2017-09-15 08:51:46 -04:00
}
2018-05-14 10:24:58 -04:00
// Due to the complexities of UA detection and the ramifications of a misdetection
// only older Safari and IE browsers throw incompatibility errors.
2018-03-06 16:22:07 -05:00
// Map should be of minimum required browser version.
2019-08-15 14:30:40 -04:00
// -1 means that the browser is not supported in any version.
2018-03-06 16:22:07 -05:00
var browserMinimumSupported = map [ string ] int {
2019-08-15 14:30:40 -04:00
"BrowserIE" : 12 ,
2019-11-04 11:01:29 -05:00
"BrowserSafari" : 12 ,
2018-03-06 16:22:07 -05:00
}
2015-06-15 03:53:32 -04:00
2020-11-09 05:32:21 -05:00
func CheckClientCompatibility ( agentString string ) bool {
2018-03-06 16:22:07 -05:00
ua := uasurfer . Parse ( agentString )
2017-09-06 16:23:14 -04:00
2019-08-15 14:30:40 -04:00
if version , exist := browserMinimumSupported [ ua . Browser . Name . String ( ) ] ; exist && ( ua . Browser . Version . Major < version || version < 0 ) {
2018-03-06 16:22:07 -05:00
return false
2015-06-15 03:53:32 -04:00
}
return true
}
2026-03-04 10:16:11 -05:00
func CheckDesktopAppCompatibility ( agentString string , minVersion * string ) bool {
if minVersion == nil || * minVersion == "" {
return true
}
clientVersionStr , ok := app . GetDesktopAppVersion ( agentString )
if ! ok {
return true
}
2026-03-25 09:41:33 -04:00
clientVersion , err := semver . NewVersion ( clientVersionStr )
2026-03-04 10:16:11 -05:00
if err != nil {
return true
}
2026-03-25 09:41:33 -04:00
required , err := semver . StrictNewVersion ( * minVersion )
2026-03-04 10:16:11 -05:00
if err != nil {
return true
}
2026-03-25 09:41:33 -04:00
return clientVersion . GreaterThanEqual ( required )
2026-03-04 10:16:11 -05:00
}
2025-01-29 01:45:13 -05:00
func Handle404 ( a * app . App , w http . ResponseWriter , r * http . Request ) {
2018-05-14 10:24:58 -04:00
err := model . NewAppError ( "Handle404" , "api.context.404.app_error" , nil , "" , http . StatusNotFound )
2021-05-11 06:00:44 -04:00
ipAddress := utils . GetIPAddress ( r , a . Config ( ) . ServiceSettings . TrustedProxyIPHeader )
2019-05-24 14:22:13 -04:00
mlog . Debug ( "not found handler triggered" , mlog . String ( "path" , r . URL . Path ) , mlog . Int ( "code" , 404 ) , mlog . String ( "ip" , ipAddress ) )
2021-08-16 13:46:44 -04:00
if IsAPICall ( a , r ) {
2022-09-29 14:18:57 -04:00
w . Header ( ) . Set ( "Content-Type" , "application/json" )
2018-05-14 10:24:58 -04:00
w . WriteHeader ( err . StatusCode )
err . DetailedError = "There doesn't appear to be an api call for the url='" + r . URL . Path + "'. Typo? are you missing a team_id or user_id as part of the url?"
2024-10-29 03:45:40 -04:00
if _ , writeErr := w . Write ( [ ] byte ( err . ToJSON ( ) ) ) ; writeErr != nil {
mlog . Warn ( "Error writing 404 response" , mlog . Err ( writeErr ) )
}
2021-05-11 06:00:44 -04:00
} else if * a . Config ( ) . ServiceSettings . WebserverMode == "disabled" {
2019-05-13 12:10:30 -04:00
http . NotFound ( w , r )
2018-05-14 10:24:58 -04:00
} else {
2021-05-11 06:00:44 -04:00
utils . RenderWebAppError ( a . Config ( ) , w , r , err , a . AsymmetricSigningKey ( ) )
2016-04-22 01:37:01 -04:00
}
2018-05-14 10:24:58 -04:00
}
2016-04-22 01:37:01 -04:00
2025-01-29 01:45:13 -05:00
func IsAPICall ( a * app . App , r * http . Request ) bool {
2021-05-11 06:00:44 -04:00
subpath , _ := utils . GetSubpathFromConfig ( a . Config ( ) )
2018-06-21 14:31:51 -04:00
2018-06-26 17:04:06 -04:00
return strings . HasPrefix ( r . URL . Path , path . Join ( subpath , "api" ) + "/" )
}
2025-01-29 01:45:13 -05:00
func IsWebhookCall ( a * app . App , r * http . Request ) bool {
2018-06-26 17:04:06 -04:00
subpath , _ := utils . GetSubpathFromConfig ( a . Config ( ) )
return strings . HasPrefix ( r . URL . Path , path . Join ( subpath , "hooks" ) + "/" )
2015-12-17 12:44:46 -05:00
}
2018-05-14 11:27:30 -04:00
2025-01-29 01:45:13 -05:00
func IsOAuthAPICall ( a * app . App , r * http . Request ) bool {
2021-05-11 06:00:44 -04:00
subpath , _ := utils . GetSubpathFromConfig ( a . Config ( ) )
2019-05-30 13:23:26 -04:00
if r . Method == "POST" && r . URL . Path == path . Join ( subpath , "oauth" , "authorize" ) {
return true
}
if r . URL . Path == path . Join ( subpath , "oauth" , "apps" , "authorized" ) ||
r . URL . Path == path . Join ( subpath , "oauth" , "deauthorize" ) ||
2025-12-10 01:31:53 -05:00
r . URL . Path == path . Join ( subpath , "oauth" , "access_token" ) ||
r . URL . Path == path . Join ( subpath , "oauth" , "intune" ) {
2019-05-30 13:23:26 -04:00
return true
}
return false
}
2018-05-14 11:27:30 -04:00
func ReturnStatusOK ( w http . ResponseWriter ) {
m := make ( map [ string ] string )
2021-07-12 14:05:36 -04:00
m [ model . STATUS ] = model . StatusOk
2024-10-29 03:45:40 -04:00
if _ , err := w . Write ( [ ] byte ( model . MapToJSON ( m ) ) ) ; err != nil {
mlog . Warn ( "Error writing status OK response" , mlog . Err ( err ) )
}
2018-05-14 11:27:30 -04:00
}