mirror of
https://github.com/Luzifer/twitch-bot.git
synced 2024-12-20 03:41:16 +00:00
[eventsub] Add support for suspicious user events
- User status is updated - User sent a message while having sus-user status Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
acf96c31ad
commit
7737d939f4
6 changed files with 180 additions and 43 deletions
|
@ -273,6 +273,29 @@ Fields:
|
|||
- `plan` - The sub-plan they are using (`1000` = T1, `2000` = T2, `3000` = T3, `Prime`)
|
||||
- `username` - The login-name of the user who gifted the subscription
|
||||
|
||||
## `sus_user_message`
|
||||
|
||||
A suspicious (monitored / restricted) user sent a message in the given channel
|
||||
|
||||
- `ban_evasion` _string_ - Status of the ban-evasion detection: `unknown`, `possible`, `likely`
|
||||
- `channel` _string_ - The channel in which the event occurred
|
||||
- `message` _string_ - The message the user sent in plain text
|
||||
- `shared_ban_channels` _[]string_ - IDs of channels with shared ban-info in which the user is also banned
|
||||
- `status` _string_ - Restriction status: `active_monitoring`, `restricted`
|
||||
- `user_id` _string_ - ID of the user sending the message
|
||||
- `user_type` _[]string_ - How the user ended being on the naughty-list: `manually_added`, `ban_evader_detector`, or `shared_channel_ban`
|
||||
- `username` _string_ - The login-name of the user sending the message
|
||||
|
||||
## `sus_user_update`
|
||||
|
||||
The status of suspicious user was changed by a moderator
|
||||
|
||||
- `channel` _string_ - The channel in which the event occurred
|
||||
- `moderator` _string_ - The login-name of the moderator changing the status
|
||||
- `status` _string_ - Restriction status: `no_treatment`, `active_monitoring`, `restricted`
|
||||
- `user_id` _string_ - ID of the suspicious user
|
||||
- `username` _string_ - Login-name of the suspicious user
|
||||
|
||||
## `timeout`
|
||||
|
||||
Moderator action caused a user to be timed out from chat.
|
||||
|
|
|
@ -45,6 +45,8 @@ var (
|
|||
eventTypeSubgift = ptrStr("subgift")
|
||||
eventTypeSubmysterygift = ptrStr("submysterygift")
|
||||
eventTypeSub = ptrStr("sub")
|
||||
eventTypeSusUserMessage = ptrStr("sus_user_message")
|
||||
eventTypeSusUserUpdate = ptrStr("sus_user_update")
|
||||
eventTypeTimeout = ptrStr("timeout")
|
||||
eventTypeWatchStreak = ptrStr("watch_streak")
|
||||
eventTypeWhisper = ptrStr("whisper")
|
||||
|
@ -83,6 +85,8 @@ var (
|
|||
eventTypeSub,
|
||||
eventTypeSubgift,
|
||||
eventTypeSubmysterygift,
|
||||
eventTypeSusUserMessage,
|
||||
eventTypeSusUserUpdate,
|
||||
eventTypeTimeout,
|
||||
eventTypeWatchStreak,
|
||||
eventTypeWhisper,
|
||||
|
|
|
@ -29,6 +29,8 @@ const (
|
|||
EventSubEventTypeChannelPollBegin = "channel.poll.begin"
|
||||
EventSubEventTypeChannelPollEnd = "channel.poll.end"
|
||||
EventSubEventTypeChannelPollProgress = "channel.poll.progress"
|
||||
EventSubEventTypeChannelSuspiciousUserMessage = "channel.suspicious_user.message"
|
||||
EventSubEventTypeChannelSuspiciousUserUpdate = "channel.suspicious_user.update"
|
||||
EventSubEventTypeStreamOffline = "stream.offline"
|
||||
EventSubEventTypeStreamOnline = "stream.online"
|
||||
EventSubEventTypeUserAuthorizationRevoke = "user.authorization.revoke"
|
||||
|
@ -235,6 +237,53 @@ type (
|
|||
StartedAt time.Time `json:"started_at"`
|
||||
}
|
||||
|
||||
// EventSubEventSuspiciousUserMessage contains the payload for a
|
||||
// channel.suspicious_user.message
|
||||
EventSubEventSuspiciousUserMessage struct {
|
||||
BroadcasterUserID string `json:"broadcaster_user_id"`
|
||||
BroadcasterUserName string `json:"broadcaster_user_name"`
|
||||
BroadcasterUserLogin string `json:"broadcaster_user_login"`
|
||||
UserID string `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
UserLogin string `json:"user_login"`
|
||||
LowTrustStatus string `json:"low_trust_status"` // Can be the following: "none", "active_monitoring", or "restricted"
|
||||
SharedBanChannelIDs []string `json:"shared_ban_channel_ids"`
|
||||
Types []string `json:"types"` // can be "manual", "ban_evader_detector", or "shared_channel_ban"
|
||||
BanEvasionEvaluation string `json:"ban_evasion_evaluation"` // can be "unknown", "possible", or "likely"
|
||||
Message struct {
|
||||
MessageID string `json:"message_id"`
|
||||
Text string `json:"text"`
|
||||
Fragments []struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text"`
|
||||
Cheermote struct {
|
||||
Prefix string `json:"prefix"`
|
||||
Bits int `json:"bits"`
|
||||
Tier int `json:"tier"`
|
||||
} `json:"Cheermote"`
|
||||
Emote struct {
|
||||
ID string `json:"id"`
|
||||
EmoteSetID string `json:"emote_set_id"`
|
||||
} `json:"emote"`
|
||||
} `json:"fragments"`
|
||||
} `json:"message"`
|
||||
}
|
||||
|
||||
// EventSubEventSuspiciousUserUpdated contains the payload for a
|
||||
// channel.suspicious_user.update
|
||||
EventSubEventSuspiciousUserUpdated struct {
|
||||
BroadcasterUserID string `json:"broadcaster_user_id"`
|
||||
BroadcasterUserName string `json:"broadcaster_user_name"`
|
||||
BroadcasterUserLogin string `json:"broadcaster_user_login"`
|
||||
ModeratorUserID string `json:"moderator_user_id"`
|
||||
ModeratorUserName string `json:"moderator_user_name"`
|
||||
ModeratorUserLogin string `json:"moderator_user_login"`
|
||||
UserID string `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
UserLogin string `json:"user_login"`
|
||||
LowTrustStatus string `json:"low_trust_status"` // Can be the following: "none", "active_monitoring", or "restricted"
|
||||
}
|
||||
|
||||
// EventSubEventUserAuthorizationRevoke contains the payload for an
|
||||
// authorization revoke event
|
||||
EventSubEventUserAuthorizationRevoke struct {
|
||||
|
|
|
@ -3,35 +3,36 @@ package twitch
|
|||
// Collection of known API scopes
|
||||
const (
|
||||
// API Scopes
|
||||
ScopeChannelBot = "channel:bot"
|
||||
ScopeChannelEditCommercial = "channel:edit:commercial"
|
||||
ScopeChannelManageAds = "channel:manage:ads"
|
||||
ScopeChannelManageBroadcast = "channel:manage:broadcast"
|
||||
ScopeChannelManageModerators = "channel:manage:moderators"
|
||||
ScopeChannelManagePolls = "channel:manage:polls"
|
||||
ScopeChannelManagePredictions = "channel:manage:predictions"
|
||||
ScopeChannelManageRaids = "channel:manage:raids"
|
||||
ScopeChannelManageRedemptions = "channel:manage:redemptions"
|
||||
ScopeChannelManageVIPS = "channel:manage:vips"
|
||||
ScopeChannelManageWhispers = "user:manage:whispers"
|
||||
ScopeChannelReadAds = "channel:read:ads"
|
||||
ScopeChannelReadHypetrain = "channel:read:hype_train"
|
||||
ScopeChannelReadPolls = "channel:read:polls"
|
||||
ScopeChannelReadRedemptions = "channel:read:redemptions"
|
||||
ScopeChannelReadSubscriptions = "channel:read:subscriptions"
|
||||
ScopeClipsEdit = "clips:edit"
|
||||
ScopeModeratorManageAnnoucements = "moderator:manage:announcements"
|
||||
ScopeModeratorManageBannedUsers = "moderator:manage:banned_users"
|
||||
ScopeModeratorManageChatMessages = "moderator:manage:chat_messages"
|
||||
ScopeModeratorManageChatSettings = "moderator:manage:chat_settings"
|
||||
ScopeModeratorManageShieldMode = "moderator:manage:shield_mode"
|
||||
ScopeModeratorManageShoutouts = "moderator:manage:shoutouts"
|
||||
ScopeModeratorReadFollowers = "moderator:read:followers"
|
||||
ScopeModeratorReadShoutouts = "moderator:read:shoutouts"
|
||||
ScopeUserBot = "user:bot"
|
||||
ScopeUserManageChatColor = "user:manage:chat_color"
|
||||
ScopeUserManageWhispers = "user:manage:whispers"
|
||||
ScopeUserReadChat = "user:read:chat"
|
||||
ScopeChannelBot = "channel:bot"
|
||||
ScopeChannelEditCommercial = "channel:edit:commercial"
|
||||
ScopeChannelManageAds = "channel:manage:ads"
|
||||
ScopeChannelManageBroadcast = "channel:manage:broadcast"
|
||||
ScopeChannelManageModerators = "channel:manage:moderators"
|
||||
ScopeChannelManagePolls = "channel:manage:polls"
|
||||
ScopeChannelManagePredictions = "channel:manage:predictions"
|
||||
ScopeChannelManageRaids = "channel:manage:raids"
|
||||
ScopeChannelManageRedemptions = "channel:manage:redemptions"
|
||||
ScopeChannelManageVIPS = "channel:manage:vips"
|
||||
ScopeChannelManageWhispers = "user:manage:whispers"
|
||||
ScopeChannelReadAds = "channel:read:ads"
|
||||
ScopeChannelReadHypetrain = "channel:read:hype_train"
|
||||
ScopeChannelReadPolls = "channel:read:polls"
|
||||
ScopeChannelReadRedemptions = "channel:read:redemptions"
|
||||
ScopeChannelReadSubscriptions = "channel:read:subscriptions"
|
||||
ScopeClipsEdit = "clips:edit"
|
||||
ScopeModeratorManageAnnoucements = "moderator:manage:announcements"
|
||||
ScopeModeratorManageBannedUsers = "moderator:manage:banned_users"
|
||||
ScopeModeratorManageChatMessages = "moderator:manage:chat_messages"
|
||||
ScopeModeratorManageChatSettings = "moderator:manage:chat_settings"
|
||||
ScopeModeratorManageShieldMode = "moderator:manage:shield_mode"
|
||||
ScopeModeratorManageShoutouts = "moderator:manage:shoutouts"
|
||||
ScopeModeratorReadFollowers = "moderator:read:followers"
|
||||
ScopeModeratorReadShoutouts = "moderator:read:shoutouts"
|
||||
ScopeModeratorReadSuspiciousUsers = "moderator:read:suspicious_users"
|
||||
ScopeUserBot = "user:bot"
|
||||
ScopeUserManageChatColor = "user:manage:chat_color"
|
||||
ScopeUserManageWhispers = "user:manage:whispers"
|
||||
ScopeUserReadChat = "user:read:chat"
|
||||
|
||||
// Deprecated v5 scope but used in chat
|
||||
ScopeV5ChannelEditor = "channel_editor"
|
||||
|
|
29
scopes.go
29
scopes.go
|
@ -4,20 +4,21 @@ import "github.com/Luzifer/twitch-bot/v3/pkg/twitch"
|
|||
|
||||
var (
|
||||
channelExtendedScopes = map[string]string{
|
||||
twitch.ScopeChannelEditCommercial: "run commercial",
|
||||
twitch.ScopeChannelManageBroadcast: "modify category / title",
|
||||
twitch.ScopeChannelManagePolls: "manage polls",
|
||||
twitch.ScopeChannelManagePredictions: "manage predictions",
|
||||
twitch.ScopeChannelManageRaids: "start raids",
|
||||
twitch.ScopeChannelManageVIPS: "manage VIPs",
|
||||
twitch.ScopeChannelReadAds: "see when an ad-break starts",
|
||||
twitch.ScopeChannelReadHypetrain: "see Hype-Train events",
|
||||
twitch.ScopeChannelReadRedemptions: "see channel-point redemptions",
|
||||
twitch.ScopeChannelReadSubscriptions: "see subscribed users / sub count / points",
|
||||
twitch.ScopeClipsEdit: "create clips on behalf of this user",
|
||||
twitch.ScopeModeratorReadFollowers: "see who follows this channel",
|
||||
twitch.ScopeModeratorReadShoutouts: "see shoutouts created / received",
|
||||
twitch.ScopeUserManageWhispers: "send whispers on behalf of this user",
|
||||
twitch.ScopeChannelEditCommercial: "run commercial",
|
||||
twitch.ScopeChannelManageBroadcast: "modify category / title",
|
||||
twitch.ScopeChannelManagePolls: "manage polls",
|
||||
twitch.ScopeChannelManagePredictions: "manage predictions",
|
||||
twitch.ScopeChannelManageRaids: "start raids",
|
||||
twitch.ScopeChannelManageVIPS: "manage VIPs",
|
||||
twitch.ScopeChannelReadAds: "see when an ad-break starts",
|
||||
twitch.ScopeChannelReadHypetrain: "see Hype-Train events",
|
||||
twitch.ScopeChannelReadRedemptions: "see channel-point redemptions",
|
||||
twitch.ScopeChannelReadSubscriptions: "see subscribed users / sub count / points",
|
||||
twitch.ScopeClipsEdit: "create clips on behalf of this user",
|
||||
twitch.ScopeModeratorReadFollowers: "see who follows this channel",
|
||||
twitch.ScopeModeratorReadShoutouts: "see shoutouts created / received",
|
||||
twitch.ScopeModeratorReadSuspiciousUsers: "see users marked suspicious / restricted",
|
||||
twitch.ScopeUserManageWhispers: "send whispers on behalf of this user",
|
||||
}
|
||||
|
||||
botDefaultScopes = []string{
|
||||
|
|
|
@ -232,6 +232,22 @@ func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration
|
|||
Hook: t.handleEventSubStreamOnOff(true),
|
||||
Optional: true,
|
||||
},
|
||||
{
|
||||
Topic: twitch.EventSubEventTypeChannelSuspiciousUserMessage,
|
||||
Version: twitch.EventSubTopicVersionBeta,
|
||||
Condition: twitch.EventSubCondition{BroadcasterUserID: userID, ModeratorUserID: userID},
|
||||
RequiredScopes: []string{twitch.ScopeModeratorReadSuspiciousUsers},
|
||||
Hook: t.handleEventSubSusUserMessage,
|
||||
Optional: true,
|
||||
},
|
||||
{
|
||||
Topic: twitch.EventSubEventTypeChannelSuspiciousUserUpdate,
|
||||
Version: twitch.EventSubTopicVersionBeta,
|
||||
Condition: twitch.EventSubCondition{BroadcasterUserID: userID, ModeratorUserID: userID},
|
||||
RequiredScopes: []string{twitch.ScopeModeratorReadSuspiciousUsers},
|
||||
Hook: t.handleEventSubSusUserUpdate,
|
||||
Optional: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,6 +454,49 @@ func (t *twitchWatcher) handleEventSubStreamOnOff(isOnline bool) func(json.RawMe
|
|||
}
|
||||
}
|
||||
|
||||
func (*twitchWatcher) handleEventSubSusUserMessage(m json.RawMessage) (err error) {
|
||||
var payload twitch.EventSubEventSuspiciousUserMessage
|
||||
if err := json.Unmarshal(m, &payload); err != nil {
|
||||
return errors.Wrap(err, "unmarshalling event")
|
||||
}
|
||||
|
||||
fields := fieldcollection.FieldCollectionFromData(map[string]any{
|
||||
"ban_evasion": payload.BanEvasionEvaluation,
|
||||
"channel": "#" + payload.BroadcasterUserLogin,
|
||||
"message": payload.Message.Text,
|
||||
"shared_ban_channels": payload.SharedBanChannelIDs,
|
||||
"status": payload.LowTrustStatus,
|
||||
"user_id": payload.UserID,
|
||||
"user_type": payload.Types,
|
||||
"username": payload.UserLogin,
|
||||
})
|
||||
|
||||
log.WithFields(log.Fields(fields.Data())).Info("restricted user message")
|
||||
go handleMessage(ircHdl.Client(), nil, eventTypeSusUserMessage, fields)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*twitchWatcher) handleEventSubSusUserUpdate(m json.RawMessage) (err error) {
|
||||
var payload twitch.EventSubEventSuspiciousUserUpdated
|
||||
if err := json.Unmarshal(m, &payload); err != nil {
|
||||
return errors.Wrap(err, "unmarshalling event")
|
||||
}
|
||||
|
||||
fields := fieldcollection.FieldCollectionFromData(map[string]any{
|
||||
"channel": "#" + payload.BroadcasterUserLogin,
|
||||
"moderator": payload.ModeratorUserLogin,
|
||||
"status": payload.LowTrustStatus,
|
||||
"user_id": payload.UserID,
|
||||
"username": payload.UserLogin,
|
||||
})
|
||||
|
||||
log.WithFields(log.Fields(fields.Data())).Info("user restriction updated")
|
||||
go handleMessage(ircHdl.Client(), nil, eventTypeSusUserUpdate, fields)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *twitchWatcher) updateChannelFromAPI(channel string) error {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
|
Loading…
Reference in a new issue