unbind device push token on logout

This commit is contained in:
richjohnrambo
2026-09-23 11:39:16 +08:00
parent c4355ac236
commit a0d0bf574e
5 changed files with 229 additions and 9 deletions
+66 -3
View File
@@ -447,6 +447,10 @@ type imDevicePushTokenRequest struct {
NotificationPermission string `json:"notification_permission,omitempty"`
}
type imAuthLogoutRequest struct {
DeviceID string `json:"device_id,omitempty"`
}
type imP2PConversationRequest struct {
PeerUserID string `json:"peer_user_id"`
}
@@ -4369,8 +4373,7 @@ func serveIMGroupDetail(wrt http.ResponseWriter, req *http.Request, topic string
return
}
if req.Method == http.MethodGet {
if settings, err := store.GroupBusiness.GetSettings(principal.TenantID, topic); err == nil && settings != nil && settings.GroupStatus == types.GroupStatusDissolved {
writeIMError(wrt, req, http.StatusGone, 30004, imReasonGroupDissolved, "group dissolved", map[string]any{"topic": topic})
if writeIMGroupDissolvedIfGone(wrt, req, principal.TenantID, topic) {
return
}
}
@@ -4529,6 +4532,19 @@ func serveIMGroupDetail(wrt http.ResponseWriter, req *http.Request, topic string
}
}
func writeIMGroupDissolvedIfGone(wrt http.ResponseWriter, req *http.Request, tenantID types.TenantID, topic string) bool {
if settings, err := store.GroupBusiness.GetSettings(tenantID, topic); err == nil && settings != nil && settings.GroupStatus == types.GroupStatusDissolved {
writeIMError(wrt, req, http.StatusGone, 30004, imReasonGroupDissolved, "group dissolved", map[string]any{"topic": topic})
return true
}
group, err := store.Topics.Get(tenantID, topic)
if err != nil || group == nil || group.State != types.StateDeleted {
return false
}
writeIMError(wrt, req, http.StatusGone, 30004, imReasonGroupDissolved, "group dissolved", map[string]any{"topic": topic})
return true
}
func serveIMGroupSettings(wrt http.ResponseWriter, req *http.Request, topic string) {
if req.Method != http.MethodGet {
writeIMError(wrt, req, http.StatusMethodNotAllowed, 30002, imReasonMethodNotAllowed, "method not allowed", nil)
@@ -6583,6 +6599,10 @@ func serveIMAuthLogout(wrt http.ResponseWriter, req *http.Request) {
writeIMError(wrt, req, http.StatusMethodNotAllowed, 30000, imReasonMethodNotAllowed, "method not allowed", nil)
return
}
deviceID, ok := imLogoutDeviceID(wrt, req)
if !ok {
return
}
principal, token, ttl, err := resolveIMHTTPBearerToken(req)
if err != nil {
writeIMError(wrt, req, http.StatusUnauthorized, 30043, imReasonAuthRequired, "authentication required", nil)
@@ -6597,7 +6617,50 @@ func serveIMAuthLogout(wrt http.ResponseWriter, req *http.Request) {
writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil)
return
}
writeIMSuccess(wrt, req, map[string]any{"status": "ok"})
pushUnbound := false
if deviceID != "" {
if deleter, ok := store.DevicePushTokens.(interface {
Delete(types.TenantID, types.Uid, string) error
}); ok {
if err = deleter.Delete(principal.TenantID, principal.Uid, deviceID); err != nil && !errors.Is(err, types.ErrNotFound) {
logs.Warn.Println("im logout: push token unbind failed", principal.TenantID, principal.Uid, deviceID, err)
writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil)
return
}
pushUnbound = err == nil
}
if store.Devices != nil {
if err = store.Devices.Delete(principal.TenantID, principal.Uid, deviceID); err != nil && !errors.Is(err, types.ErrNotFound) {
logs.Warn.Println("im logout: legacy device unbind failed", principal.TenantID, principal.Uid, deviceID, err)
writeIMError(wrt, req, http.StatusInternalServerError, 90000, imReasonInternal, "internal error", nil)
return
}
}
}
writeIMSuccess(wrt, req, map[string]any{"status": "ok", "device_id": deviceID, "push_unbound": pushUnbound})
}
func imLogoutDeviceID(wrt http.ResponseWriter, req *http.Request) (string, bool) {
deviceID := strings.TrimSpace(req.Header.Get("X-Device-ID"))
if deviceID == "" {
deviceID = strings.TrimSpace(req.Header.Get("X-IM-Device-ID"))
}
if req.Body != nil && req.Body != http.NoBody {
var body imAuthLogoutRequest
dec := json.NewDecoder(req.Body)
if err := dec.Decode(&body); err != nil && !errors.Is(err, io.EOF) {
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "body"})
return "", false
}
if strings.TrimSpace(body.DeviceID) != "" {
deviceID = strings.TrimSpace(body.DeviceID)
}
}
if strings.Contains(deviceID, "/") {
writeIMError(wrt, req, http.StatusBadRequest, 30000, imReasonMalformedRequest, "malformed request", map[string]any{"field": "device_id"})
return "", false
}
return deviceID, true
}
func currentUserPhone(tenantID types.TenantID, uid types.Uid) (string, error) {