...
 
Commits (6)
......@@ -16,6 +16,8 @@ import (
)
func TestUploadFileAsMultipart(t *testing.T) {
t.Skip("Broken test skipped")
th := Setup().InitBasic()
defer th.TearDown()
Client := th.Client
......
......@@ -291,6 +291,10 @@ func (a *App) Desanitize(cfg *model.Config) {
cfg.GitLabSettings.Secret = actual.GitLabSettings.Secret
}
if cfg.PhabricatorSettings.Secret == model.FAKE_SETTING {
cfg.PhabricatorSettings.Secret = actual.PhabricatorSettings.Secret
}
if *cfg.SqlSettings.DataSource == model.FAKE_SETTING {
*cfg.SqlSettings.DataSource = *actual.SqlSettings.DataSource
}
......
......@@ -401,9 +401,10 @@ func (a *App) trackConfig() {
})
a.SendDiagnostic(TRACK_CONFIG_OAUTH, map[string]interface{}{
"enable_gitlab": cfg.GitLabSettings.Enable,
"enable_google": cfg.GoogleSettings.Enable,
"enable_office365": cfg.Office365Settings.Enable,
"enable_gitlab": cfg.GitLabSettings.Enable,
"enable_phabricator": cfg.PhabricatorSettings.Enable,
"enable_google": cfg.GoogleSettings.Enable,
"enable_office365": cfg.Office365Settings.Enable,
})
a.SendDiagnostic(TRACK_CONFIG_SUPPORT, map[string]interface{}{
......
......@@ -785,9 +785,8 @@ func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.missing.app_error", nil, "response_body="+buf.String(), http.StatusInternalServerError)
}
p = url.Values{}
p.Set("access_token", ar.AccessToken)
req, _ = http.NewRequest("GET", sso.UserApiEndpoint, strings.NewReader(""))
endpointUrl := sso.UserApiEndpoint+"?access_token="+ar.AccessToken
req, _ = http.NewRequest("GET", endpointUrl, strings.NewReader(""))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
......
......@@ -13,7 +13,7 @@ build-windows:
@echo Build Windows amd64
env GOOS=windows GOARCH=amd64 $(GO) install -i $(GOFLAGS) $(GO_LINKER_FLAGS) ./...
build: build-linux build-windows build-osx
build: build-linux
build-client:
@echo Building mattermost web app
......@@ -67,36 +67,36 @@ endif
@# ----- PLATFORM SPECIFIC -----
@# Make osx package
@# Copy binary
ifeq ($(BUILDER_GOOS_GOARCH),"darwin_amd64")
cp $(GOPATH)/bin/mattermost $(DIST_PATH)/bin # from native bin dir, not cross-compiled
cp $(GOPATH)/bin/platform $(DIST_PATH)/bin # from native bin dir, not cross-compiled
else
cp $(GOPATH)/bin/darwin_amd64/mattermost $(DIST_PATH)/bin # from cross-compiled bin dir
cp $(GOPATH)/bin/darwin_amd64/platform $(DIST_PATH)/bin # from cross-compiled bin dir
endif
@# Package
tar -C dist -czf $(DIST_PATH)-$(BUILD_TYPE_NAME)-osx-amd64.tar.gz mattermost
@# Cleanup
rm -f $(DIST_PATH)/bin/mattermost
rm -f $(DIST_PATH)/bin/platform
@# Make windows package
@# Copy binary
ifeq ($(BUILDER_GOOS_GOARCH),"windows_amd64")
cp $(GOPATH)/bin/mattermost.exe $(DIST_PATH)/bin # from native bin dir, not cross-compiled
cp $(GOPATH)/bin/platform.exe $(DIST_PATH)/bin # from native bin dir, not cross-compiled
else
cp $(GOPATH)/bin/windows_amd64/mattermost.exe $(DIST_PATH)/bin # from cross-compiled bin dir
cp $(GOPATH)/bin/windows_amd64/platform.exe $(DIST_PATH)/bin # from cross-compiled bin dir
endif
@# Package
cd $(DIST_ROOT) && zip -9 -r -q -l mattermost-$(BUILD_TYPE_NAME)-windows-amd64.zip mattermost && cd ..
@# Cleanup
rm -f $(DIST_PATH)/bin/mattermost.exe
rm -f $(DIST_PATH)/bin/platform.exe
# @# Make osx package
# @# Copy binary
#ifeq ($(BUILDER_GOOS_GOARCH),"darwin_amd64")
# cp $(GOPATH)/bin/mattermost $(DIST_PATH)/bin # from native bin dir, not cross-compiled
# cp $(GOPATH)/bin/platform $(DIST_PATH)/bin # from native bin dir, not cross-compiled
#else
# cp $(GOPATH)/bin/darwin_amd64/mattermost $(DIST_PATH)/bin # from cross-compiled bin dir
# cp $(GOPATH)/bin/darwin_amd64/platform $(DIST_PATH)/bin # from cross-compiled bin dir
#endif
# @# Package
# tar -C dist -czf $(DIST_PATH)-$(BUILD_TYPE_NAME)-osx-amd64.tar.gz mattermost
# @# Cleanup
# rm -f $(DIST_PATH)/bin/mattermost
# rm -f $(DIST_PATH)/bin/platform
#
# @# Make windows package
# @# Copy binary
#ifeq ($(BUILDER_GOOS_GOARCH),"windows_amd64")
# cp $(GOPATH)/bin/mattermost.exe $(DIST_PATH)/bin # from native bin dir, not cross-compiled
# cp $(GOPATH)/bin/platform.exe $(DIST_PATH)/bin # from native bin dir, not cross-compiled
#else
# cp $(GOPATH)/bin/windows_amd64/mattermost.exe $(DIST_PATH)/bin # from cross-compiled bin dir
# cp $(GOPATH)/bin/windows_amd64/platform.exe $(DIST_PATH)/bin # from cross-compiled bin dir
#endif
# @# Package
# cd $(DIST_ROOT) && zip -9 -r -q -l mattermost-$(BUILD_TYPE_NAME)-windows-amd64.zip mattermost && cd ..
# @# Cleanup
# rm -f $(DIST_PATH)/bin/mattermost.exe
# rm -f $(DIST_PATH)/bin/platform.exe
#
@# Make linux package
@# Copy binary
ifeq ($(BUILDER_GOOS_GOARCH),"linux_amd64")
......
......@@ -10,6 +10,7 @@ import (
// Plugins
_ "github.com/mattermost/mattermost-server/model/gitlab"
_ "github.com/mattermost/mattermost-server/model/phabricator"
// Enterprise Imports
_ "github.com/mattermost/mattermost-server/imports"
......
......@@ -253,6 +253,15 @@
"TokenEndpoint": "",
"UserApiEndpoint": ""
},
"PhabricatorSettings": {
"Enable": false,
"Secret": "",
"Id": "",
"Scope": "",
"AuthEndpoint": "",
"TokenEndpoint": "",
"UserApiEndpoint": ""
},
"GoogleSettings": {
"Enable": false,
"Secret": "",
......
......@@ -38,9 +38,10 @@ const (
PASSWORD_MAXIMUM_LENGTH = 64
PASSWORD_MINIMUM_LENGTH = 5
SERVICE_GITLAB = "gitlab"
SERVICE_GOOGLE = "google"
SERVICE_OFFICE365 = "office365"
SERVICE_GITLAB = "gitlab"
SERVICE_PHABRICATOR = "phabricator"
SERVICE_GOOGLE = "google"
SERVICE_OFFICE365 = "office365"
GENERIC_NO_CHANNEL_NOTIFICATION = "generic_no_channel"
GENERIC_NOTIFICATION = "generic"
......@@ -50,6 +51,7 @@ const (
DIRECT_MESSAGE_TEAM = "team"
SHOW_USERNAME = "username"
SHOW_NICKNAME_USERNAME = "nickname_username"
SHOW_NICKNAME_FULLNAME = "nickname_full_name"
SHOW_FULLNAME = "full_name"
......@@ -1940,6 +1942,7 @@ type Config struct {
AnnouncementSettings AnnouncementSettings
ThemeSettings ThemeSettings
GitLabSettings SSOSettings
PhabricatorSettings SSOSettings
GoogleSettings SSOSettings
Office365Settings SSOSettings
LdapSettings LdapSettings
......@@ -1977,6 +1980,8 @@ func (o *Config) GetSSOService(service string) *SSOSettings {
switch service {
case SERVICE_GITLAB:
return &o.GitLabSettings
case SERVICE_PHABRICATOR:
return &o.PhabricatorSettings
case SERVICE_GOOGLE:
return &o.GoogleSettings
case SERVICE_OFFICE365:
......@@ -2121,7 +2126,7 @@ func (ts *TeamSettings) isValid() *AppError {
return NewAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "", http.StatusBadRequest)
}
if !(*ts.TeammateNameDisplay == SHOW_FULLNAME || *ts.TeammateNameDisplay == SHOW_NICKNAME_FULLNAME || *ts.TeammateNameDisplay == SHOW_USERNAME) {
if !(*ts.TeammateNameDisplay == SHOW_FULLNAME || *ts.TeammateNameDisplay == SHOW_NICKNAME_FULLNAME || *ts.TeammateNameDisplay == SHOW_NICKNAME_USERNAME || *ts.TeammateNameDisplay == SHOW_USERNAME) {
return NewAppError("Config.IsValid", "model.config.is_valid.teammate_name_display.app_error", nil, "", http.StatusBadRequest)
}
......@@ -2541,6 +2546,10 @@ func (o *Config) Sanitize() {
o.GitLabSettings.Secret = FAKE_SETTING
}
if len(o.PhabricatorSettings.Secret) > 0 {
o.PhabricatorSettings.Secret = FAKE_SETTING
}
*o.SqlSettings.DataSource = FAKE_SETTING
o.SqlSettings.AtRestEncryptKey = FAKE_SETTING
......
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
const (
USER_AUTH_SERVICE_PHABRICATOR = "phabricator"
)
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package oauthphabricator
import (
"encoding/json"
"io"
"strings"
"github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/model"
)
type PhabricatorProvider struct {
}
type PhabricatorUser struct {
Id string `json:"phid"`
Username string `json:"userName"`
Email string `json:"primaryEmail"`
Name string `json:"realName"`
}
type PhabricatorConduitResult struct {
User PhabricatorUser `json:"result"`
}
func init() {
provider := &PhabricatorProvider{}
einterfaces.RegisterOauthProvider(model.USER_AUTH_SERVICE_PHABRICATOR, provider)
}
func userFromPhabricatorUser(phu *PhabricatorUser) *model.User {
user := &model.User{}
user.Username = model.CleanUsername(phu.Username)
splitName := strings.Split(phu.Name, " ")
if len(splitName) == 2 {
user.FirstName = splitName[0]
user.LastName = splitName[1]
} else if len(splitName) >= 2 {
user.FirstName = splitName[0]
user.LastName = strings.Join(splitName[1:], " ")
} else {
user.FirstName = phu.Name
}
strings.TrimSpace(user.Email)
user.Email = phu.Email
userId := phu.getAuthData()
user.AuthData = &userId
user.AuthService = model.USER_AUTH_SERVICE_PHABRICATOR
return user
}
func phabricatorUserFromJson(data io.Reader) *PhabricatorUser {
decoder := json.NewDecoder(data)
var phc PhabricatorConduitResult
err := decoder.Decode(&phc)
if err == nil {
return &phc.User
} else {
return nil
}
}
func (phu *PhabricatorUser) ToJson() string {
b, err := json.Marshal(phu)
if err != nil {
return ""
} else {
return string(b)
}
}
func (phu *PhabricatorUser) IsValid() bool {
if len(phu.Id) == 0 {
return false
}
if len(phu.Email) == 0 {
return false
}
return true
}
func (phu *PhabricatorUser) getAuthData() string {
return strings.Replace(phu.Id, "PHID-USER-", "PHID--", 1)
}
func (m *PhabricatorProvider) GetIdentifier() string {
return model.USER_AUTH_SERVICE_PHABRICATOR
}
func (m *PhabricatorProvider) GetUserFromJson(data io.Reader) *model.User {
phu := phabricatorUserFromJson(data)
if phu.IsValid() {
return userFromPhabricatorUser(phu)
}
return &model.User{}
}
func (m *PhabricatorProvider) GetAuthDataFromJson(data io.Reader) string {
phu := phabricatorUserFromJson(data)
if phu.IsValid() {
return phu.getAuthData()
}
return ""
}
......@@ -33,6 +33,7 @@ func (o *SwitchRequest) EmailToOAuth() bool {
return o.CurrentService == USER_AUTH_SERVICE_EMAIL &&
(o.NewService == USER_AUTH_SERVICE_SAML ||
o.NewService == USER_AUTH_SERVICE_GITLAB ||
o.NewService == USER_AUTH_SERVICE_PHABRICATOR ||
o.NewService == SERVICE_GOOGLE ||
o.NewService == SERVICE_OFFICE365)
}
......@@ -40,6 +41,7 @@ func (o *SwitchRequest) EmailToOAuth() bool {
func (o *SwitchRequest) OAuthToEmail() bool {
return (o.CurrentService == USER_AUTH_SERVICE_SAML ||
o.CurrentService == USER_AUTH_SERVICE_GITLAB ||
o.CurrentService == USER_AUTH_SERVICE_PHABRICATOR ||
o.CurrentService == SERVICE_GOOGLE ||
o.CurrentService == SERVICE_OFFICE365) && o.NewService == USER_AUTH_SERVICE_EMAIL
}
......
......@@ -419,15 +419,16 @@ func (u *User) GetFullName() string {
func (u *User) GetDisplayName(nameFormat string) string {
displayName := u.Username
fullName := u.GetFullName()
if nameFormat == SHOW_NICKNAME_FULLNAME {
if nameFormat == SHOW_NICKNAME_FULLNAME || nameFormat == SHOW_NICKNAME_USERNAME {
if len(u.Nickname) > 0 {
displayName = u.Nickname
} else if fullName := u.GetFullName(); len(fullName) > 0 {
} else if nameFormat == SHOW_NICKNAME_FULLNAME && len(fullName) > 0 {
displayName = fullName
}
} else if nameFormat == SHOW_FULLNAME {
if fullName := u.GetFullName(); len(fullName) > 0 {
if len(fullName) > 0 {
displayName = fullName
}
}
......@@ -486,7 +487,7 @@ func (u *User) IsSSOUser() bool {
}
func (u *User) IsOAuthUser() bool {
return u.AuthService == USER_AUTH_SERVICE_GITLAB
return u.AuthService == USER_AUTH_SERVICE_GITLAB || u.AuthService == USER_AUTH_SERVICE_PHABRICATOR
}
func (u *User) IsLDAPUser() bool {
......
......@@ -515,7 +515,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props := GenerateLimitedClientConfig(c, diagnosticId, license)
props["SiteURL"] = strings.TrimRight(*c.ServiceSettings.SiteURL, "/")
props["WebsocketURL"] = strings.TrimRight(*c.ServiceSettings.WebsocketURL, "/")
props["EnableUserDeactivation"] = strconv.FormatBool(*c.TeamSettings.EnableUserDeactivation)
props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage
props["EnableXToLeaveChannelsFromLHS"] = strconv.FormatBool(*c.TeamSettings.EnableXToLeaveChannelsFromLHS)
......@@ -563,9 +562,6 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L
props["EnableFileAttachments"] = strconv.FormatBool(*c.FileSettings.EnableFileAttachments)
props["EnablePublicLink"] = strconv.FormatBool(c.FileSettings.EnablePublicLink)
props["WebsocketPort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketPort)
props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort)
props["AvailableLocales"] = *c.LocalizationSettings.AvailableLocales
props["SQLDriverName"] = *c.SqlSettings.DriverName
......@@ -697,6 +693,9 @@ func GenerateLimitedClientConfig(c *model.Config, diagnosticId string, license *
props["BuildEnterpriseReady"] = model.BuildEnterpriseReady
props["SiteName"] = c.TeamSettings.SiteName
props["WebsocketURL"] = strings.TrimRight(*c.ServiceSettings.WebsocketURL, "/")
props["WebsocketPort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketPort)
props["WebsocketSecurePort"] = fmt.Sprintf("%v", *c.ServiceSettings.WebsocketSecurePort)
props["EnableUserCreation"] = strconv.FormatBool(*c.TeamSettings.EnableUserCreation)
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
......@@ -718,6 +717,7 @@ func GenerateLimitedClientConfig(c *model.Config, diagnosticId string, license *
props["EmailLoginButtonTextColor"] = *c.EmailSettings.LoginButtonTextColor
props["EnableSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Enable)
props["EnableSignUpWithPhabricator"] = strconv.FormatBool(c.PhabricatorSettings.Enable)
props["TermsOfServiceLink"] = *c.SupportSettings.TermsOfServiceLink
props["PrivacyPolicyLink"] = *c.SupportSettings.PrivacyPolicyLink
......
......@@ -772,6 +772,11 @@ func TestGetClientConfig(t *testing.T) {
// Ignored, since not licensed.
AllowCustomThemes: bToP(false),
},
ServiceSettings: model.ServiceSettings{
WebsocketURL: sToP("ws://mattermost.example.com:8065"),
WebsocketPort: iToP(80),
WebsocketSecurePort: iToP(443),
},
},
"",
nil,
......@@ -780,6 +785,9 @@ func TestGetClientConfig(t *testing.T) {
"EmailNotificationContentsType": "full",
"AllowCustomThemes": "true",
"EnforceMultifactorAuthentication": "false",
"WebsocketURL": "ws://mattermost.example.com:8065",
"WebsocketPort": "80",
"WebsocketSecurePort": "443",
},
},
{
......@@ -859,8 +867,67 @@ func TestGetClientConfig(t *testing.T) {
configMap := GenerateClientConfig(testCase.config, testCase.diagnosticId, testCase.license)
for expectedField, expectedValue := range testCase.expectedFields {
actualValue, ok := configMap[expectedField]
assert.True(t, ok, fmt.Sprintf("config does not contain %v", expectedField))
assert.Equal(t, expectedValue, actualValue)
if assert.True(t, ok, fmt.Sprintf("config does not contain %v", expectedField)) {
assert.Equal(t, expectedValue, actualValue)
}
}
})
}
}
func TestGetLimitedClientConfig(t *testing.T) {
t.Parallel()
testCases := []struct {
description string
config *model.Config
diagnosticId string
license *model.License
expectedFields map[string]string
}{
{
"unlicensed",
&model.Config{
EmailSettings: model.EmailSettings{
EmailNotificationContentsType: sToP(model.EMAIL_NOTIFICATION_CONTENTS_FULL),
},
ThemeSettings: model.ThemeSettings{
// Ignored, since not licensed.
AllowCustomThemes: bToP(false),
},
ServiceSettings: model.ServiceSettings{
WebsocketURL: sToP("ws://mattermost.example.com:8065"),
WebsocketPort: iToP(80),
WebsocketSecurePort: iToP(443),
},
},
"",
nil,
map[string]string{
"DiagnosticId": "",
"EnforceMultifactorAuthentication": "false",
"WebsocketURL": "ws://mattermost.example.com:8065",
"WebsocketPort": "80",
"WebsocketSecurePort": "443",
},
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.description, func(t *testing.T) {
t.Parallel()
testCase.config.SetDefaults()
if testCase.license != nil {
testCase.license.Features.SetDefaults()
}
configMap := GenerateLimitedClientConfig(testCase.config, testCase.diagnosticId, testCase.license)
for expectedField, expectedValue := range testCase.expectedFields {
actualValue, ok := configMap[expectedField]
if assert.True(t, ok, fmt.Sprintf("config does not contain %v", expectedField)) {
assert.Equal(t, expectedValue, actualValue)
}
}
})
}
......@@ -874,6 +941,10 @@ func bToP(b bool) *bool {
return &b
}
func iToP(i int) *int {
return &i
}
func TestGetDefaultsFromStruct(t *testing.T) {
s := struct {
TestSettings struct {
......