Bind history to the recipient session and channel, not the name (closes #148)
check / check (push) Waiting to run
check / check (push) Waiting to run
History was selected by msg_to, so whoever next held a released nick, or created a deleted channel again under its old name, could read the earlier holder's messages. Each message row now records the session a DM or INVITE was sent to (to_session_id) and the channel a channel message was sent to (to_channel_id), and GET /api/v1/history selects by the one that applies, using its index. A session's DM history now also follows it across nick changes. A DM or channel message whose recipient is deleted before it is stored gets the unknown nick or channel error. Model: opus-5-5
This commit was merged in pull request #161.
This commit is contained in:
+36
-24
@@ -566,7 +566,7 @@ func (hdlr *Handlers) enqueueNumeric(
|
||||
}
|
||||
|
||||
dbID, _, insertErr := hdlr.params.Database.InsertMessage(
|
||||
ctx, command, hdlr.serverName(), nick,
|
||||
ctx, command, hdlr.serverName(), nick, 0, 0,
|
||||
paramsJSON, json.RawMessage(body), nil,
|
||||
)
|
||||
if insertErr != nil {
|
||||
@@ -652,7 +652,7 @@ func (hdlr *Handlers) initChannelState(
|
||||
dbID, _, insErr := hdlr.params.Database.
|
||||
InsertMessage(
|
||||
ctx, "JOIN", nick, chanInfo.Name,
|
||||
nil, nil, nil,
|
||||
0, chanInfo.ID, nil, nil, nil,
|
||||
)
|
||||
if insErr != nil {
|
||||
hdlr.log.Error(
|
||||
@@ -2404,7 +2404,7 @@ func (hdlr *Handlers) executeBanChange(
|
||||
)
|
||||
if mErr == nil {
|
||||
_ = hdlr.fanOutSilent(
|
||||
request, irc.CmdMode, nick, channel,
|
||||
request, irc.CmdMode, nick, channel, 0, chID,
|
||||
json.RawMessage(modeBody), memberIDs,
|
||||
)
|
||||
}
|
||||
@@ -2522,7 +2522,7 @@ func (hdlr *Handlers) setChannelKeyMode(
|
||||
modeBody, mErr := json.Marshal([]string{"+k", key})
|
||||
if mErr == nil {
|
||||
_ = hdlr.fanOutSilent(
|
||||
request, irc.CmdMode, nick, channel,
|
||||
request, irc.CmdMode, nick, channel, 0, chID,
|
||||
json.RawMessage(modeBody), memberIDs,
|
||||
)
|
||||
}
|
||||
@@ -2571,7 +2571,7 @@ func (hdlr *Handlers) clearChannelKeyMode(
|
||||
modeBody, mErr := json.Marshal([]string{"-k", "*"})
|
||||
if mErr == nil {
|
||||
_ = hdlr.fanOutSilent(
|
||||
request, irc.CmdMode, nick, channel,
|
||||
request, irc.CmdMode, nick, channel, 0, chID,
|
||||
json.RawMessage(modeBody), memberIDs,
|
||||
)
|
||||
}
|
||||
@@ -2646,7 +2646,7 @@ func (hdlr *Handlers) setChannelLimitMode(
|
||||
)
|
||||
if mErr == nil {
|
||||
_ = hdlr.fanOutSilent(
|
||||
request, irc.CmdMode, nick, channel,
|
||||
request, irc.CmdMode, nick, channel, 0, chID,
|
||||
json.RawMessage(modeBody), memberIDs,
|
||||
)
|
||||
}
|
||||
@@ -2696,7 +2696,7 @@ func (hdlr *Handlers) clearChannelLimitMode(
|
||||
modeBody, mErr := json.Marshal([]string{"-l"})
|
||||
if mErr == nil {
|
||||
_ = hdlr.fanOutSilent(
|
||||
request, irc.CmdMode, nick, channel,
|
||||
request, irc.CmdMode, nick, channel, 0, chID,
|
||||
json.RawMessage(modeBody), memberIDs,
|
||||
)
|
||||
}
|
||||
@@ -2755,7 +2755,7 @@ func (hdlr *Handlers) handleInvite(
|
||||
if mErr == nil {
|
||||
_ = hdlr.fanOutSilent(
|
||||
request, irc.CmdInvite, nick, targetNick,
|
||||
json.RawMessage(invBody),
|
||||
targetSID, 0, json.RawMessage(invBody),
|
||||
[]int64{targetSID},
|
||||
)
|
||||
}
|
||||
@@ -3250,9 +3250,10 @@ func (hdlr *Handlers) HandleGetHistory() http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if !hdlr.canAccessHistory(
|
||||
toSessionID, toChannelID, ok := hdlr.canAccessHistory(
|
||||
writer, request, sessionID, nick, target,
|
||||
) {
|
||||
)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3264,7 +3265,7 @@ func (hdlr *Handlers) HandleGetHistory() http.HandlerFunc {
|
||||
}
|
||||
|
||||
msgs, err := hdlr.params.Database.GetHistory(
|
||||
request.Context(), target,
|
||||
request.Context(), toSessionID, toChannelID,
|
||||
request.URL.Query().Get("before"), limit,
|
||||
)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
@@ -3297,17 +3298,23 @@ func (hdlr *Handlers) HandleGetHistory() http.HandlerFunc {
|
||||
}
|
||||
|
||||
// canAccessHistory verifies the user can read history
|
||||
// for the given target (channel or DM participant).
|
||||
// for the given target (channel or DM participant) and
|
||||
// returns the session id and channel id to pass to
|
||||
// GetHistory: the user's own session for its nick, or the
|
||||
// channel's id, with 0 for the other. On false it has
|
||||
// written the error response.
|
||||
func (hdlr *Handlers) canAccessHistory(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID int64,
|
||||
nick, target string,
|
||||
) bool {
|
||||
) (int64, int64, bool) {
|
||||
if strings.HasPrefix(target, "#") {
|
||||
return hdlr.canAccessChannelHistory(
|
||||
chID, ok := hdlr.canAccessChannelHistory(
|
||||
writer, request, sessionID, target,
|
||||
)
|
||||
|
||||
return 0, chID, ok
|
||||
}
|
||||
|
||||
// DM history: only allow if the target is the
|
||||
@@ -3319,18 +3326,20 @@ func (hdlr *Handlers) canAccessHistory(
|
||||
http.StatusForbidden,
|
||||
)
|
||||
|
||||
return false
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
return true
|
||||
return sessionID, 0, true
|
||||
}
|
||||
|
||||
// canAccessChannelHistory returns the id of the channel
|
||||
// named target if the user is a member of it.
|
||||
func (hdlr *Handlers) canAccessChannelHistory(
|
||||
writer http.ResponseWriter,
|
||||
request *http.Request,
|
||||
sessionID int64,
|
||||
target string,
|
||||
) bool {
|
||||
) (int64, bool) {
|
||||
chID, err := hdlr.params.Database.GetChannelByName(
|
||||
request.Context(), target,
|
||||
)
|
||||
@@ -3341,7 +3350,7 @@ func (hdlr *Handlers) canAccessChannelHistory(
|
||||
http.StatusNotFound,
|
||||
)
|
||||
|
||||
return false
|
||||
return 0, false
|
||||
}
|
||||
|
||||
isMember, err := hdlr.params.Database.IsChannelMember(
|
||||
@@ -3357,7 +3366,7 @@ func (hdlr *Handlers) canAccessChannelHistory(
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
|
||||
return false
|
||||
return 0, false
|
||||
}
|
||||
|
||||
if !isMember {
|
||||
@@ -3367,10 +3376,10 @@ func (hdlr *Handlers) canAccessChannelHistory(
|
||||
http.StatusForbidden,
|
||||
)
|
||||
|
||||
return false
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return true
|
||||
return chID, true
|
||||
}
|
||||
|
||||
// HandleLogout deletes the authenticated client's token
|
||||
@@ -3679,17 +3688,19 @@ func (hdlr *Handlers) deliverWhoisIdle(
|
||||
}
|
||||
|
||||
// fanOut inserts a message and enqueues it to all given
|
||||
// sessions.
|
||||
// sessions. toSessionID and toChannelID are the recipient
|
||||
// InsertMessage records for history, 0 when there is none.
|
||||
func (hdlr *Handlers) fanOut(
|
||||
request *http.Request,
|
||||
command, from, target string,
|
||||
toSessionID, toChannelID int64,
|
||||
body json.RawMessage,
|
||||
meta json.RawMessage,
|
||||
sessionIDs []int64,
|
||||
) (string, error) {
|
||||
dbID, msgUUID, err := hdlr.params.Database.InsertMessage(
|
||||
request.Context(), command, from, target,
|
||||
nil, body, meta,
|
||||
toSessionID, toChannelID, nil, body, meta,
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("insert message: %w", err)
|
||||
@@ -3714,12 +3725,13 @@ func (hdlr *Handlers) fanOut(
|
||||
func (hdlr *Handlers) fanOutSilent(
|
||||
request *http.Request,
|
||||
command, from, target string,
|
||||
toSessionID, toChannelID int64,
|
||||
body json.RawMessage,
|
||||
sessionIDs []int64,
|
||||
) error {
|
||||
_, err := hdlr.fanOut(
|
||||
request, command, from, target,
|
||||
body, nil, sessionIDs,
|
||||
toSessionID, toChannelID, body, nil, sessionIDs,
|
||||
)
|
||||
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user