summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NOTICE.txt33
-rw-r--r--api/api.go2
-rw-r--r--api/context.go34
-rw-r--r--api/server.go8
-rw-r--r--config/config.json1
-rw-r--r--i18n/en.json2
-rw-r--r--i18n/es.json2
-rw-r--r--i18n/pt.json4
-rw-r--r--mattermost.go2
-rw-r--r--model/config.go6
-rw-r--r--model/search_params.go4
-rw-r--r--model/search_params_test.go4
-rw-r--r--model/utils.go1
-rw-r--r--utils/config.go2
-rw-r--r--web/react/components/admin_console/service_settings.jsx35
-rw-r--r--web/react/components/get_team_invite_link_modal.jsx4
-rw-r--r--web/static/i18n/en.json5
-rw-r--r--web/static/i18n/es.json4
-rw-r--r--web/static/i18n/pt.json1
19 files changed, 139 insertions, 15 deletions
diff --git a/NOTICE.txt b/NOTICE.txt
index b39ee7cc9..8491e2f17 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1638,3 +1638,36 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+---
+
+This product contains a modified portion of 'fastclick', a library for eliminating the delay between a physical tap and the firing of a click event on mobile browsers.
+by FT Labs.
+
+* HOMEPAGE:
+ * https://github.com/ftlabs/fastclick
+
+* LICENSE:
+
+Copyright (c) 2014 The Financial Times Ltd.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/api/api.go b/api/api.go
index d202172d0..4fecd3dd4 100644
--- a/api/api.go
+++ b/api/api.go
@@ -36,7 +36,7 @@ func (me *ServerTemplatePage) Render() string {
T := utils.GetUserTranslations(me.Locale)
me.Props["Footer"] = T("api.templates.email_footer")
me.Html["EmailInfo"] = template.HTML(T("api.templates.email_info",
- map[string]interface{}{"FeedbackEmail": me.ClientCfg["FeedbackEmail"], "SiteName": me.ClientCfg["SiteName"]}))
+ map[string]interface{}{"SupportEmail": me.ClientCfg["SupportEmail"], "SiteName": me.ClientCfg["SiteName"]}))
if err := ServerTemplates.ExecuteTemplate(&text, me.TemplateName, me); err != nil {
l4g.Error(utils.T("api.api.render.error"), me.TemplateName, err)
diff --git a/api/context.go b/api/context.go
index 9e05c5d87..edcdcbfef 100644
--- a/api/context.go
+++ b/api/context.go
@@ -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"
diff --git a/api/server.go b/api/server.go
index 070ed7a70..b84066cbe 100644
--- a/api/server.go
+++ b/api/server.go
@@ -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() {
diff --git a/config/config.json b/config/config.json
index 2795546f8..b211b16d3 100644
--- a/config/config.json
+++ b/config/config.json
@@ -15,6 +15,7 @@
"EnableDeveloper": false,
"EnableSecurityFixAlert": true,
"EnableInsecureOutgoingConnections": false,
+ "AllowCorsFrom": "",
"SessionLengthWebInDays": 30,
"SessionLengthMobileInDays": 30,
"SessionLengthSSOInDays": 30,
diff --git a/i18n/en.json b/i18n/en.json
index 2b125feca..0f8b5de7c 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1113,7 +1113,7 @@
},
{
"id": "api.templates.email_info",
- "translation": "Any questions at all, mail us any time: <a href='mailto:{{.FeedbackEmail}}' style='text-decoration: none; color:#2389D7;'>{{.FeedbackEmail}}</a>.<br>Best wishes,<br>The {{.SiteName}} Team<br>"
+ "translation": "Any questions at all, mail us any time: <a href='mailto:{{.SupportEmail}}' style='text-decoration: none; color:#2389D7;'>{{.SupportEmail}}</a>.<br>Best wishes,<br>The {{.SiteName}} Team<br>"
},
{
"id": "api.templates.error.link",
diff --git a/i18n/es.json b/i18n/es.json
index 1426195dd..6670b7f5b 100644
--- a/i18n/es.json
+++ b/i18n/es.json
@@ -1113,7 +1113,7 @@
},
{
"id": "api.templates.email_info",
- "translation": "Si tienes alguna pregunta, escribenos en cualquier momento a: <a href=\"mailto:{{.FeedbackEmail}}\" style=\"text-decoration: none; color:#2389D7;\">{{.FeedbackEmail}}</a>.<br>Los mejores deseos,<br>El Equipo {{.SiteName}}<br>"
+ "translation": "Si tienes alguna pregunta, escribenos en cualquier momento a: <a href=\"mailto:{{.SupportEmail}}\" style=\"text-decoration: none; color:#2389D7;\">{{.SupportEmail}}</a>.<br>Los mejores deseos,<br>El Equipo {{.SiteName}}<br>"
},
{
"id": "api.templates.error.link",
diff --git a/i18n/pt.json b/i18n/pt.json
index a70cccf4d..e01db6b22 100644
--- a/i18n/pt.json
+++ b/i18n/pt.json
@@ -1113,7 +1113,7 @@
},
{
"id": "api.templates.email_info",
- "translation": "Qualquer dúvida, envie-nos a qualquer momento: <a href='mailto:{{.FeedbackEmail}}' style='text-decoration: none; color:#2389D7;'>{{.FeedbackEmail}}</a>.<br>Nossos melhores cumprimentos,<br>Equipe {{.SiteName}}<br>"
+ "translation": "Qualquer dúvida, envie-nos a qualquer momento: <a href='mailto:{{.SupportEmail}}' style='text-decoration: none; color:#2389D7;'>{{.SupportEmail}}</a>.<br>Nossos melhores cumprimentos,<br>Equipe {{.SiteName}}<br>"
},
{
"id": "api.templates.error.link",
@@ -3587,4 +3587,4 @@
"id": "web.watcher_fail.error",
"translation": "Falha ao adicionar diretório observador %v"
}
-] \ No newline at end of file
+]
diff --git a/mattermost.go b/mattermost.go
index 7446fe791..b305aac3c 100644
--- a/mattermost.go
+++ b/mattermost.go
@@ -282,7 +282,7 @@ func cmdCreateTeam() {
team.DisplayName = flagTeamName
team.Name = flagTeamName
team.Email = flagEmail
- team.Type = model.TEAM_INVITE
+ team.Type = model.TEAM_OPEN
api.CreateTeam(c, team)
if c.Err != nil {
diff --git a/model/config.go b/model/config.go
index aa3dd3586..82c51224e 100644
--- a/model/config.go
+++ b/model/config.go
@@ -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 {
diff --git a/model/search_params.go b/model/search_params.go
index 9a7406a07..d31782691 100644
--- a/model/search_params.go
+++ b/model/search_params.go
@@ -89,9 +89,9 @@ func parseSearchFlags(input []string) ([]string, [][2]string) {
}
if !isFlag {
- // trim off surrounding punctuation
+ // trim off surrounding punctuation (note that we leave trailing asterisks to allow wildcards)
word = puncStart.ReplaceAllString(word, "")
- word = puncEnd.ReplaceAllString(word, "")
+ word = puncEndWildcard.ReplaceAllString(word, "")
// and remove extra pound #s
word = hashtagStart.ReplaceAllString(word, "#")
diff --git a/model/search_params_test.go b/model/search_params_test.go
index 59eb0a113..7138d82c4 100644
--- a/model/search_params_test.go
+++ b/model/search_params_test.go
@@ -216,4 +216,8 @@ func TestParseSearchParams(t *testing.T) {
if sp := ParseSearchParams("##hashtag +#plus+"); len(sp) != 1 || sp[0].Terms != "#hashtag #plus" || sp[0].IsHashtag != true || len(sp[0].InChannels) != 0 || len(sp[0].FromUsers) != 0 {
t.Fatalf("Incorrect output from parse search params: %v", sp[0])
}
+
+ if sp := ParseSearchParams("wildcar*"); len(sp) != 1 || sp[0].Terms != "wildcar*" || sp[0].IsHashtag != false || len(sp[0].InChannels) != 0 || len(sp[0].FromUsers) != 0 {
+ t.Fatalf("Incorrect output from parse search params: %v", sp[0])
+ }
}
diff --git a/model/utils.go b/model/utils.go
index 695d4a0cb..808c89e30 100644
--- a/model/utils.go
+++ b/model/utils.go
@@ -291,6 +291,7 @@ var validHashtag = regexp.MustCompile(`^(#[A-Za-zäöüÄÖÜß]+[A-Za-z0-9äöÃ
var puncStart = regexp.MustCompile(`^[.,()&$!\?\[\]{}':;\\<>\-+=%^*|]+`)
var hashtagStart = regexp.MustCompile(`^#{2,}`)
var puncEnd = regexp.MustCompile(`[.,()&$#!\?\[\]{}':;\\<>\-+=%^*|]+$`)
+var puncEndWildcard = regexp.MustCompile(`[.,()&$#!\?\[\]{}':;\\<>\-+=%^|]+$`)
func ParseHashtags(text string) (string, string) {
words := strings.Fields(text)
diff --git a/utils/config.go b/utils/config.go
index 3e4ba5c5b..63906c345 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -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
}
diff --git a/web/react/components/admin_console/service_settings.jsx b/web/react/components/admin_console/service_settings.jsx
index 047c7eb8d..9ed81b6a3 100644
--- a/web/react/components/admin_console/service_settings.jsx
+++ b/web/react/components/admin_console/service_settings.jsx
@@ -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,
() => {
@@ -766,6 +772,35 @@ class ServiceSettings extends React.Component {
<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'
htmlFor='SessionLengthWebInDays'
>
<FormattedMessage
diff --git a/web/react/components/get_team_invite_link_modal.jsx b/web/react/components/get_team_invite_link_modal.jsx
index 299729250..ba6164dbf 100644
--- a/web/react/components/get_team_invite_link_modal.jsx
+++ b/web/react/components/get_team_invite_link_modal.jsx
@@ -15,7 +15,7 @@ const holders = defineMessages({
},
help: {
id: 'get_team_invite_link_modal.help',
- defaultMessage: 'Send teammates the link below for them to sign-up to this team site.'
+ defaultMessage: 'Send teammates the link below for them to sign-up to this team site. The Team Invite Link can be shared with multiple teammates as it does not change unless it\'s regenerated in Team Settings by a Team Admin.'
},
helpDisabled: {
id: 'get_team_invite_link_modal.helpDisabled',
@@ -73,4 +73,4 @@ GetTeamInviteLinkModal.propTypes = {
intl: intlShape.isRequired
};
-export default injectIntl(GetTeamInviteLinkModal); \ No newline at end of file
+export default injectIntl(GetTeamInviteLinkModal);
diff --git a/web/static/i18n/en.json b/web/static/i18n/en.json
index 14ef0fb46..7d427935c 100644
--- a/web/static/i18n/en.json
+++ b/web/static/i18n/en.json
@@ -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",
@@ -699,7 +702,7 @@
"get_link.copy": "Copy Link",
"get_post_link_modal.help": "The link below allows authorized users to see your post.",
"get_post_link_modal.title": "Copy Permalink",
- "get_team_invite_link_modal.help": "Send teammates the link below for them to sign-up to this team site.",
+ "get_team_invite_link_modal.help": "Send teammates the link below for them to sign-up to this team site. The Team Invite Link can be shared with multiple teammates as it does not change unless it's regenerated in Team Settings by a Team Admin.",
"get_team_invite_link_modal.helpDisabled": "User creation has been disabled for your team. Please ask your team administrator for details.",
"get_team_invite_link_modal.title": "Team Invite Link",
"intro_messages.DM": "This is the start of your direct message history with {teammate}.<br />Direct messages and files shared here are not shown to people outside this area.",
diff --git a/web/static/i18n/es.json b/web/static/i18n/es.json
index 09abcf530..e3f23e77e 100644
--- a/web/static/i18n/es.json
+++ b/web/static/i18n/es.json
@@ -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",
@@ -699,7 +702,6 @@
"get_link.copy": "Copiar Enlace",
"get_post_link_modal.help": "En enlace de abajo permite a los usuarios autorizados a ver tu mensaje.",
"get_post_link_modal.title": "Copiar enlace Permanente",
- "get_team_invite_link_modal.help": "Enviar a los compañeros de equipo el enlace que se muestra a continuación para permitirles registrarse a este equipo.",
"get_team_invite_link_modal.helpDisabled": "La creación de usuario ha sido deshabilitada para tu equipo. Por favor solicita más detalles a tu administrador de equipo.",
"get_team_invite_link_modal.title": "Enlace de Invitación al Equipo",
"intro_messages.DM": "Este es el inicio de tu historial de mensajes directos con {teammate}.<br />Los mensajes directos y archivos que se comparten aquí no son mostrados a personas fuera de esta área.",
diff --git a/web/static/i18n/pt.json b/web/static/i18n/pt.json
index ef5b9a2ab..f79dae461 100644
--- a/web/static/i18n/pt.json
+++ b/web/static/i18n/pt.json
@@ -699,7 +699,6 @@
"get_link.copy": "Copiar Link",
"get_post_link_modal.help": "O link abaixo permite que usuários autorizados possam ver seus posts.",
"get_post_link_modal.title": "Copiar Permalink",
- "get_team_invite_link_modal.help": "Enviar a equipe de trabalho o link abaixo para eles se inscreverem nesta equipe.",
"get_team_invite_link_modal.helpDisabled": "Criação de usuários está desabilitada para sua equipe. Por favor peça ao administrador de equipe por detalhes.",
"get_team_invite_link_modal.title": "Link para Convite de Equipe",
"intro_messages.DM": "Este é o início do seu histórico de mensagens diretas com {teammate}.<br />Mensagens diretas e arquivos compartilhados aqui não são mostrados para pessoas de fora desta área.",