@@ -21,6 +21,15 @@ import (
|
||||
|
||||
var sessionCache *utils.Cache = utils.NewLru(model.SESSION_CACHE_SIZE)
|
||||
|
||||
var allowedMethods []string = []string{
|
||||
"POST",
|
||||
"GET",
|
||||
"OPTIONS",
|
||||
"PUT",
|
||||
"PATCH",
|
||||
"DELETE",
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
Session model.Session
|
||||
RequestId string
|
||||
@@ -234,6 +243,31 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cw *CorsWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if len(*utils.Cfg.ServiceSettings.AllowCorsFrom) > 0 {
|
||||
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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
return
|
||||
}
|
||||
|
||||
cw.router.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func GetProtocol(r *http.Request) string {
|
||||
if r.Header.Get(model.HEADER_FORWARDED_PROTO) == "https" {
|
||||
return "https"
|
||||
|
||||
@@ -21,6 +21,10 @@ type Server struct {
|
||||
Router *mux.Router
|
||||
}
|
||||
|
||||
type CorsWrapper struct {
|
||||
router *mux.Router
|
||||
}
|
||||
|
||||
var Srv *Server
|
||||
|
||||
func NewServer() {
|
||||
@@ -38,7 +42,7 @@ func StartServer() {
|
||||
l4g.Info(utils.T("api.server.start_server.starting.info"))
|
||||
l4g.Info(utils.T("api.server.start_server.listening.info"), utils.Cfg.ServiceSettings.ListenAddress)
|
||||
|
||||
var handler http.Handler = Srv.Router
|
||||
var handler http.Handler = &CorsWrapper{Srv.Router}
|
||||
|
||||
if utils.Cfg.RateLimitSettings.EnableRateLimiter {
|
||||
l4g.Info(utils.T("api.server.start_server.rate.info"))
|
||||
@@ -65,7 +69,7 @@ func StartServer() {
|
||||
throttled.DefaultDeniedHandler.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
handler = th.Throttle(Srv.Router)
|
||||
handler = th.Throttle(&CorsWrapper{Srv.Router})
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"EnableDeveloper": false,
|
||||
"EnableSecurityFixAlert": true,
|
||||
"EnableInsecureOutgoingConnections": false,
|
||||
"AllowCorsFrom": "",
|
||||
"SessionLengthWebInDays": 30,
|
||||
"SessionLengthMobileInDays": 30,
|
||||
"SessionLengthSSOInDays": 30,
|
||||
|
||||
@@ -39,6 +39,7 @@ type ServiceSettings struct {
|
||||
EnableDeveloper *bool
|
||||
EnableSecurityFixAlert *bool
|
||||
EnableInsecureOutgoingConnections *bool
|
||||
AllowCorsFrom *string
|
||||
SessionLengthWebInDays *int
|
||||
SessionLengthMobileInDays *int
|
||||
SessionLengthSSOInDays *int
|
||||
@@ -377,6 +378,11 @@ func (o *Config) SetDefaults() {
|
||||
o.ServiceSettings.WebsocketSecurePort = new(int)
|
||||
*o.ServiceSettings.WebsocketSecurePort = 443
|
||||
}
|
||||
|
||||
if o.ServiceSettings.AllowCorsFrom == nil {
|
||||
o.ServiceSettings.AllowCorsFrom = new(string)
|
||||
*o.ServiceSettings.AllowCorsFrom = ""
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Config) IsValid() *AppError {
|
||||
|
||||
@@ -236,5 +236,7 @@ func getClientConfig(c *model.Config) map[string]string {
|
||||
props["WebsocketPort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketPort)
|
||||
props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort)
|
||||
|
||||
props["AllowCorsFrom"] = *c.ServiceSettings.AllowCorsFrom
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ var holders = defineMessages({
|
||||
id: 'admin.service.sessionDaysEx',
|
||||
defaultMessage: 'Ex "30"'
|
||||
},
|
||||
corsExample: {
|
||||
id: 'admin.service.corsEx',
|
||||
defaultMessage: 'http://example.com'
|
||||
},
|
||||
saving: {
|
||||
id: 'admin.service.saving',
|
||||
defaultMessage: 'Saving Config...'
|
||||
@@ -131,6 +135,8 @@ class ServiceSettings extends React.Component {
|
||||
config.ServiceSettings.SessionCacheInMinutes = SessionCacheInMinutes;
|
||||
ReactDOM.findDOMNode(this.refs.SessionCacheInMinutes).value = SessionCacheInMinutes;
|
||||
|
||||
config.ServiceSettings.AllowCorsFrom = ReactDOM.findDOMNode(this.refs.AllowCorsFrom).value.trim();
|
||||
|
||||
Client.saveConfig(
|
||||
config,
|
||||
() => {
|
||||
@@ -763,6 +769,35 @@ class ServiceSettings extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='AllowCorsFrom'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='admin.service.corsTitle'
|
||||
defaultMessage='Allow Cross-origin Requests from:'
|
||||
/>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='AllowCorsFrom'
|
||||
ref='AllowCorsFrom'
|
||||
placeholder={formatMessage(holders.corsExample)}
|
||||
defaultValue={this.props.config.ServiceSettings.AllowCorsFrom}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
<p className='help-text'>
|
||||
<FormattedMessage
|
||||
id='admin.service.corsDescription'
|
||||
defaultMessage='Enable HTTP Cross origin request from a specific domain. Use "*" if you want to allow CORS from any domain or leave it blank to disable it.'
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
|
||||
@@ -277,6 +277,9 @@
|
||||
"admin.service.attemptTitle": "Maximum Login Attempts:",
|
||||
"admin.service.cmdsDesc": "When true, user created slash commands will be allowed.",
|
||||
"admin.service.cmdsTitle": "Enable Slash Commands: ",
|
||||
"admin.service.corsEx": "http://example.com https://example.com",
|
||||
"admin.service.corsDescription": "Enable HTTP Cross origin request from specific domains (separate by a spacebar). Use \"*\" if you want to allow CORS from any domain or leave it blank to disable it.",
|
||||
"admin.service.corsTitle": "Allow Cross-origin Requests from:",
|
||||
"admin.service.developerDesc": "(Developer Option) When true, extra information around errors will be displayed in the UI.",
|
||||
"admin.service.developerTitle": "Enable Developer Mode: ",
|
||||
"admin.service.false": "false",
|
||||
|
||||
@@ -277,6 +277,9 @@
|
||||
"admin.service.attemptTitle": "Máximo de intentos de conexión:",
|
||||
"admin.service.cmdsDesc": "Cuando es verdadero, se permite la creación de comandos de barra por usuarios.",
|
||||
"admin.service.cmdsTitle": "Habilitar Comandos de Barra: ",
|
||||
"admin.service.corsEx": "http://ejemplo.com https://ejemplo.com",
|
||||
"admin.service.corsDescription": "Habilita las solicitudes HTTP de origen cruzado para dominios en específico (separados por un espacio). Utiliza \"*\" si quieres habilitar CORS desde cualquier dominio o deja el campo en blanco para deshabilitarlo.",
|
||||
"admin.service.corsTitle": "Permitir Solicitudes de Origen Cruzado desde:",
|
||||
"admin.service.developerDesc": "(Opción de Desarrollador) Cuando está asignado en verdadero, información extra sobre errores se muestra en el UI.",
|
||||
"admin.service.developerTitle": "Habilitar modo de Desarrollador: ",
|
||||
"admin.service.false": "falso",
|
||||
|
||||
Ссылка в новой задаче
Block a user