Commit ef96d774 authored by Christopher Speller's avatar Christopher Speller Committed by Joram Wilander
Browse files

Updating to support plugins V2 (#1)

parent 47750713
{
"id": "mattermost-profanity-filter",
"name": "Profanity Filter",
"description": "For filtering out naughty words.",
"version": "0.0.2",
"backend": {
"executable": "server/plugin.exe"
},
"settings_schema": {
"settings": [
{
"key": "RejectPosts",
"display_name": "Reject Posts",
"type": "bool",
"help_text": "If set the plugin will reject posts containing profanity instead of censoring."
},
{
"key": "CensorCharacter",
"display_name": "Censor Character",
"type": "text",
"help_text": "The character(s) to use to censor profanity. Censored words' letters will be replaced with this character. Note that markdown will be interpreted. You can escape markdown character with a backslash. For using * you type \\*.",
"placeholder": "Ex. \\*",
"default": "\\*"
}
],
"footer": ""
}
}
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/golang/protobuf"
packages = [
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp"
]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "github.com/alecthomas/log4go"
name = "github.com/gorilla/websocket"
packages = ["."]
revision = "d146e6b86faab5f7e4d135cc63b749d74bf0d4a6"
revision = "5ed622c449da6d44c3c8329331ff47a9e5844f71"
[[projects]]
name = "github.com/gorilla/websocket"
branch = "master"
name = "github.com/hashicorp/go-hclog"
packages = ["."]
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
revision = "69ff559dc25f3b435631604f573a5fa1efdb6433"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-plugin"
packages = ["."]
revision = "e8d22c780116115ae5624720c9af0c97afe4f551"
[[projects]]
branch = "master"
name = "github.com/hashicorp/yamux"
packages = ["."]
revision = "3520598351bb3500a49ae9563f5539666ae0a27c"
[[projects]]
branch = "plugins-2"
name = "github.com/mattermost/mattermost-server"
packages = [
"mlog",
"model",
"plugin",
"plugin/rpcplugin",
"utils/jsonutils",
"utils/markdown"
]
revision = "416c7523c3097af6759b7c40075df51d44624672"
version = "v4.9.2"
revision = "4c1ddcff10b359baf5728b334acb60cc3e1b1123"
[[projects]]
branch = "master"
name = "github.com/mitchellh/go-testing-interface"
packages = ["."]
revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28"
[[projects]]
name = "github.com/nicksnyder/go-i18n"
......@@ -35,6 +66,12 @@
revision = "0dc1626d56435e9d605a29875701721c54bc9bbd"
version = "v1.10.0"
[[projects]]
name = "github.com/oklog/run"
packages = ["."]
revision = "4dadeb3030eda0273a12382bb2348ffc7c9d1a39"
version = "v1.0.0"
[[projects]]
name = "github.com/pborman/uuid"
packages = ["."]
......@@ -44,8 +81,8 @@
[[projects]]
name = "github.com/pelletier/go-toml"
packages = ["."]
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
version = "v1.1.0"
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
version = "v1.2.0"
[[projects]]
name = "github.com/pkg/errors"
......@@ -53,6 +90,31 @@
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
name = "go.uber.org/atomic"
packages = ["."]
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
version = "v1.3.2"
[[projects]]
name = "go.uber.org/multierr"
packages = ["."]
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
version = "v1.1.0"
[[projects]]
name = "go.uber.org/zap"
packages = [
".",
"buffer",
"internal/bufferpool",
"internal/color",
"internal/exit",
"zapcore"
]
revision = "eeedf312bc6c57391d84767a4cd413f02a917974"
version = "v1.8.0"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
......@@ -60,7 +122,88 @@
"bcrypt",
"blowfish"
]
revision = "2d027ae1dddd4694d54f7a8b6cbe78dca8720226"
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
[[projects]]
branch = "master"
name = "golang.org/x/net"
packages = [
"context",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/timeseries",
"trace"
]
revision = "32a936f46389aa10549d60bd7833e54b01685d09"
[[projects]]
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
revision = "ff3583edef7de132f219f0efc00e097cabcc0ec0"
[[projects]]
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"balancer/base",
"balancer/roundrobin",
"codes",
"connectivity",
"credentials",
"encoding",
"encoding/proto",
"grpclog",
"health",
"health/grpc_health_v1",
"internal",
"internal/backoff",
"internal/channelz",
"internal/grpcrand",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"resolver/dns",
"resolver/passthrough",
"stats",
"status",
"tap",
"transport"
]
revision = "168a6198bcb0ef175f7dacec0b8691fc141dc9b8"
version = "v1.13.0"
[[projects]]
name = "gopkg.in/natefinch/lumberjack.v2"
packages = ["."]
revision = "a96e63847dc3c67d17befa69c303767e2f84e54f"
version = "v2.1"
[[projects]]
name = "gopkg.in/yaml.v2"
......@@ -71,6 +214,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "f067bcaf7a860a33bcacac68a709d90ce50728df182d3f549f4254d34e881582"
inputs-digest = "f668865c79a88e53fb00200ef9a572b472033dc51ba31ae6d791e2538c09c121"
solver-name = "gps-cdcl"
solver-version = 1
......@@ -27,7 +27,7 @@
[[constraint]]
name = "github.com/mattermost/mattermost-server"
version = "4.9.2"
branch = "plugins-2"
[prune]
go-tests = true
......
package main
type Configuration struct {
RejectPosts bool
CensorCharacter string
}
func (c *Configuration) IsValid() error {
return nil
}
func (c *Configuration) SetDefaults() {
if c.CensorCharacter == "" {
c.CensorCharacter = "\\*"
}
}
package main
import (
"github.com/mattermost/mattermost-server/plugin/rpcplugin"
)
func main() {
rpcplugin.Main(&Plugin{})
}
......@@ -3,30 +3,24 @@ package main
import (
"net/http"
"strings"
"sync/atomic"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
)
type Plugin struct {
api plugin.API
configuration atomic.Value
badWords map[string]bool
}
plugin.MattermostPlugin
badWords map[string]bool
func (p *Plugin) OnActivate(api plugin.API) error {
p.api = api
if err := p.OnConfigurationChange(); err != nil {
return err
}
RejectPosts bool
CensorCharacter string
}
config := p.config()
config.SetDefaults()
if err := config.IsValid(); err != nil {
return err
}
func main() {
plugin.ClientMain(&Plugin{})
}
func (p *Plugin) OnActivate() error {
p.badWords = make(map[string]bool, len(badWords))
for _, word := range badWords {
p.badWords[word] = true
......@@ -35,24 +29,7 @@ func (p *Plugin) OnActivate(api plugin.API) error {
return nil
}
func (p *Plugin) config() *Configuration {
return p.configuration.Load().(*Configuration)
}
func (p *Plugin) OnConfigurationChange() error {
var configuration Configuration
err := p.api.LoadPluginConfiguration(&configuration)
p.configuration.Store(&configuration)
return err
}
func (p *Plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
config := p.config()
if err := config.IsValid(); err != nil {
http.Error(w, "This plugin is not configured.", http.StatusNotImplemented)
return
}
func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
switch path := r.URL.Path; path {
default:
http.NotFound(w, r)
......@@ -69,10 +46,10 @@ func (p *Plugin) FilterPost(post *model.Post) (*model.Post, string) {
words := strings.Split(message, " ")
for i, word := range words {
if p.WordIsBad(word) {
if p.config().RejectPosts {
if p.RejectPosts {
return nil, "Profane word not allowed: " + word
}
words[i] = strings.Repeat(p.config().CensorCharacter, len(word))
words[i] = strings.Repeat(p.CensorCharacter, len(word))
}
}
......@@ -80,10 +57,10 @@ func (p *Plugin) FilterPost(post *model.Post) (*model.Post, string) {
return post, ""
}
func (p *Plugin) MessageWillBePosted(post *model.Post) (*model.Post, string) {
func (p *Plugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
return p.FilterPost(post)
}
func (p *Plugin) MessageWillBeUpdated(newPost *model.Post, _ *model.Post) (*model.Post, string) {
func (p *Plugin) MessageWillBeUpdated(c *plugin.Context, newPost *model.Post, _ *model.Post) (*model.Post, string) {
return p.FilterPost(newPost)
}
Copyright (c) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# This is an unmaintained fork, left only so it doesn't break imports.
Please see http://log4go.googlecode.com/
Installation:
- Run `goinstall log4go.googlecode.com/hg`
Usage:
- Add the following import:
import l4g "log4go.googlecode.com/hg"
Acknowledgements:
- pomack
For providing awesome patches to bring log4go up to the latest Go spec
// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
package log4go
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
)
type xmlProperty struct {
Name string `xml:"name,attr"`
Value string `xml:",chardata"`
}
type xmlFilter struct {
Enabled string `xml:"enabled,attr"`
Tag string `xml:"tag"`
Level string `xml:"level"`
Type string `xml:"type"`
Property []xmlProperty `xml:"property"`
}
type xmlLoggerConfig struct {
Filter []xmlFilter `xml:"filter"`
}
// Load XML configuration; see examples/example.xml for documentation
func (log Logger) LoadConfiguration(filename string) {
log.Close()
// Open the configuration file
fd, err := os.Open(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not open %q for reading: %s\n", filename, err)
os.Exit(1)
}
contents, err := ioutil.ReadAll(fd)
if err != nil {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not read %q: %s\n", filename, err)
os.Exit(1)
}
xc := new(xmlLoggerConfig)
if err := xml.Unmarshal(contents, xc); err != nil {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not parse XML configuration in %q: %s\n", filename, err)
os.Exit(1)
}
for _, xmlfilt := range xc.Filter {
var filt LogWriter
var lvl Level
bad, good, enabled := false, true, false
// Check required children
if len(xmlfilt.Enabled) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required attribute %s for filter missing in %s\n", "enabled", filename)
bad = true
} else {
enabled = xmlfilt.Enabled != "false"
}
if len(xmlfilt.Tag) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "tag", filename)
bad = true
}
if len(xmlfilt.Type) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "type", filename)
bad = true
}
if len(xmlfilt.Level) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter missing in %s\n", "level", filename)
bad = true
}
switch xmlfilt.Level {
case "FINEST":
lvl = FINEST
case "FINE":
lvl = FINE
case "DEBUG":
lvl = DEBUG
case "TRACE":
lvl = TRACE
case "INFO":
lvl = INFO
case "WARNING":
lvl = WARNING
case "ERROR":
lvl = ERROR
case "CRITICAL":
lvl = CRITICAL
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required child <%s> for filter has unknown value in %s: %s\n", "level", filename, xmlfilt.Level)
bad = true
}
// Just so all of the required attributes are errored at the same time if missing
if bad {
os.Exit(1)
}
switch xmlfilt.Type {
case "console":
filt, good = xmlToConsoleLogWriter(filename, xmlfilt.Property, enabled)
case "file":
filt, good = xmlToFileLogWriter(filename, xmlfilt.Property, enabled)
case "xml":
filt, good = xmlToXMLLogWriter(filename, xmlfilt.Property, enabled)
case "socket":
filt, good = xmlToSocketLogWriter(filename, xmlfilt.Property, enabled)
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Could not load XML configuration in %s: unknown filter type \"%s\"\n", filename, xmlfilt.Type)
os.Exit(1)
}
// Just so all of the required params are errored at the same time if wrong
if !good {
os.Exit(1)
}
// If we're disabled (syntax and correctness checks only), don't add to logger
if !enabled {
continue
}
log[xmlfilt.Tag] = &Filter{lvl, filt}
}
}
func xmlToConsoleLogWriter(filename string, props []xmlProperty, enabled bool) (*ConsoleLogWriter, bool) {
format := "[%D %T] [%L] (%S) %M"
// Parse properties
for _, prop := range props {
switch prop.Name {
case "format":
format = strings.Trim(prop.Value, " \r\n")
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for console filter in %s\n", prop.Name, filename)
}
}
// If it's disabled, we're just checking syntax
if !enabled {
return nil, true
}
clw := NewConsoleLogWriter()
clw.SetFormat(format)
return clw, true
}
// Parse a number with K/M/G suffixes based on thousands (1000) or 2^10 (1024)
func strToNumSuffix(str string, mult int) int {
num := 1
if len(str) > 1 {
switch str[len(str)-1] {
case 'G', 'g':
num *= mult
fallthrough
case 'M', 'm':
num *= mult
fallthrough
case 'K', 'k':
num *= mult
str = str[0 : len(str)-1]
}
}
parsed, _ := strconv.Atoi(str)
return parsed * num
}
func xmlToFileLogWriter(filename string, props []xmlProperty, enabled bool) (*FileLogWriter, bool) {
file := ""
format := "[%D %T] [%L] (%S) %M"
maxlines := 0
maxsize := 0
daily := false
rotate := false
// Parse properties
for _, prop := range props {
switch prop.Name {
case "filename":
file = strings.Trim(prop.Value, " \r\n")
case "format":
format = strings.Trim(prop.Value, " \r\n")
case "maxlines":
maxlines = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1000)
case "maxsize":
maxsize = strToNumSuffix(strings.Trim(prop.Value, " \r\n"), 1024)
case "daily":
daily = strings.Trim(prop.Value, " \r\n") != "false"
case "rotate":
rotate = strings.Trim(prop.Value, " \r\n") != "false"
default:
fmt.Fprintf(os.Stderr, "LoadConfiguration: Warning: Unknown property \"%s\" for file filter in %s\n", prop.Name, filename)
}
}
// Check properties
if len(file) == 0 {
fmt.Fprintf(os.Stderr, "LoadConfiguration: Error: Required property \"%s\" for file filter missing in %s\n", "filename", filename)
return nil, false
}
// If it's disabled, we're just checking syntax
if !enabled {
return nil, true