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) { +	 +	 +	 +	 +//} | 
