summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api4/user.go49
-rw-r--r--api4/user_test.go29
-rw-r--r--model/client4.go11
3 files changed, 89 insertions, 0 deletions
diff --git a/api4/user.go b/api4/user.go
index c04fa0d77..3d10473a2 100644
--- a/api4/user.go
+++ b/api4/user.go
@@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"strconv"
+ "time"
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/platform/app"
@@ -46,6 +47,7 @@ func InitUser() {
BaseRoutes.User.Handle("/sessions", ApiSessionRequired(getSessions)).Methods("GET")
BaseRoutes.User.Handle("/sessions/revoke", ApiSessionRequired(revokeSession)).Methods("POST")
+ BaseRoutes.Users.Handle("/sessions/device", ApiSessionRequired(attachDeviceId)).Methods("PUT")
BaseRoutes.User.Handle("/audits", ApiSessionRequired(getUserAudits)).Methods("GET")
}
@@ -778,6 +780,53 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) {
ReturnStatusOK(w)
}
+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("device_id")
+ return
+ }
+
+ // A special case where we logout of all other sessions with the same device id
+ if err := app.RevokeSessionsForDeviceId(c.Session.UserId, deviceId, c.Session.Id); err != nil {
+ c.Err = err
+ return
+ }
+
+ app.ClearSessionCacheForUser(c.Session.UserId)
+ c.Session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthMobileInDays)
+
+ maxAge := *utils.Cfg.ServiceSettings.SessionLengthMobileInDays * 60 * 60 * 24
+
+ secure := false
+ if app.GetProtocol(r) == "https" {
+ secure = true
+ }
+
+ expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAge), 0)
+ sessionCookie := &http.Cookie{
+ Name: model.SESSION_COOKIE_TOKEN,
+ Value: c.Session.Token,
+ Path: "/",
+ MaxAge: maxAge,
+ Expires: expiresAt,
+ HttpOnly: true,
+ Secure: secure,
+ }
+
+ http.SetCookie(w, sessionCookie)
+
+ if err := app.AttachDeviceId(c.Session.Id, deviceId, c.Session.ExpiresAt); err != nil {
+ c.Err = err
+ return
+ }
+
+ c.LogAudit("")
+ ReturnStatusOK(w)
+}
+
func getUserAudits(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId()
if c.Err != nil {
diff --git a/api4/user_test.go b/api4/user_test.go
index 16ae8bdad..3bdc73045 100644
--- a/api4/user_test.go
+++ b/api4/user_test.go
@@ -1275,7 +1275,36 @@ func TestRevokeSessions(t *testing.T) {
_, resp = th.SystemAdminClient.RevokeSession(th.SystemAdminUser.Id, session.Id)
CheckNoError(t, resp)
+}
+
+func TestAttachDeviceId(t *testing.T) {
+ th := Setup().InitBasic()
+ defer TearDown()
+ Client := th.Client
+
+ deviceId := model.PUSH_NOTIFY_APPLE + ":1234567890"
+ pass, resp := Client.AttachDeviceId(deviceId)
+ CheckNoError(t, resp)
+
+ if !pass {
+ t.Fatal("should have passed")
+ }
+ if sessions, err := app.GetSessions(th.BasicUser.Id); err != nil {
+ t.Fatal(err)
+ } else {
+ if sessions[0].DeviceId != deviceId {
+ t.Fatal("Missing device Id")
+ }
+ }
+
+ _, resp = Client.AttachDeviceId("")
+ CheckBadRequestStatus(t, resp)
+
+ Client.Logout()
+
+ _, resp = Client.AttachDeviceId("")
+ CheckUnauthorizedStatus(t, resp)
}
func TestGetUserAudits(t *testing.T) {
diff --git a/model/client4.go b/model/client4.go
index 031973a34..e1bd70878 100644
--- a/model/client4.go
+++ b/model/client4.go
@@ -617,6 +617,17 @@ func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) {
}
}
+// AttachDeviceId attaches a mobile device ID to the current session.
+func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) {
+ requestBody := map[string]string{"device_id": deviceId}
+ if r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+ }
+}
+
// GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount
// of unread messages and mentions the current user has for the teams it belongs to.
// An optional team ID can be set to exclude that team from the results. Must be authenticated.