PLT-1586 adding attach device id method

This commit is contained in:
=Corey Hulen
2016-01-26 20:32:24 -05:00
parent 21d51f8c90
commit c2bc9454ce
9 changed files with 145 additions and 11 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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"

View File

@@ -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

View File

@@ -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, ".")

View File

@@ -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
}

View File

@@ -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()

View File

@@ -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 {

View File

@@ -137,6 +137,21 @@ export default class Login extends React.Component {
);
}
let findTeams = null;
if (!Utils.isMobileApp()) {
findTeams = (
<div className='form-group margin--extra form-group--small'>
<span>
<a href='/find_team'>
<FormattedMessage
id='login.find_teams'
defaultMessage='Find your other teams'
/>
</a></span>
</div>
);
}
return (
<div className='signup-team__container'>
<h5 className='margin--less'>{'Sign in to:'}</h5>
@@ -147,15 +162,7 @@ export default class Login extends React.Component {
{emailSignup}
{ldapLogin}
{userSignUp}
<div className='form-group margin--extra form-group--small'>
<span>
<a href='/find_team'>
<FormattedMessage
id='login.find_teams'
defaultMessage='Find your other teams'
/>
</a></span>
</div>
{findTeams}
{forgotPassword}
{teamSignUp}
</div>