diff options
-rw-r--r-- | binnit.cfg | 4 | ||||
-rw-r--r-- | binnit.go | 179 | ||||
-rw-r--r-- | main.go | 59 | ||||
-rw-r--r-- | paste/paste.go | 52 |
4 files changed, 253 insertions, 41 deletions
@@ -12,7 +12,7 @@ bind_addr = 127.0.0.1 bind_port=8080 ## Directory where all pastes are kept -paste_dir=./pastes +paste_dir="./rubbish" ## Directory where HTML files and templates are kept templ_dir=./html @@ -21,4 +21,4 @@ templ_dir=./html max_size=16384 ## logfile -log_file="./binnit.log"
\ No newline at end of file +log_file="./binnit.log" diff --git a/binnit.go b/binnit.go new file mode 100644 index 0000000..0c4c49d --- /dev/null +++ b/binnit.go @@ -0,0 +1,179 @@ +/* + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + * + * (c) Vincenzo "KatolaZ" Nicosia 2017 -- <katolaz@freaknet.org> + * + * + * This file is part of "binnit", a minimal no-fuss pastebin-like + * server written in golang + * + */ + + +package main + +import ( + "fmt" + "log" + "net/http" + "os" + "path/filepath" + "time" + "io" + "binnit/paste" +) + + +var p_conf = Config{ + server_name: "localhost", + bind_addr: "0.0.0.0", + bind_port: "8000", + paste_dir: "./pastes", + templ_dir: "./tmpl", + max_size: 4096, + log_file: "./binnit.log", +} + + + +func min (a, b int) int { + + if a > b { + return b + } else { + return a + } + +} + +func handle_get_paste(w http.ResponseWriter, r *http.Request) { + + var paste_name, orig_name string + var err error + + orig_name = filepath.Clean(r.URL.Path) + paste_name = p_conf.paste_dir + "/" + orig_name + + orig_IP := r.RemoteAddr + + log.Printf("Received GET from %s for '%s'\n", orig_IP, orig_name) + + // The default is to serve index.html + if (orig_name == "/") || (orig_name == "/index.html") { + http.ServeFile(w, r, p_conf.templ_dir + "/index.html") + } else { + // otherwise, if the requested paste exists, we serve it... + if _, err = os.Stat(paste_name); err == nil && orig_name != "./" { + //http.ServeFile(w, r, paste_name) + s, err := prepare_paste_page(&p_conf, orig_name) + if err == nil { + fmt.Fprintf(w, "%s", s) + return + } else { + fmt.Fprintf(w, "Error recovering paste '%s'\n", orig_name) + return + } + } else { + // otherwise, we give say we didn't find it + fmt.Fprintf(w, "Paste '%s' not found\n", orig_name) + return + } + } +} + +func handle_put_paste(w http.ResponseWriter, r *http.Request) { + + + if err := r.ParseForm(); err != nil { + // Invalid POST -- let's serve the default file + http.ServeFile(w, r, p_conf.templ_dir + "/index.html") + } else { + req_body := r.PostForm + + orig_IP := r.RemoteAddr + + log.Printf("Received new POST from %s\n", orig_IP) + + // get title, body, and time + title := req_body.Get("title") + date := time.Now().String() + content := req_body.Get("paste") + + content = content[0:min(len(content), int(p_conf.max_size))] + + ID, err := paste.Store(title, date, content, p_conf.paste_dir) + + log.Printf(" ID: %s; err: %s\n", ID, err) + + if err == nil { + hostname := p_conf.server_name + if show := req_body.Get("show"); show != "1" { + fmt.Fprintf(w, "http://%s/%s", hostname, ID) + return + } else{ + fmt.Fprintf(w, "<html><body>Link: <a href='http://%s/%s'>http://%s/%s</a></body></html>", + hostname, ID, hostname, ID) + return + } + } else { + fmt.Fprintf(w, "%s\n", err) + } + } +} + + +func req_handler(w http.ResponseWriter, r *http.Request) { + + switch r.Method { + case "GET": + handle_get_paste(w, r) + case "POST": + handle_put_paste(w, r) + default: + http.NotFound(w, r) + } +} + +func main() { + + + + parse_config("binnit.cfg", &p_conf) + + + f, err := os.OpenFile(p_conf.log_file, os.O_APPEND | os.O_CREATE | os.O_RDWR, 0600) + if err != nil { + fmt.Fprintf(os.Stderr, "Error opening log_file: %s. Exiting\n", p_conf.log_file) + os.Exit(1) + } + defer f.Close() + + + log.SetOutput(io.Writer(f)) + log.SetPrefix("[binnit]: ") + log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds) + + log.Println("Binnit version 0.1 -- Starting ") + log.Printf(" + Serving pastes on: %s\n", p_conf.server_name) + log.Printf(" + listening on: %s:%s\n", p_conf.bind_addr, p_conf.bind_port ) + log.Printf(" + paste_dir: %s\n", p_conf.paste_dir) + log.Printf(" + templ_dir: %s\n", p_conf.templ_dir) + log.Printf(" + max_size: %d\n", p_conf.max_size) + + // FIXME: create paste_dir if it does not exist + + http.HandleFunc("/", req_handler) + log.Fatal(http.ListenAndServe(p_conf.bind_addr + ":" + p_conf.bind_port, nil)) +} @@ -25,15 +25,14 @@ package main import ( - "crypto/sha256" "fmt" - "io/ioutil" "log" "net/http" "os" "path/filepath" "time" "io" + "binnit/paste" ) @@ -101,7 +100,6 @@ func handle_put_paste(w http.ResponseWriter, r *http.Request) { // Invalid POST -- let's serve the default file http.ServeFile(w, r, p_conf.templ_dir + "/index.html") } else { - h := sha256.New() req_body := r.PostForm orig_IP := r.RemoteAddr @@ -110,48 +108,30 @@ func handle_put_paste(w http.ResponseWriter, r *http.Request) { // get title, body, and time title := req_body.Get("title") - paste := req_body.Get("paste") - now := time.Now().String() - // format content + date := time.Now().String() + content := req_body.Get("paste") + + content = content[0:min(len(content), int(p_conf.max_size))] - paste = paste[0:min(len(paste), int(p_conf.max_size))] + ID, err := paste.Store(title, date, content, p_conf.paste_dir) - content := fmt.Sprintf("# Title: %s\n# Pasted: %s\n------------\n%s", title, now, paste) - - // ccompute the sha256 hash using title, body, and time - h.Write([]byte(content)) - - paste_hash := fmt.Sprintf("%x", h.Sum(nil)) - log.Printf(" `-- hash: %s\n", paste_hash) - paste_dir := p_conf.paste_dir + "/" - - // Now we save the file - for i := 0; i < len(paste_hash)-16; i++ { - paste_name := paste_hash[i:i+16] - if _, err := os.Stat(paste_dir + paste_name); os.IsNotExist(err) { - // The file does not exist, so we can create it - if err := ioutil.WriteFile(paste_dir+ paste_name, []byte(content), 0644); err == nil { - // and then we return the URL: - log.Printf(" `-- saving paste to : %s", paste_dir + paste_name) - //hostname := r.Host - hostname := p_conf.server_name - if show := req_body.Get("show"); show != "1" { - fmt.Fprintf(w, "%s/%s", hostname, paste_name) - return - } else{ - fmt.Fprintf(w, "<html><body>Link: <a href='http://%s/%s'>http://%s/%s</a></body></html>", - hostname, paste_hash[i:i+16], hostname, paste_hash[i:i+16]) - return - } - } else { - fmt.Fprintf(w, "Cannot create the paste.. Sorry!\n") - return - } + log.Printf(" ID: %s; err: %s\n", ID, err) + + if err == nil { + hostname := p_conf.server_name + if show := req_body.Get("show"); show != "1" { + fmt.Fprintf(w, "%s/%s", hostname, ID) + return + } else{ + fmt.Fprintf(w, "<html><body>Link: <a href='http://%s/%s'>http://%s/%s</a></body></html>", + hostname, ID, hostname, ID) + return } + } else { + fmt.Fprintf(w, "%s\n", err) } } } - func req_handler(w http.ResponseWriter, r *http.Request) { switch r.Method { @@ -190,6 +170,7 @@ func main() { log.Printf(" + templ_dir: %s\n", p_conf.templ_dir) log.Printf(" + max_size: %d\n", p_conf.max_size) + // FIXME: create paste_dir if it does not exist http.HandleFunc("/", req_handler) log.Fatal(http.ListenAndServe(p_conf.bind_addr + ":" + p_conf.bind_port, nil)) diff --git a/paste/paste.go b/paste/paste.go new file mode 100644 index 0000000..ce06f6a --- /dev/null +++ b/paste/paste.go @@ -0,0 +1,52 @@ +package paste + +import( + "crypto/sha256" + "fmt" + "log" + "os" + "io/ioutil" + "errors" +) + + + +func Store(title, date, content, dest_dir string) (string, error) { + + h := sha256.New() + + h.Write([]byte(title)) + h.Write([]byte(date)) + h.Write([]byte(content)) + + paste := fmt.Sprintf("# Title: %s\n# Date: %s\n%s", title, date, content) + + paste_hash := fmt.Sprintf("%x", h.Sum(nil)) + log.Printf(" `-- hash: %s\n", paste_hash) + paste_dir := dest_dir + "/" + + + // Now we save the file + for i := 0; i < len(paste_hash)-16; i++ { + paste_name := paste_hash[i:i+16] + if _, err := os.Stat(paste_dir + paste_name); os.IsNotExist(err) { + // The file does not exist, so we can create it + if err := ioutil.WriteFile(paste_dir + paste_name, []byte(paste), 0644); err == nil { + // and then we return the URL: + log.Printf(" `-- saving new paste to : %s", paste_dir + paste_name) + return paste_name, nil + } else { + log.Printf("Cannot create the paste: %s!\n", paste_dir + paste_name) + } + } + } + return "", errors.New("Cannot store the paste...Sorry!") +} + + +//func Retrieve(URI string) (title, date, content string) { + + + + +//} |