From 21d51f8c9094f434afed8d23d4790aea28a4c0df Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Tue, 26 Jan 2016 19:53:33 -0500 Subject: [PATCH 1/5] PLT-1586 adding LDAP/OAuth to iOS --- web/react/components/login.jsx | 2 +- web/templates/claim_account.html | 18 +++++++++++++-- web/templates/docs.html | 3 +++ web/templates/find_team.html | 3 +++ web/templates/login.html | 2 +- web/templates/password_reset.html | 16 ++++++++++++- web/templates/verify.html | 11 ++++++++- web/templates/welcome.html | 37 ------------------------------- 8 files changed, 49 insertions(+), 43 deletions(-) delete mode 100644 web/templates/welcome.html diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx index 6887489a77..57e9a37883 100644 --- a/web/react/components/login.jsx +++ b/web/react/components/login.jsx @@ -115,7 +115,7 @@ export default class Login extends React.Component { } let teamSignUp = null; - if (global.window.mm_config.EnableTeamCreation === 'true') { + if (global.window.mm_config.EnableTeamCreation === 'true' && !Utils.isMobileApp()) { teamSignUp = (
-
-
+
+ +
- - -{{end}} From c2bc9454ce5550a180d8ee9fec75db7f3841b1ad Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Tue, 26 Jan 2016 20:32:24 -0500 Subject: [PATCH 2/5] PLT-1586 adding attach device id method --- api/user.go | 45 ++++++++++++++++++++++++++++++++- api/user_test.go | 28 ++++++++++++++++++++ i18n/en.json | 4 +++ model/client.go | 11 ++++++++ model/version.go | 2 +- store/sql_session_store.go | 18 +++++++++++++ store/sql_session_store_test.go | 22 ++++++++++++++++ store/store.go | 1 + web/react/components/login.jsx | 25 +++++++++++------- 9 files changed, 145 insertions(+), 11 deletions(-) diff --git a/api/user.go b/api/user.go index 473f0da547..ceaf1fc2db 100644 --- a/api/user.go +++ b/api/user.go @@ -48,6 +48,7 @@ func InitUser(r *mux.Router) { sr.Handle("/logout", ApiUserRequired(logout)).Methods("POST") sr.Handle("/login_ldap", ApiAppHandler(loginLdap)).Methods("POST") sr.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST") + sr.Handle("/attach_device", ApiUserRequired(attachDeviceId)).Methods("POST") sr.Handle("/switch_to_sso", ApiAppHandler(switchToSSO)).Methods("POST") sr.Handle("/switch_to_email", ApiUserRequired(switchToEmail)).Methods("POST") @@ -546,7 +547,6 @@ func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, } } } - } else { session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthWebInDays) } @@ -718,6 +718,49 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.MapToJson(props))) } +func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) { + props := model.MapFromJson(r.Body) + + deviceId := props["device_id"] + if len(deviceId) == 0 { + c.SetInvalidParam("attachDevice", "deviceId") + return + } + + if !(strings.HasPrefix(deviceId, model.PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(deviceId, model.PUSH_NOTIFY_ANDROID+":")) { + c.SetInvalidParam("attachDevice", "deviceId") + return + } + + // A special case where we logout of all other sessions with the same Id + if result := <-Srv.Store.Session().GetSessions(c.Session.UserId); result.Err != nil { + c.Err = result.Err + c.Err.StatusCode = http.StatusForbidden + return + } else { + sessions := result.Data.([]*model.Session) + for _, session := range sessions { + if session.DeviceId == deviceId && session.Id != c.Session.Id { + l4g.Debug(utils.T("api.user.login.revoking.app_error"), session.Id, c.Session.UserId) + RevokeSessionById(c, session.Id) + if c.Err != nil { + c.LogError(c.Err) + c.Err = nil + } + } + } + } + + sessionCache.Remove(c.Session.Token) + + if result := <-Srv.Store.Session().UpdateDeviceId(c.Session.Id, deviceId); result.Err != nil { + c.Err = result.Err + return + } + + w.Write([]byte(deviceId)) +} + func RevokeSessionById(c *Context, sessionId string) { if result := <-Srv.Store.Session().Get(sessionId); result.Err != nil { c.Err = result.Err diff --git a/api/user_test.go b/api/user_test.go index 9a172805a4..5f85bda0f3 100644 --- a/api/user_test.go +++ b/api/user_test.go @@ -734,6 +734,34 @@ func TestUserUpdateRoles(t *testing.T) { } } +func TestUserUpdateDeviceId(t *testing.T) { + Setup() + + team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} + team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team) + + user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"} + user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user.Id)) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + deviceId := model.PUSH_NOTIFY_APPLE + ":1234567890" + + if _, err := Client.AttachDeviceId(deviceId); err != nil { + t.Fatal(err) + } + + if result := <-Srv.Store.Session().GetSessions(user.Id); result.Err != nil { + t.Fatal(result.Err) + } else { + sessions := result.Data.([]*model.Session) + + if sessions[0].DeviceId != deviceId { + t.Fatal("Missing device Id") + } + } +} + func TestUserUpdateActive(t *testing.T) { Setup() diff --git a/i18n/en.json b/i18n/en.json index 72863acd95..14a2e3148d 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2771,6 +2771,10 @@ "id": "store.sql_session.update_roles.app_error", "translation": "We couldn't update the roles" }, + { + "id": "store.sql_session.update_device_id.app_error", + "translation": "We couldn't update the device id" + }, { "id": "store.sql_system.get.app_error", "translation": "We encountered an error finding the system properties" diff --git a/model/client.go b/model/client.go index 8021c70394..d31ac15920 100644 --- a/model/client.go +++ b/model/client.go @@ -775,6 +775,17 @@ func (c *Client) UpdateUserRoles(data map[string]string) (*Result, *AppError) { } } +func (c *Client) AttachDeviceId(deviceId string) (*Result, *AppError) { + data := make(map[string]string) + data["device_id"] = deviceId + if r, err := c.DoApiPost("/users/attach_device", MapToJson(data)); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil + } +} + func (c *Client) UpdateActive(userId string, active bool) (*Result, *AppError) { data := make(map[string]string) data["user_id"] = userId diff --git a/model/version.go b/model/version.go index 88334ceea9..f503ddb846 100644 --- a/model/version.go +++ b/model/version.go @@ -28,7 +28,7 @@ var CurrentVersion string = versions[0] var BuildNumber = "_BUILD_NUMBER_" var BuildDate = "_BUILD_DATE_" var BuildHash = "_BUILD_HASH_" -var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_" +var BuildEnterpriseReady = "false" func SplitVersion(version string) (int64, int64, int64) { parts := strings.Split(version, ".") diff --git a/store/sql_session_store.go b/store/sql_session_store.go index 4762a1dfdb..6532947f45 100644 --- a/store/sql_session_store.go +++ b/store/sql_session_store.go @@ -232,3 +232,21 @@ func (me SqlSessionStore) UpdateRoles(userId, roles string) StoreChannel { return storeChannel } + +func (me SqlSessionStore) UpdateDeviceId(id, deviceId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + if _, err := me.GetMaster().Exec("UPDATE Sessions SET DeviceId = :DeviceId WHERE Id = :Id", map[string]interface{}{"DeviceId": deviceId, "Id": id}); err != nil { + result.Err = model.NewLocAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, "") + } else { + result.Data = deviceId + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} diff --git a/store/sql_session_store_test.go b/store/sql_session_store_test.go index cec8e93b03..34d3128a62 100644 --- a/store/sql_session_store_test.go +++ b/store/sql_session_store_test.go @@ -157,6 +157,28 @@ func TestSessionRemoveToken(t *testing.T) { } } +func TestSessionUpdateDeviceId(t *testing.T) { + Setup() + + s1 := model.Session{} + s1.UserId = model.NewId() + s1.TeamId = model.NewId() + Must(store.Session().Save(&s1)) + + if rs1 := (<-store.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs1.Err != nil { + t.Fatal(rs1.Err) + } + + s2 := model.Session{} + s2.UserId = model.NewId() + s2.TeamId = model.NewId() + Must(store.Session().Save(&s2)) + + if rs2 := (<-store.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs2.Err != nil { + t.Fatal(rs2.Err) + } +} + func TestSessionStoreUpdateLastActivityAt(t *testing.T) { Setup() diff --git a/store/store.go b/store/store.go index b91b08f272..e8c5537acc 100644 --- a/store/store.go +++ b/store/store.go @@ -137,6 +137,7 @@ type SessionStore interface { PermanentDeleteSessionsByUser(teamId string) StoreChannel UpdateLastActivityAt(sessionId string, time int64) StoreChannel UpdateRoles(userId string, roles string) StoreChannel + UpdateDeviceId(sessionIdOrToken string, deviceId string) StoreChannel } type AuditStore interface { diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx index 57e9a37883..3c1d663344 100644 --- a/web/react/components/login.jsx +++ b/web/react/components/login.jsx @@ -137,6 +137,21 @@ export default class Login extends React.Component { ); } + let findTeams = null; + if (!Utils.isMobileApp()) { + findTeams = ( +
+ + + + +
+ ); + } + return (
{'Sign in to:'}
@@ -147,15 +162,7 @@ export default class Login extends React.Component { {emailSignup} {ldapLogin} {userSignUp} -
- - - - -
+ {findTeams} {forgotPassword} {teamSignUp}
From 038e50b5b5a2d813a3ac82850ce866c1a13089e4 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Tue, 26 Jan 2016 21:04:29 -0500 Subject: [PATCH 3/5] PLT-1586 Changing session reporting --- web/react/components/activity_log_modal.jsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx index 6a880f0eee..91ca876474 100644 --- a/web/react/components/activity_log_modal.jsx +++ b/web/react/components/activity_log_modal.jsx @@ -100,12 +100,15 @@ export default class ActivityLogModal extends React.Component { if (currentSession.props.platform === 'Windows') { devicePicture = 'fa fa-windows'; + } else if (currentSession.device_id.indexOf('apple:') === 0) { + devicePicture = 'fa fa-apple'; + devicePlatform = 'iPhone Native App'; + } else if (currentSession.device_id.indexOf('Android:') === 0) { + devicePlatform = 'Android Native App'; + devicePicture = 'fa fa-android'; } else if (currentSession.props.platform === 'Macintosh' || currentSession.props.platform === 'iPhone') { devicePicture = 'fa fa-apple'; - } else if (currentSession.props.platform.browser.indexOf('Mattermost/') === 0) { - devicePicture = 'fa fa-apple'; - devicePlatform = 'iPhone'; } else if (currentSession.props.platform === 'Linux') { if (currentSession.props.os.indexOf('Android') >= 0) { devicePlatform = 'Android'; From 0dec26bb9f3e05a84873996c9ecb3bd87b7dc925 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Tue, 26 Jan 2016 21:11:39 -0500 Subject: [PATCH 4/5] Fixing version --- model/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/version.go b/model/version.go index f503ddb846..88334ceea9 100644 --- a/model/version.go +++ b/model/version.go @@ -28,7 +28,7 @@ var CurrentVersion string = versions[0] var BuildNumber = "_BUILD_NUMBER_" var BuildDate = "_BUILD_DATE_" var BuildHash = "_BUILD_HASH_" -var BuildEnterpriseReady = "false" +var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_" func SplitVersion(version string) (int64, int64, int64) { parts := strings.Split(version, ".") From 6fd0f651b94e594dddb00800bf295af7ff42934e Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Tue, 26 Jan 2016 21:13:44 -0500 Subject: [PATCH 5/5] Fixing naming --- store/store.go | 2 +- web/react/components/activity_log_modal.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/store/store.go b/store/store.go index e8c5537acc..3988f0c6af 100644 --- a/store/store.go +++ b/store/store.go @@ -137,7 +137,7 @@ type SessionStore interface { PermanentDeleteSessionsByUser(teamId string) StoreChannel UpdateLastActivityAt(sessionId string, time int64) StoreChannel UpdateRoles(userId string, roles string) StoreChannel - UpdateDeviceId(sessionIdOrToken string, deviceId string) StoreChannel + UpdateDeviceId(id string, deviceId string) StoreChannel } type AuditStore interface { diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx index 91ca876474..eec4d8f8df 100644 --- a/web/react/components/activity_log_modal.jsx +++ b/web/react/components/activity_log_modal.jsx @@ -103,7 +103,7 @@ export default class ActivityLogModal extends React.Component { } else if (currentSession.device_id.indexOf('apple:') === 0) { devicePicture = 'fa fa-apple'; devicePlatform = 'iPhone Native App'; - } else if (currentSession.device_id.indexOf('Android:') === 0) { + } else if (currentSession.device_id.indexOf('android:') === 0) { devicePlatform = 'Android Native App'; devicePicture = 'fa fa-android'; } else if (currentSession.props.platform === 'Macintosh' ||