2015-10-08 12:27:09 -04:00
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
2015-06-14 23:53:32 -08:00
// See License.txt for license information.
package api
import (
2015-09-16 09:37:20 -07:00
"fmt"
2015-06-14 23:53:32 -08:00
"net"
"net/http"
"net/url"
"strings"
2016-11-22 11:05:54 -08:00
"time"
2015-08-25 11:06:11 -07:00
2016-01-11 09:12:51 -06:00
l4g "github.com/alecthomas/log4go"
2016-04-21 22:37:01 -07:00
"github.com/gorilla/mux"
goi18n "github.com/nicksnyder/go-i18n/i18n"
2016-08-04 09:25:37 -08:00
"github.com/mattermost/platform/einterfaces"
2015-08-25 11:06:11 -07:00
"github.com/mattermost/platform/model"
2016-12-08 07:18:15 -08:00
"github.com/mattermost/platform/store"
2015-08-25 11:06:11 -07:00
"github.com/mattermost/platform/utils"
2015-06-14 23:53:32 -08:00
)
var sessionCache * utils . Cache = utils . NewLru ( model . SESSION_CACHE_SIZE )
2016-03-02 21:24:40 -03:00
var allowedMethods [ ] string = [ ] string {
"POST" ,
"GET" ,
"OPTIONS" ,
"PUT" ,
"PATCH" ,
"DELETE" ,
}
2015-06-14 23:53:32 -08:00
type Context struct {
2016-02-08 07:26:10 -05:00
Session model . Session
RequestId string
IpAddress string
Path string
Err * model . AppError
teamURLValid bool
teamURL string
2016-08-09 09:53:22 -04:00
siteURL string
2016-02-08 07:26:10 -05:00
T goi18n . TranslateFunc
Locale string
2016-04-21 22:37:01 -07:00
TeamId string
2015-06-14 23:53:32 -08:00
}
func ApiAppHandler ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , false , false , true , false , false , false , false }
2015-06-14 23:53:32 -08:00
}
func AppHandler ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , false , false , false , false , false , false , false }
2015-07-08 11:50:10 -04:00
}
func AppHandlerIndependent ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , false , false , false , false , true , false , false }
2015-06-14 23:53:32 -08:00
}
func ApiUserRequired ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , true , false , true , false , false , false , true }
2015-06-14 23:53:32 -08:00
}
func ApiUserRequiredActivity ( h func ( * Context , http . ResponseWriter , * http . Request ) , isUserActivity bool ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , true , false , true , isUserActivity , false , false , true }
}
func ApiUserRequiredMfa ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
return & handler { h , true , false , true , false , false , false , false }
2015-06-14 23:53:32 -08:00
}
func UserRequired ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , true , false , false , false , false , false , true }
2015-06-14 23:53:32 -08:00
}
2016-08-03 12:19:27 -05:00
func AppHandlerTrustRequester ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , false , false , false , false , false , true , false }
2016-08-03 12:19:27 -05:00
}
2015-06-14 23:53:32 -08:00
func ApiAdminSystemRequired ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , true , true , true , false , false , false , true }
2016-04-04 14:58:05 -04:00
}
2016-09-13 12:42:48 -04:00
func ApiAdminSystemRequiredTrustRequester ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , true , true , true , false , false , true , true }
2016-09-13 12:42:48 -04:00
}
2016-04-04 14:58:05 -04:00
func ApiAppHandlerTrustRequester ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , false , false , true , false , false , true , false }
2016-04-04 14:58:05 -04:00
}
func ApiUserRequiredTrustRequester ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , true , false , true , false , false , true , true }
2015-06-14 23:53:32 -08:00
}
2016-05-05 16:35:03 -04:00
func ApiAppHandlerTrustRequesterIndependent ( h func ( * Context , http . ResponseWriter , * http . Request ) ) http . Handler {
2016-12-12 08:16:10 -05:00
return & handler { h , false , false , true , false , true , true , false }
2016-05-05 16:35:03 -04:00
}
2015-06-14 23:53:32 -08:00
type handler struct {
handleFunc func ( * Context , http . ResponseWriter , * http . Request )
requireUser bool
requireSystemAdmin bool
isApi bool
isUserActivity bool
2015-07-08 11:50:10 -04:00
isTeamIndependent bool
2016-04-04 14:58:05 -04:00
trustRequester bool
2016-12-12 08:16:10 -05:00
requireMfa bool
2015-06-14 23:53:32 -08:00
}
func ( h handler ) ServeHTTP ( w http . ResponseWriter , r * http . Request ) {
2016-11-22 11:05:54 -08:00
now := time . Now ( )
2015-06-14 23:53:32 -08:00
l4g . Debug ( "%v" , r . URL . Path )
c := & Context { }
2016-01-21 14:15:44 -06:00
c . T , c . Locale = utils . GetTranslationsAndLocale ( w , r )
2015-06-14 23:53:32 -08:00
c . RequestId = model . NewId ( )
c . IpAddress = GetIpAddress ( r )
2016-04-21 22:37:01 -07:00
c . TeamId = mux . Vars ( r ) [ "team_id" ]
2015-06-14 23:53:32 -08:00
2015-09-16 15:49:12 -04:00
token := ""
isTokenFromQueryString := false
// Attempt to parse token out of the header
authHeader := r . Header . Get ( model . HEADER_AUTH )
if len ( authHeader ) > 6 && strings . ToUpper ( authHeader [ 0 : 6 ] ) == model . HEADER_BEARER {
// Default session token
token = authHeader [ 7 : ]
} else if len ( authHeader ) > 5 && strings . ToLower ( authHeader [ 0 : 5 ] ) == model . HEADER_TOKEN {
// OAuth token
token = authHeader [ 6 : ]
}
// Attempt to parse the token from the cookie
if len ( token ) == 0 {
2016-02-08 07:26:10 -05:00
if cookie , err := r . Cookie ( model . SESSION_COOKIE_TOKEN ) ; err == nil {
token = cookie . Value
2016-04-04 14:58:05 -04:00
if ( h . requireSystemAdmin || h . requireUser ) && ! h . trustRequester {
if r . Header . Get ( model . HEADER_REQUESTED_WITH ) != model . HEADER_REQUESTED_WITH_XML {
2016-12-16 14:10:11 +01:00
c . Err = model . NewLocAppError ( "ServeHTTP" , "api.context.session_expired.app_error" , nil , "token=" + token + " Appears to be a CSRF attempt" )
2016-04-04 14:58:05 -04:00
token = ""
}
}
2015-09-16 15:49:12 -04:00
}
}
// Attempt to parse token out of the query string
if len ( token ) == 0 {
token = r . URL . Query ( ) . Get ( "access_token" )
isTokenFromQueryString = true
}
2016-08-09 09:53:22 -04:00
if * utils . Cfg . ServiceSettings . SiteURL != "" {
c . SetSiteURL ( * utils . Cfg . ServiceSettings . SiteURL )
} else {
protocol := GetProtocol ( r )
c . SetSiteURL ( protocol + "://" + r . Host )
2016-08-02 16:37:09 -04:00
}
2015-06-14 23:53:32 -08:00
w . Header ( ) . Set ( model . HEADER_REQUEST_ID , c . RequestId )
2016-09-08 08:48:02 -04:00
w . Header ( ) . Set ( model . HEADER_VERSION_ID , fmt . Sprintf ( "%v.%v.%v" , model . CurrentVersion , model . BuildNumber , utils . CfgHash ) )
2016-08-04 09:25:37 -08:00
if einterfaces . GetClusterInterface ( ) != nil {
w . Header ( ) . Set ( model . HEADER_CLUSTER_ID , einterfaces . GetClusterInterface ( ) . GetClusterId ( ) )
}
2015-07-27 11:59:14 -07:00
2016-08-03 12:19:27 -05:00
// Instruct the browser not to display us in an iframe unless is the same origin for anti-clickjacking
2015-07-27 11:59:14 -07:00
if ! h . isApi {
2016-08-03 12:19:27 -05:00
w . Header ( ) . Set ( "X-Frame-Options" , "SAMEORIGIN" )
w . Header ( ) . Set ( "Content-Security-Policy" , "frame-ancestors 'self'" )
2015-09-11 12:11:10 -04:00
} else {
2015-09-16 15:49:12 -04:00
// All api response bodies will be JSON formatted by default
2015-09-11 12:11:10 -04:00
w . Header ( ) . Set ( "Content-Type" , "application/json" )
2016-02-11 13:17:27 -08:00
if r . Method == "GET" {
w . Header ( ) . Set ( "Expires" , "0" )
}
2015-07-27 11:59:14 -07:00
}
2015-06-14 23:53:32 -08:00
2015-09-16 15:49:12 -04:00
if len ( token ) != 0 {
2016-01-20 13:36:16 -06:00
session := GetSession ( token )
2015-06-14 23:53:32 -08:00
if session == nil || session . IsExpired ( ) {
2015-10-01 17:52:47 -07:00
c . RemoveSessionCookie ( w , r )
2016-02-08 07:26:10 -05:00
if h . requireUser || h . requireSystemAdmin {
c . Err = model . NewLocAppError ( "ServeHTTP" , "api.context.session_expired.app_error" , nil , "token=" + token )
c . Err . StatusCode = http . StatusUnauthorized
}
2015-09-16 15:49:12 -04:00
} else if ! session . IsOAuth && isTokenFromQueryString {
2016-01-21 10:07:29 -03:00
c . Err = model . NewLocAppError ( "ServeHTTP" , "api.context.token_provided.app_error" , nil , "token=" + token )
2015-06-14 23:53:32 -08:00
c . Err . StatusCode = http . StatusUnauthorized
} else {
c . Session = * session
}
}
2015-07-08 11:50:10 -04:00
if h . isApi || h . isTeamIndependent {
c . setTeamURL ( c . GetSiteURL ( ) , false )
c . Path = r . URL . Path
} else {
splitURL := strings . Split ( r . URL . Path , "/" )
2016-08-02 16:37:09 -04:00
c . setTeamURL ( c . GetSiteURL ( ) + "/" + splitURL [ 1 ] , true )
2015-07-08 11:50:10 -04:00
c . Path = "/" + strings . Join ( splitURL [ 2 : ] , "/" )
}
2015-06-14 23:53:32 -08:00
if c . Err == nil && h . requireUser {
c . UserRequired ( )
}
2016-12-12 08:16:10 -05:00
if c . Err == nil && h . requireMfa {
c . MfaRequired ( )
}
2015-06-14 23:53:32 -08:00
if c . Err == nil && h . requireSystemAdmin {
c . SystemAdminRequired ( )
}
2015-09-16 15:49:12 -04:00
if c . Err == nil && h . isUserActivity && token != "" && len ( c . Session . UserId ) > 0 {
2016-08-31 06:24:14 -07:00
SetStatusOnline ( c . Session . UserId , c . Session . Id , false )
2015-06-14 23:53:32 -08:00
}
2016-12-20 16:55:22 +01:00
if c . Err == nil && ( h . requireUser || h . requireSystemAdmin ) {
//check if teamId exist
c . CheckTeamId ( )
}
2015-06-14 23:53:32 -08:00
if c . Err == nil {
h . handleFunc ( c , w , r )
}
2016-07-19 12:40:13 -04:00
// Handle errors that have occoured
2015-06-14 23:53:32 -08:00
if c . Err != nil {
2016-01-20 14:36:34 -06:00
c . Err . Translate ( c . T )
2015-06-14 23:53:32 -08:00
c . Err . RequestId = c . RequestId
c . LogError ( c . Err )
c . Err . Where = r . URL . Path
2016-10-19 14:49:25 -04:00
// Block out detailed error when not in developer mode
2016-07-19 12:40:13 -04:00
if ! * utils . Cfg . ServiceSettings . EnableDeveloper {
c . Err . DetailedError = ""
}
2015-06-14 23:53:32 -08:00
if h . isApi {
w . WriteHeader ( c . Err . StatusCode )
w . Write ( [ ] byte ( c . Err . ToJson ( ) ) )
2016-11-22 11:05:54 -08:00
if einterfaces . GetMetricsInterface ( ) != nil {
einterfaces . GetMetricsInterface ( ) . IncrementHttpError ( )
}
2015-06-14 23:53:32 -08:00
} else {
if c . Err . StatusCode == http . StatusUnauthorized {
2015-07-08 11:50:10 -04:00
http . Redirect ( w , r , c . GetTeamURL ( ) + "/?redirect=" + url . QueryEscape ( r . URL . Path ) , http . StatusTemporaryRedirect )
2015-06-14 23:53:32 -08:00
} else {
RenderWebError ( c . Err , w , r )
}
}
2016-11-22 11:05:54 -08:00
}
if h . isApi && einterfaces . GetMetricsInterface ( ) != nil {
einterfaces . GetMetricsInterface ( ) . IncrementHttpRequest ( )
if r . URL . Path != model . API_URL_SUFFIX + "/users/websocket" {
elapsed := float64 ( time . Since ( now ) ) / float64 ( time . Second )
einterfaces . GetMetricsInterface ( ) . ObserveHttpRequestDuration ( elapsed )
}
2015-06-14 23:53:32 -08:00
}
}
2016-03-02 21:24:40 -03:00
func ( cw * CorsWrapper ) ServeHTTP ( w http . ResponseWriter , r * http . Request ) {
2016-03-01 22:12:05 -03:00
if len ( * utils . Cfg . ServiceSettings . AllowCorsFrom ) > 0 {
2016-03-02 21:24:40 -03:00
origin := r . Header . Get ( "Origin" )
if * utils . Cfg . ServiceSettings . AllowCorsFrom == "*" || strings . Contains ( * utils . Cfg . ServiceSettings . AllowCorsFrom , origin ) {
w . Header ( ) . Set ( "Access-Control-Allow-Origin" , origin )
if r . Method == "OPTIONS" {
w . Header ( ) . Set (
"Access-Control-Allow-Methods" ,
strings . Join ( allowedMethods , ", " ) )
w . Header ( ) . Set (
"Access-Control-Allow-Headers" ,
r . Header . Get ( "Access-Control-Request-Headers" ) )
}
}
2016-03-01 22:12:05 -03:00
}
if r . Method == "OPTIONS" {
return
}
cw . router . ServeHTTP ( w , r )
}
2015-09-22 12:12:50 -07:00
func GetProtocol ( r * http . Request ) string {
if r . Header . Get ( model . HEADER_FORWARDED_PROTO ) == "https" {
return "https"
} else {
return "http"
}
}
2015-06-14 23:53:32 -08:00
func ( c * Context ) LogAudit ( extraInfo string ) {
2015-09-16 15:49:12 -04:00
audit := & model . Audit { UserId : c . Session . UserId , IpAddress : c . IpAddress , Action : c . Path , ExtraInfo : extraInfo , SessionId : c . Session . Id }
2016-01-20 13:36:16 -06:00
if r := <- Srv . Store . Audit ( ) . Save ( audit ) ; r . Err != nil {
2015-08-20 15:04:37 -07:00
c . LogError ( r . Err )
}
2015-06-14 23:53:32 -08:00
}
func ( c * Context ) LogAuditWithUserId ( userId , extraInfo string ) {
2015-08-20 15:04:37 -07:00
if len ( c . Session . UserId ) > 0 {
extraInfo = strings . TrimSpace ( extraInfo + " session_user=" + c . Session . UserId )
}
2015-06-14 23:53:32 -08:00
2015-09-16 15:49:12 -04:00
audit := & model . Audit { UserId : userId , IpAddress : c . IpAddress , Action : c . Path , ExtraInfo : extraInfo , SessionId : c . Session . Id }
2016-01-20 13:36:16 -06:00
if r := <- Srv . Store . Audit ( ) . Save ( audit ) ; r . Err != nil {
2015-08-20 15:04:37 -07:00
c . LogError ( r . Err )
}
2015-06-14 23:53:32 -08:00
}
func ( c * Context ) LogError ( err * model . AppError ) {
2016-07-01 11:57:17 -08:00
// filter out endless reconnects
2016-08-26 13:24:57 -08:00
if c . Path == "/api/v3/users/websocket" && err . StatusCode == 401 || err . Id == "web.check_browser_compatibility.app_error" {
2016-07-01 11:57:17 -08:00
c . LogDebug ( err )
} else {
l4g . Error ( utils . T ( "api.context.log.error" ) , c . Path , err . Where , err . StatusCode ,
c . RequestId , c . Session . UserId , c . IpAddress , err . SystemMessage ( utils . T ) , err . DetailedError )
}
2015-06-14 23:53:32 -08:00
}
2016-06-29 04:16:20 -08:00
func ( c * Context ) LogDebug ( err * model . AppError ) {
l4g . Debug ( utils . T ( "api.context.log.error" ) , c . Path , err . Where , err . StatusCode ,
c . RequestId , c . Session . UserId , c . IpAddress , err . SystemMessage ( utils . T ) , err . DetailedError )
}
2015-06-14 23:53:32 -08:00
func ( c * Context ) UserRequired ( ) {
if len ( c . Session . UserId ) == 0 {
2016-01-21 10:07:29 -03:00
c . Err = model . NewLocAppError ( "" , "api.context.session_expired.app_error" , nil , "UserRequired" )
2015-06-14 23:53:32 -08:00
c . Err . StatusCode = http . StatusUnauthorized
return
}
}
2016-12-12 08:16:10 -05:00
func ( c * Context ) MfaRequired ( ) {
// Must be licensed for MFA and have it configured for enforcement
if ! utils . IsLicensed || ! * utils . License . Features . MFA || ! * utils . Cfg . ServiceSettings . EnableMultifactorAuthentication || ! * utils . Cfg . ServiceSettings . EnforceMultifactorAuthentication {
return
}
// OAuth integrations are excepted
if c . Session . IsOAuth {
return
}
if result := <- Srv . Store . User ( ) . Get ( c . Session . UserId ) ; result . Err != nil {
c . Err = model . NewLocAppError ( "" , "api.context.session_expired.app_error" , nil , "MfaRequired" )
c . Err . StatusCode = http . StatusUnauthorized
return
} else {
user := result . Data . ( * model . User )
// Only required for email and ldap accounts
if user . AuthService != "" &&
user . AuthService != model . USER_AUTH_SERVICE_EMAIL &&
user . AuthService != model . USER_AUTH_SERVICE_LDAP {
return
}
if ! user . MfaActive {
c . Err = model . NewLocAppError ( "" , "api.context.mfa_required.app_error" , nil , "MfaRequired" )
c . Err . StatusCode = http . StatusUnauthorized
return
}
}
}
2015-06-14 23:53:32 -08:00
func ( c * Context ) SystemAdminRequired ( ) {
if len ( c . Session . UserId ) == 0 {
2016-01-21 10:07:29 -03:00
c . Err = model . NewLocAppError ( "" , "api.context.session_expired.app_error" , nil , "SystemAdminRequired" )
2015-06-14 23:53:32 -08:00
c . Err . StatusCode = http . StatusUnauthorized
return
2016-09-13 12:42:48 -04:00
} else if ! HasPermissionToContext ( c , model . PERMISSION_MANAGE_SYSTEM ) {
2016-01-21 10:07:29 -03:00
c . Err = model . NewLocAppError ( "" , "api.context.permissions.app_error" , nil , "AdminRequired" )
2015-06-14 23:53:32 -08:00
c . Err . StatusCode = http . StatusForbidden
return
}
}
2015-10-01 17:52:47 -07:00
func ( c * Context ) RemoveSessionCookie ( w http . ResponseWriter , r * http . Request ) {
2015-10-20 14:49:42 -07:00
cookie := & http . Cookie {
2015-10-20 04:37:51 -07:00
Name : model . SESSION_COOKIE_TOKEN ,
2015-10-20 14:49:42 -07:00
Value : "" ,
2015-10-01 17:52:47 -07:00
Path : "/" ,
2015-10-20 14:49:42 -07:00
MaxAge : - 1 ,
2015-10-01 17:52:47 -07:00
HttpOnly : true ,
}
2015-10-20 14:49:42 -07:00
http . SetCookie ( w , cookie )
2015-06-14 23:53:32 -08:00
}
func ( c * Context ) SetInvalidParam ( where string , name string ) {
2016-05-05 16:35:03 -04:00
c . Err = NewInvalidParamError ( where , name )
}
func NewInvalidParamError ( where string , name string ) * model . AppError {
err := model . NewLocAppError ( where , "api.context.invalid_param.app_error" , map [ string ] interface { } { "Name" : name } , "" )
err . StatusCode = http . StatusBadRequest
return err
2015-06-14 23:53:32 -08:00
}
func ( c * Context ) SetUnknownError ( where string , details string ) {
2016-01-21 10:07:29 -03:00
c . Err = model . NewLocAppError ( where , "api.context.unknown.app_error" , nil , details )
2015-06-14 23:53:32 -08:00
}
2015-07-08 11:50:10 -04:00
func ( c * Context ) setTeamURL ( url string , valid bool ) {
c . teamURL = url
c . teamURLValid = valid
}
2015-10-01 17:52:47 -07:00
func ( c * Context ) SetTeamURLFromSession ( ) {
2016-04-21 22:37:01 -07:00
if result := <- Srv . Store . Team ( ) . Get ( c . TeamId ) ; result . Err == nil {
2015-07-08 11:50:10 -04:00
c . setTeamURL ( c . GetSiteURL ( ) + "/" + result . Data . ( * model . Team ) . Name , true )
}
}
2016-08-09 09:53:22 -04:00
func ( c * Context ) SetSiteURL ( url string ) {
2016-10-12 06:51:57 -07:00
c . siteURL = strings . TrimRight ( url , "/" )
2016-08-09 09:53:22 -04:00
}
2015-07-08 11:50:10 -04:00
func ( c * Context ) GetTeamURLFromTeam ( team * model . Team ) string {
return c . GetSiteURL ( ) + "/" + team . Name
}
func ( c * Context ) GetTeamURL ( ) string {
if ! c . teamURLValid {
2015-10-01 17:52:47 -07:00
c . SetTeamURLFromSession ( )
2015-07-08 11:50:10 -04:00
if ! c . teamURLValid {
2016-01-21 10:07:29 -03:00
l4g . Debug ( utils . T ( "api.context.invalid_team_url.debug" ) )
2015-07-08 11:50:10 -04:00
}
}
return c . teamURL
}
func ( c * Context ) GetSiteURL ( ) string {
2016-08-09 09:53:22 -04:00
return c . siteURL
2015-07-08 11:50:10 -04:00
}
2016-09-13 12:42:48 -04:00
func ( c * Context ) GetCurrentTeamMember ( ) * model . TeamMember {
return c . Session . GetTeamByTeamId ( c . TeamId )
}
2016-04-21 22:37:01 -07:00
func IsApiCall ( r * http . Request ) bool {
return strings . Index ( r . URL . Path , "/api/" ) == 0
}
2015-06-14 23:53:32 -08:00
func GetIpAddress ( r * http . Request ) string {
address := r . Header . Get ( model . HEADER_FORWARDED )
2015-09-22 12:12:50 -07:00
if len ( address ) == 0 {
address = r . Header . Get ( model . HEADER_REAL_IP )
}
2015-06-14 23:53:32 -08:00
if len ( address ) == 0 {
address , _ , _ = net . SplitHostPort ( r . RemoteAddr )
}
return address
}
func RenderWebError ( err * model . AppError , w http . ResponseWriter , r * http . Request ) {
2016-04-01 11:48:19 -04:00
T , _ := utils . GetTranslationsAndLocale ( w , r )
title := T ( "api.templates.error.title" , map [ string ] interface { } { "SiteName" : utils . ClientCfg [ "SiteName" ] } )
message := err . Message
details := err . DetailedError
link := "/"
linkMessage := T ( "api.templates.error.link" )
2016-07-05 15:49:00 -04:00
status := http . StatusTemporaryRedirect
if err . StatusCode != http . StatusInternalServerError {
status = err . StatusCode
}
2016-04-01 11:48:19 -04:00
http . Redirect (
w ,
r ,
"/error?title=" + url . QueryEscape ( title ) +
"&message=" + url . QueryEscape ( message ) +
"&details=" + url . QueryEscape ( details ) +
"&link=" + url . QueryEscape ( link ) +
"&linkmessage=" + url . QueryEscape ( linkMessage ) ,
2016-07-05 15:49:00 -04:00
status )
2015-06-14 23:53:32 -08:00
}
func Handle404 ( w http . ResponseWriter , r * http . Request ) {
2016-01-21 10:07:29 -03:00
err := model . NewLocAppError ( "Handle404" , "api.context.404.app_error" , nil , "" )
2016-04-21 22:37:01 -07:00
err . Translate ( utils . T )
2015-06-14 23:53:32 -08:00
err . StatusCode = http . StatusNotFound
2016-06-29 04:16:20 -08:00
2016-08-22 06:06:35 -08:00
l4g . Debug ( "%v: code=404 ip=%v" , r . URL . Path , GetIpAddress ( r ) )
2016-04-21 22:37:01 -07:00
if IsApiCall ( r ) {
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?"
w . Write ( [ ] byte ( err . ToJson ( ) ) )
} else {
RenderWebError ( err , w , r )
}
2015-06-14 23:53:32 -08:00
}
2015-09-16 15:49:12 -04:00
2016-01-20 13:36:16 -06:00
func GetSession ( token string ) * model . Session {
2016-12-19 10:16:22 -05:00
metrics := einterfaces . GetMetricsInterface ( )
2015-10-16 19:05:55 -07:00
var session * model . Session
if ts , ok := sessionCache . Get ( token ) ; ok {
session = ts . ( * model . Session )
2016-12-19 10:16:22 -05:00
if metrics != nil {
metrics . IncrementMemCacheHitCounter ( "Session" )
}
} else {
if metrics != nil {
metrics . IncrementMemCacheMissCounter ( "Session" )
}
2015-10-16 19:05:55 -07:00
}
if session == nil {
2016-01-20 13:36:16 -06:00
if sessionResult := <- Srv . Store . Session ( ) . Get ( token ) ; sessionResult . Err != nil {
2016-01-21 10:07:29 -03:00
l4g . Error ( utils . T ( "api.context.invalid_token.error" ) , token , sessionResult . Err . DetailedError )
2015-10-16 19:05:55 -07:00
} else {
session = sessionResult . Data . ( * model . Session )
2016-01-05 11:13:25 -06:00
2016-05-17 13:55:51 -07:00
if session . IsExpired ( ) || session . Token != token {
2016-01-05 11:13:25 -06:00
return nil
} else {
AddSessionToCache ( session )
return session
}
2015-10-16 19:05:55 -07:00
}
}
return session
}
2016-04-21 22:37:01 -07:00
func RemoveAllSessionsForUserId ( userId string ) {
2016-10-25 05:56:06 -07:00
RemoveAllSessionsForUserIdSkipClusterSend ( userId )
if einterfaces . GetClusterInterface ( ) != nil {
einterfaces . GetClusterInterface ( ) . RemoveAllSessionsForUserId ( userId )
}
}
func RemoveAllSessionsForUserIdSkipClusterSend ( userId string ) {
2016-04-21 22:37:01 -07:00
keys := sessionCache . Keys ( )
for _ , key := range keys {
if ts , ok := sessionCache . Get ( key ) ; ok {
session := ts . ( * model . Session )
if session . UserId == userId {
sessionCache . Remove ( key )
}
}
}
2016-08-04 09:25:37 -08:00
2016-12-22 07:52:02 -05:00
InvalidateWebConnSessionCacheForUser ( userId )
2016-04-21 22:37:01 -07:00
}
2015-09-16 15:49:12 -04:00
func AddSessionToCache ( session * model . Session ) {
2016-01-05 11:13:25 -06:00
sessionCache . AddWithExpiresInSecs ( session . Token , session , int64 ( * utils . Cfg . ServiceSettings . SessionCacheInMinutes * 60 ) )
2015-09-16 15:49:12 -04:00
}
2016-12-08 07:18:15 -08:00
func InvalidateAllCaches ( ) {
l4g . Info ( utils . T ( "api.context.invalidate_all_caches" ) )
sessionCache . Purge ( )
ClearStatusCache ( )
store . ClearChannelCaches ( )
store . ClearUserCaches ( )
2016-12-13 22:24:24 -05:00
store . ClearPostCaches ( )
2016-12-08 07:18:15 -08:00
}
2016-12-20 16:55:22 +01:00
func ( c * Context ) CheckTeamId ( ) {
if c . TeamId != "" && c . Session . GetTeamByTeamId ( c . TeamId ) == nil {
if HasPermissionToContext ( c , model . PERMISSION_MANAGE_SYSTEM ) {
if result := <- Srv . Store . Team ( ) . Get ( c . TeamId ) ; result . Err != nil {
c . Err = result . Err
c . Err . StatusCode = http . StatusBadRequest
return
}
} else {
// just return because it fail on the HasPermissionToContext and the error is already on the Context c.Err
return
}
}
}