feat: domain blocker plugin
This commit is contained in:
parent
c9edb57505
commit
7dd02c0056
25 changed files with 898 additions and 63 deletions
|
@ -7,6 +7,7 @@ ButterRobot organizes plugins into different categories:
|
|||
- **Development**: Utility plugins like `ping`
|
||||
- **Fun**: Entertainment plugins like dice rolling, coin flipping
|
||||
- **Social**: Social media related plugins like URL transformers/expanders
|
||||
- **Security**: Moderation and protection features like domain blocking
|
||||
|
||||
When creating a new plugin, consider which category it fits into and place it in the appropriate directory.
|
||||
|
||||
|
@ -59,6 +60,91 @@ func (p *MarcoPlugin) OnMessage(msg *model.Message, config map[string]interface{
|
|||
}
|
||||
```
|
||||
|
||||
### Configuration-Enabled Plugin
|
||||
|
||||
This plugin requires configuration to be set in the admin interface. It demonstrates how to create plugins that need channel-specific configuration:
|
||||
|
||||
```go
|
||||
package security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"git.nakama.town/fmartingr/butterrobot/internal/model"
|
||||
"git.nakama.town/fmartingr/butterrobot/internal/plugin"
|
||||
)
|
||||
|
||||
// DomainBlockPlugin is a plugin that blocks messages containing links from specific domains
|
||||
type DomainBlockPlugin struct {
|
||||
plugin.BasePlugin
|
||||
}
|
||||
|
||||
// New creates a new DomainBlockPlugin instance
|
||||
func New() *DomainBlockPlugin {
|
||||
return &DomainBlockPlugin{
|
||||
BasePlugin: plugin.BasePlugin{
|
||||
ID: "security.domainblock",
|
||||
Name: "Domain Blocker",
|
||||
Help: "Blocks messages containing links from configured domains",
|
||||
ConfigRequired: true, // Mark this plugin as requiring configuration
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// OnMessage processes incoming messages
|
||||
func (p *DomainBlockPlugin) OnMessage(msg *model.Message, config map[string]interface{}) []*model.Message {
|
||||
// Get blocked domains from config
|
||||
blockedDomainsStr, ok := config["blocked_domains"].(string)
|
||||
if !ok || blockedDomainsStr == "" {
|
||||
return nil // No blocked domains configured
|
||||
}
|
||||
|
||||
// Split and clean blocked domains
|
||||
blockedDomains := strings.Split(blockedDomainsStr, ",")
|
||||
for i, domain := range blockedDomains {
|
||||
blockedDomains[i] = strings.ToLower(strings.TrimSpace(domain))
|
||||
}
|
||||
|
||||
// Extract domains from message
|
||||
urlRegex := regexp.MustCompile(`https?://([^\s/$.?#].[^\s]*)`)
|
||||
matches := urlRegex.FindAllStringSubmatch(msg.Text, -1)
|
||||
|
||||
// Check if any extracted domains are blocked
|
||||
for _, match := range matches {
|
||||
if len(match) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
domain := strings.ToLower(match[1])
|
||||
|
||||
for _, blockedDomain := range blockedDomains {
|
||||
if blockedDomain == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasSuffix(domain, blockedDomain) || domain == blockedDomain {
|
||||
// Domain is blocked, create warning message
|
||||
response := &model.Message{
|
||||
Text: fmt.Sprintf("⚠️ Message contained a link to blocked domain: %s", blockedDomain),
|
||||
Chat: msg.Chat,
|
||||
ReplyTo: msg.ID,
|
||||
Channel: msg.Channel,
|
||||
}
|
||||
return []*model.Message{response}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
plugin.Register(New())
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Example: URL Transformer
|
||||
|
||||
This more complex plugin transforms URLs, useful for improving media embedding in chat platforms:
|
||||
|
@ -143,6 +229,36 @@ func (p *TwitterExpander) OnMessage(msg *model.Message, config map[string]interf
|
|||
}
|
||||
```
|
||||
|
||||
## Enabling Configuration for Plugins
|
||||
|
||||
To indicate that your plugin requires configuration:
|
||||
|
||||
1. Set `ConfigRequired: true` in the BasePlugin struct:
|
||||
```go
|
||||
BasePlugin: plugin.BasePlugin{
|
||||
ID: "myplugin.id",
|
||||
Name: "Plugin Name",
|
||||
Help: "Help text",
|
||||
ConfigRequired: true,
|
||||
},
|
||||
```
|
||||
|
||||
2. Access the configuration in the OnMessage method:
|
||||
```go
|
||||
func (p *MyPlugin) OnMessage(msg *model.Message, config map[string]interface{}) []*model.Message {
|
||||
// Extract configuration values
|
||||
configValue, ok := config["some_config_key"].(string)
|
||||
if !ok || configValue == "" {
|
||||
// Handle missing or empty configuration
|
||||
return nil
|
||||
}
|
||||
|
||||
// Use the configuration...
|
||||
}
|
||||
```
|
||||
|
||||
3. The admin interface will show a "Configure" button for plugins that require configuration.
|
||||
|
||||
## Registering Plugins
|
||||
|
||||
To use the plugin, register it in your application:
|
||||
|
@ -161,3 +277,11 @@ func (a *App) Run() error {
|
|||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, you can register your plugin in its init() function:
|
||||
|
||||
```go
|
||||
func init() {
|
||||
plugin.Register(New())
|
||||
}
|
||||
```
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
- Remind Me: Reply to a message with `!remindme <duration>` to set a reminder. Supported duration units: y (years), mo (months), d (days), h (hours), m (minutes), s (seconds). Examples: `!remindme 1y` for 1 year, `!remindme 3mo` for 3 months, `!remindme 2d` for 2 days, `!remindme 3h` for 3 hours. The bot will mention you with a reminder after the specified time.
|
||||
|
||||
### Security
|
||||
|
||||
- Domain Blocker: Blocks messages containing links from specified domains. Configure it per channel with a comma-separated list of domains to block. When a message contains a link matching any of the blocked domains, the bot will notify that the message contained a blocked domain. This plugin requires configuration through the admin interface.
|
||||
|
||||
### Social Media
|
||||
|
||||
- Twitter Link Expander: Automatically converts twitter.com and x.com links to fxtwitter.com links and removes tracking parameters. This allows for better media embedding in chat platforms.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue