Browse Source

Google Safe Browsing API support

pull/1/head
Jan-Lukas Else 4 years ago
parent
commit
3947d9e671
7 changed files with 70 additions and 8 deletions
  1. +4
    -1
      README.md
  2. +1
    -0
      config.go
  3. +4
    -0
      config_test.go
  4. +1
    -1
      forms.go
  5. +1
    -1
      go.mod
  6. +10
    -5
      go.sum
  7. +49
    -0
      spamcheck.go

+ 4
- 1
README.md View File

@ -29,6 +29,7 @@ To run the server, you must set a few environment variables from the list below.
| **`ALLOWED_TO`** | required | - | All allowed recipients (separated by `,`) |
| **`PORT`** | optional | `8080` | The port on which the server should listen |
| **`HONEYPORTS`** | optional | `_t_email` | Honeypot form fields (separated by `,`) |
| **`GOOGLE_API_KEY`** | optional | - | Google API Key for the [Google Safe Browsing API](https://developers.google.com/safe-browsing/v4/) |
## Special form fields
@ -42,10 +43,12 @@ You can find a sample form in the `form.html` file. Only fields whose name do no
| **`_formName`** | optional | - | Name of the form, hidden |
| **`_t_email`** | optional | - | (Default) "Honeypot" field, not hidden, advised (see notice below) |
## Honeypot
## Spam protection
MailyGo offers the option to use a [Honeypot](https://en.wikipedia.org/wiki/Honeypot\_(computing)) field, which is basically another input, but it's hidden to the user with either a CSS rule or some JavaScript. It is very likely, that your public form will get the attention of some bots some day and then the spam starts. But bots try to fill every possible input field and will also fill the honeypot field. MailyGo won't send mails of form submissions where a honeypot field is filled. So you should definitely use it.
If a Google Safe Browsing API key is set, submitted URLs will also get checked for threats.
## License
MailyGo is licensed under the MIT license, so you can do basically everything with it, but nevertheless, please contribute your improvements to make MailyGo better for everyone. See the LICENSE file.

+ 1
- 0
config.go View File

@ -15,6 +15,7 @@ type config struct {
SmtpPassword string `env:"SMTP_PASS"`
SmtpHost string `env:"SMTP_HOST"`
SmtpPort int `env:"SMTP_PORT" envDefault:"587"`
GoogleApiKey string `env:"GOOGLE_API_KEY"`
}
func parseConfig() (config, error) {


+ 4
- 0
config_test.go View File

@ -35,6 +35,7 @@ func Test_parseConfig(t *testing.T) {
_ = os.Setenv("SMTP_PASS", "secret")
_ = os.Setenv("SMTP_HOST", "smtp.example.com")
_ = os.Setenv("SMTP_PORT", "100")
_ = os.Setenv("GOOGLE_API_KEY", "abc")
cfg, err := parseConfig()
if err != nil {
t.Error()
@ -67,6 +68,9 @@ func Test_parseConfig(t *testing.T) {
if !reflect.DeepEqual(cfg.SmtpPort, 100) {
t.Error("SMTP port is wrong")
}
if !reflect.DeepEqual(cfg.GoogleApiKey, "abc") {
t.Error("Google API Key is wrong")
}
})
t.Run("Error when wrong config", func(t *testing.T) {
os.Clearenv()


+ 1
- 1
forms.go View File

@ -53,7 +53,7 @@ func isBot(values FormValues) bool {
}
}
}
return false
return checkValues(values)
}
func sendResponse(values FormValues, w http.ResponseWriter) {


+ 1
- 1
go.mod View File

@ -4,6 +4,6 @@ go 1.14
require (
github.com/caarlos0/env/v6 v6.2.1
github.com/google/safebrowsing v0.0.0-20190624211811-bbf0d20d26b3
github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912
golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
)

+ 10
- 5
go.sum View File

@ -6,21 +6,26 @@ github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/safebrowsing v0.0.0-20190624211811-bbf0d20d26b3 h1:4SV2fLwScO6iAgUKNqXwIrz9Fq2ykQxbSV4ObXtNCWY=
github.com/google/safebrowsing v0.0.0-20190624211811-bbf0d20d26b3/go.mod h1:hT4r/grkURkgVSWJaWd6PyS4xfAb+vb34DyMDYiOGa8=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 h1:hJde9rA24hlTcAYSwJoXpDUyGtfKQ/jsofw+WaDqGrI=
github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rakyll/statik v0.1.5/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=


+ 49
- 0
spamcheck.go View File

@ -0,0 +1,49 @@
package main
import (
"github.com/google/safebrowsing"
"net/url"
"strings"
)
// Returns true when it spam
func checkValues(values FormValues) bool {
var urlsToCheck []string
for _, value := range values {
for _, singleValue := range value {
if strings.Contains(singleValue, "http") {
parsed, e := url.Parse(singleValue)
if parsed != nil && e == nil {
urlsToCheck = append(urlsToCheck, singleValue)
}
}
}
}
return checkUrls(urlsToCheck)
}
// Only tests when GOOGLE_API_KEY is set
// Returns true when it spam
func checkUrls(urlsToCheck []string) bool {
if len(appConfig.GoogleApiKey) < 1 || len(urlsToCheck) == 0 {
return false
}
sb, err := safebrowsing.NewSafeBrowser(safebrowsing.Config{
APIKey: appConfig.GoogleApiKey,
ID: "MailyGo",
})
if err != nil {
return false
}
allThreats, err := sb.LookupURLs(urlsToCheck)
if err != nil {
return false
}
for _, threats := range allThreats {
if len(threats) > 0 {
// Unsafe url, mark as spam
return true
}
}
return false
}

Loading…
Cancel
Save