Skip to content

Commit

Permalink
add initial support for gpg encoding messages
Browse files Browse the repository at this point in the history
  • Loading branch information
aerth committed Jun 1, 2016
1 parent f527a29 commit cb9dfc7
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 40 deletions.
29 changes: 5 additions & 24 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,27 +91,6 @@ func homeHandler(w http.ResponseWriter, r *http.Request) {
}
}

// loveHandler is just for fun.
// I love lamp. This displays affection for r.URL.Path[1:]
func loveHandler(w http.ResponseWriter, r *http.Request) {

p := bluemonday.UGCPolicy()
subdomain := getSubdomain(r)
lol := p.Sanitize(r.URL.Path[1:])
if r.Method != "GET" {
log.Printf("Something tried %s on %s", r.Method, lol)
http.Redirect(w, r, "/", 301)
}
if subdomain == "" {
fmt.Fprintf(w, "I love %s!", lol)
log.Printf("I love %s says %s at %s", lol, r.UserAgent(), r.RemoteAddr)
} else {
fmt.Fprintf(w, "%s loves %s!", subdomain, lol)
log.Printf("I love %s says %s at %s", subdomain, r.UserAgent(), r.RemoteAddr)
}

}

// customErrorHandler allows cosgo administrator to customize the 404 Error page
// Using the ./templates/error.html file.
func customErrorHandler(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -197,8 +176,10 @@ func emailHandler(rw http.ResponseWriter, r *http.Request) {
}
r.ParseForm() // Could still be funky form
query = r.Form
form := mbox.ParseForm(cosgoDestination, query) // normalize and validate
if form.Email == "@" || form.Email == " " || !strings.ContainsAny(form.Email, "@") || !strings.ContainsAny(form.Email, ".") {

mailform = mbox.ParseFormGPG(cosgoDestination, query, publicKey) // normalize and validate

if mailform.Email == "@" || mailform.Email == " " || !strings.ContainsAny(mailform.Email, "@") || !strings.ContainsAny(mailform.Email, ".") {
http.Redirect(rw, r, "/?status=0&r=4#contact ", http.StatusFound)
return
}
Expand Down Expand Up @@ -227,7 +208,7 @@ func emailHandler(rw http.ResponseWriter, r *http.Request) {
http.Redirect(rw, r, "/?status=1", http.StatusFound)
return
default:
err = mbox.Save(form)
err = mbox.Save(mailform)
if err != nil {
log.Printf("FAILURE-contact: %s at %s\n\t%s %s", r.UserAgent(), r.RemoteAddr, query, err.Error())
http.Redirect(rw, r, "/?status=0&r=6#contact", http.StatusFound)
Expand Down
108 changes: 94 additions & 14 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// cosgo is an easy to use contact form *server*, able to be iframed on a static web site.
package main

/*
Expand Down Expand Up @@ -37,9 +38,12 @@ Contact form server. Saves to local mailbox or uses Mandrill or Sendgrid SMTP AP
// SOFTWARE.

import (
"bytes"
"encoding/base64"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net"
Expand All @@ -54,6 +58,11 @@ import (
"syscall"
"time"

"golang.org/x/crypto/openpgp"

"path"
"path/filepath"

"github.com/aerth/cosgo/mbox"
"github.com/dchest/captcha"
"github.com/gorilla/csrf"
Expand All @@ -71,7 +80,8 @@ var (
err error
hitcounter int
boottime time.Time
Version = "0.7-go-get"
Version = "0.8-go-get"
publicKey []byte
)

// Cosgo - This changes every [cosgoRefresh] minutes
Expand Down Expand Up @@ -116,6 +126,8 @@ var (
mandrillAPIUrl = "https://mandrillapp.com/api/1.0/"
)
var (
mailform *mbox.Form

// ErrNoReferer is returned when a HTTPS request provides an empty Referer
// header.
ErrNoReferer = errors.New("referer not supplied")
Expand All @@ -127,6 +139,7 @@ var (
// ErrBadToken is returned if the CSRF token in the request does not match
// the token in the session, or is otherwise malformed.
ErrBadToken = errors.New("CSRF token invalid, yo")

)

const (
Expand All @@ -147,7 +160,6 @@ var (
static = flag.Bool("static", true, "Serve /static/ files. Use -static=false to disable")
files = flag.Bool("files", true, "Serve /files/ files. Use -files=false to disable")
noredirect = flag.Bool("noredirect", false, "Default is to redirect all 404s back to /. \nSet true to enable error.html template")
love = flag.Bool("love", false, "Fun. Show I love ___ instead of redirect")
config = flag.Bool("config", false, "Use config file at ~/.cosgo")
custom = flag.String("custom", "default", "Example: cosgo2 ...creates $HOME/.cosgo2")
logpath = flag.String("log", "cosgo.log", "Example: /dev/null or /var/log/cosgo/log")
Expand All @@ -156,8 +168,9 @@ var (
form = flag.Bool("form", false, "Use /page/index.html and /templates/form.html, \nsets -pages flag automatically.")
pages = flag.Bool("pages", false, "Serve /page/")
sendgridflag = flag.Bool("sendgrid", false, "Set -sendgrid to not use local mailbox. This automatically sets \"-mailmode sendgrid\"")
resolvemail = flag.Bool("resolvemail", false, "Set true to check email addresses")
resolvemail = flag.Bool("resolvemail", false, "Set true to check email addresses (Outgoing traffic)")
custompages = flag.String("custompages", "page", "Serve pages from X dir")
gpg = flag.String("gpg", "", "Path to gpg Public Key (automatically encrypts messages)")
mailbox = true
)

Expand Down Expand Up @@ -321,6 +334,10 @@ func main() {
if !*nolog {
fmt.Println("\t[logs: " + *logpath + "]")
}
if *gpg != "" {
fmt.Println("\t[gpg pubkey: " + *gpg + "]")
publicKey = read2mem(rel2real(*gpg))
}
if *config {
fmt.Println("\t[config: " + *custom + "]")
}
Expand Down Expand Up @@ -449,9 +466,6 @@ func main() {
r.Methods("GET").Path("/" + *custompages + "/{dir}/{whatever}.html").Handler(sp)
}

if *love == true {
r.HandleFunc("/{whatever}", loveHandler)
}
if *pages == true {
r.HandleFunc("/"+*custompages+"{whatever}", pageHandler)
}
Expand Down Expand Up @@ -481,7 +495,7 @@ func main() {
mbox.Mail = log.New(f, "", 0)

}
// Right-clickable link
// Display right-clickable link
if *debug && !*quiet {
log.Printf("Link: " + getLink(*fastcgi, *bind, *port))
}
Expand Down Expand Up @@ -537,7 +551,7 @@ func main() {
} else {
log.Fatalln("nil listener")
}
case true: //
case true: // Fastcgi + https
if listener != nil {
go fcgi.Serve(listener,
csrf.Protect(antiCSRFkey,
Expand All @@ -551,7 +565,7 @@ func main() {
}
case false:
switch *secure {
case true: // https://, no fastcgi
case true: // https:// only, no fastcgi
if listener != nil {
go http.Serve(listener,
csrf.Protect(antiCSRFkey,
Expand All @@ -561,7 +575,7 @@ func main() {
} else {
log.Fatalln("nil listener")
}
case false: // This is using http:https://, no fastcgi.
case false: // no https, no fastcgi.
if listener != nil {
go http.Serve(listener,
csrf.Protect(antiCSRFkey,
Expand Down Expand Up @@ -607,6 +621,7 @@ func getMandrillKey() string {
return mandrillKey
}

// parseQuery sanitizes inputs and gets ready to save to mbox
func parseQuery(query url.Values) *Form {
p := bluemonday.UGCPolicy()
form := new(Form)
Expand Down Expand Up @@ -639,14 +654,29 @@ func parseQuery(query url.Values) *Form {

}
}
if publicKey != nil {
log.Println("Got form. Encoding it.")
tmpmsg, err := pgpEncode(form.Message, publicKey)
if err != nil {
log.Println("gpg error.")
log.Println(err)
} else {
log.Println("No GPG error.")
form.Message = tmpmsg
}
}
return form
}

// getDomain returns the domain name (without port) of a request.
func getDomain(r *http.Request) string {
type Domains map[string]http.Handler
hostparts := strings.Split(r.Host, ":")
requesthost := hostparts[0]
return requesthost
}

// getSubdomain returns the subdomain (if any)
func getSubdomain(r *http.Request) string {
type Subdomains map[string]http.Handler
hostparts := strings.Split(r.Host, ":")
Expand Down Expand Up @@ -679,10 +709,60 @@ func generateAPIKey(n int) string {
return strings.TrimSpace(string(b))
}

func pgpEncode(plain string) (ciphertext string) {
ciphertext = plain
return ciphertext
func rel2real(file string) (realpath string) {
pathdir, _ := path.Split(file)

if pathdir == "" {
realpath, _ = filepath.Abs(file)
} else {
realpath = file
}
return realpath
}

func read2mem(abspath string) []byte {
file, err := os.Open(abspath) // For read access.
if err != nil {
log.Fatal(err)
}

data := make([]byte, 4096)
_, err = file.Read(data)
if err != nil {
log.Fatal(err)
}


return data


}

func pgpEncode(plain string, publicKey []byte) (encStr string, err error) {
entitylist, err := openpgp.ReadArmoredKeyRing(bytes.NewBuffer(publicKey))
if err != nil {
log.Fatal(err)
}

// Encrypt message using public key
buf := new(bytes.Buffer)
w, err := openpgp.Encrypt(buf, entitylist, nil, nil, nil)
if err != nil {
}
_, err = w.Write([]byte(plain))
if err != nil {
}
err = w.Close()
if err != nil {
}

// Output as base64 encoded string
bytes, err := ioutil.ReadAll(buf)
encStr = base64.StdEncoding.EncodeToString(bytes)

return encStr, nil
}

// Copyright 2016 aerth and contributors. Source code at https://github.com/aerth/cosgo
// Copyright 2016 aerth. All Rights Reserved.
// Full source code at https://github.com/aerth/cosgo
// There should be a copy of the MIT license bundled with this software.
Loading

0 comments on commit cb9dfc7

Please sign in to comment.