Initial Commit
This commit is contained in:
		
							
								
								
									
										17
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
FROM golang:alpine
 | 
			
		||||
 | 
			
		||||
EXPOSE 8000/tcp
 | 
			
		||||
 | 
			
		||||
ENTRYPOINT ["pastebin"]
 | 
			
		||||
 | 
			
		||||
RUN \
 | 
			
		||||
    apk add --update git && \
 | 
			
		||||
    rm -rf /var/cache/apk/*
 | 
			
		||||
 | 
			
		||||
RUN mkdir -p /go/src/pastebin
 | 
			
		||||
WORKDIR /go/src/pastebin
 | 
			
		||||
 | 
			
		||||
COPY . /go/src/pastebin
 | 
			
		||||
 | 
			
		||||
RUN go get -v -d
 | 
			
		||||
RUN go install -v
 | 
			
		||||
							
								
								
									
										22
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
Copyright (C) 2017 James Mills
 | 
			
		||||
 | 
			
		||||
httpfs is covered by the MIT license::
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person
 | 
			
		||||
obtaining a copy of this software and associated documentation
 | 
			
		||||
files (the "Software"), to deal in the Software without restriction,
 | 
			
		||||
including without limitation the rights to use, copy, modify, merge,
 | 
			
		||||
publish, distribute, sublicense, and/or sell copies of the Software,
 | 
			
		||||
and to permit persons to whom the Software is furnished to do so,
 | 
			
		||||
subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included
 | 
			
		||||
in all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
			
		||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 | 
			
		||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 | 
			
		||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 | 
			
		||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										13
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
.PHONY: dev build clean
 | 
			
		||||
 | 
			
		||||
all: dev
 | 
			
		||||
 | 
			
		||||
dev: build
 | 
			
		||||
	./pastebin -bind 127.0.0.1:8000
 | 
			
		||||
 | 
			
		||||
build: clean
 | 
			
		||||
	go get ./...
 | 
			
		||||
	go build -o ./pastebin .
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -rf bin pastebin
 | 
			
		||||
							
								
								
									
										49
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
# pastebin
 | 
			
		||||
[](https://travis-ci.org/prologic/pastebin)
 | 
			
		||||
[](https://godoc.org/github.com/prologic/pastebin)
 | 
			
		||||
[](https://github.com/prologic/pastebin/wiki)
 | 
			
		||||
[](https://goreportcard.com/report/github.com/prologic/pastebin)
 | 
			
		||||
[](https://coveralls.io/r/prologic/pastebin)
 | 
			
		||||
 | 
			
		||||
pastebin is a web app that allows you to create smart bookmarks, commands and aliases by pointing your web browser's default search engine at a running instance. Similar to bunny1 or yubnub.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
### Source
 | 
			
		||||
 | 
			
		||||
```#!bash
 | 
			
		||||
$ go install github.com/prologic/pastebin/...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### OS X Homebrew
 | 
			
		||||
 | 
			
		||||
There is a formula provided that you can tap and install from
 | 
			
		||||
[prologic/homebrew-pastebin](https://github.com/prologic/homebrew-pastebin):
 | 
			
		||||
 | 
			
		||||
```#!bash
 | 
			
		||||
$ brew tap prologic/pastebin
 | 
			
		||||
$ brew install pastebin
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**NB:** This installs the latest released binary; so if you want a more
 | 
			
		||||
recent unreleased version from master you'll have to clone the repository
 | 
			
		||||
and build yourself.
 | 
			
		||||
 | 
			
		||||
pastebin is still early days so contributions, ideas and expertise are
 | 
			
		||||
much appreciated and highly welcome!
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
Run pastebin:
 | 
			
		||||
 | 
			
		||||
```#!bash
 | 
			
		||||
$ pastebin -bind 127.0.0.1:8000
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Set your browser's default pastebin engine to http://localhost:8000/?q=%s
 | 
			
		||||
 | 
			
		||||
Then type `help` to view the main help page, `g foo bar` to perform a [Google](https://google.com) search for "foo bar" or `list` to list all available commands.
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
MIT
 | 
			
		||||
							
								
								
									
										7
									
								
								config.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								config.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
// Config ...
 | 
			
		||||
type Config struct {
 | 
			
		||||
	expiry int
 | 
			
		||||
	fqdn   string
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								config_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								config_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestZeroConfig(t *testing.T) {
 | 
			
		||||
	assert := assert.New(t)
 | 
			
		||||
 | 
			
		||||
	cfg := Config{}
 | 
			
		||||
	assert.Equal(cfg.expiry, 0)
 | 
			
		||||
	assert.Equal(cfg.fqdn, "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestConfig(t *testing.T) {
 | 
			
		||||
	assert := assert.New(t)
 | 
			
		||||
 | 
			
		||||
	cfg := Config{expiry: 1800, fqdn: "https://localhost"}
 | 
			
		||||
	assert.Equal(cfg.expiry, 1800)
 | 
			
		||||
	assert.Equal(cfg.fqdn, "https://localhost")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"log"
 | 
			
		||||
 | 
			
		||||
	"github.com/boltdb/bolt"
 | 
			
		||||
	"github.com/namsral/flag"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	db  *bolt.DB
 | 
			
		||||
	cfg Config
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var (
 | 
			
		||||
		config string
 | 
			
		||||
		dbpath string
 | 
			
		||||
		bind   string
 | 
			
		||||
		fqdn   string
 | 
			
		||||
		expiry int
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	flag.StringVar(&config, "config", "", "config file")
 | 
			
		||||
	flag.StringVar(&dbpath, "dbpth", "urls.db", "Database path")
 | 
			
		||||
	flag.StringVar(&bind, "bind", "0.0.0.0:8000", "[int]:<port> to bind to")
 | 
			
		||||
	flag.StringVar(&fqdn, "fqdn", "localhost", "FQDN for public access")
 | 
			
		||||
	flag.IntVar(&expiry, "expiery", 5, "expiry time (mins) for passte")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	// TODO: Abstract the Config and Handlers better
 | 
			
		||||
	cfg.fqdn = fqdn
 | 
			
		||||
	cfg.expiry = expiry
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	db, err = bolt.Open(dbpath, 0600, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer db.Close()
 | 
			
		||||
 | 
			
		||||
	NewServer(bind, cfg).ListenAndServe()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								scripts/release.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										43
									
								
								scripts/release.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
echo -n "Version to tag: "
 | 
			
		||||
read TAG
 | 
			
		||||
 | 
			
		||||
echo -n "Name of release: "
 | 
			
		||||
read NAME
 | 
			
		||||
 | 
			
		||||
echo -n "Desc of release: "
 | 
			
		||||
read DESC
 | 
			
		||||
 | 
			
		||||
git tag ${TAG}
 | 
			
		||||
git push --tags
 | 
			
		||||
 | 
			
		||||
if [ ! -d ./bin ]; then
 | 
			
		||||
	mkdir bin
 | 
			
		||||
else
 | 
			
		||||
	rm -rf ./bin/*
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo -n "Building binaries ... "
 | 
			
		||||
 | 
			
		||||
rice embed-go
 | 
			
		||||
 | 
			
		||||
GOOS=linux GOARCH=amd64 go build -o ./bin/pastebin-Linux-x86_64 .
 | 
			
		||||
GOOS=linux GOARCH=arm64 go build -o ./bin/pastebin-Linux-x86_64 .
 | 
			
		||||
GOOS=darwin GOARCH=amd64 go build -o ./bin/pastebin-Darwin-x86_64 .
 | 
			
		||||
GOOS=windows GOARCH=amd64 go build -o ./bin/pastebin-Windows-x86_64.exe .
 | 
			
		||||
 | 
			
		||||
echo "DONE"
 | 
			
		||||
 | 
			
		||||
echo -n "Uploading binaries ... "
 | 
			
		||||
 | 
			
		||||
github-release release \
 | 
			
		||||
    -u prologic -p -r pastebin \
 | 
			
		||||
    -t ${TAG} -n "${NAME}" -d "${DESC}"
 | 
			
		||||
 | 
			
		||||
for file in bin/*; do
 | 
			
		||||
    name="$(echo $file | sed -e 's|bin/||g')"
 | 
			
		||||
    github-release upload -u prologic -r pastebin -t ${TAG} -n $name -f $file
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
echo "DONE"
 | 
			
		||||
							
								
								
									
										109
									
								
								server.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								server.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/GeertJohan/go.rice"
 | 
			
		||||
	"github.com/julienschmidt/httprouter"
 | 
			
		||||
	"github.com/patrickmn/go-cache"
 | 
			
		||||
	"github.com/renstrom/shortuuid"
 | 
			
		||||
	"go.iondynamics.net/templice"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Server ...
 | 
			
		||||
type Server struct {
 | 
			
		||||
	bind      string
 | 
			
		||||
	config    Config
 | 
			
		||||
	store     *cache.Cache
 | 
			
		||||
	templates *templice.Template
 | 
			
		||||
	router    *httprouter.Router
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) render(w http.ResponseWriter, tmpl string, data interface{}) {
 | 
			
		||||
	err := s.templates.ExecuteTemplate(w, tmpl+".html", data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, err.Error(), http.StatusInternalServerError)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IndexHandler ...
 | 
			
		||||
func (s *Server) IndexHandler() httprouter.Handle {
 | 
			
		||||
	return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
 | 
			
		||||
		s.render(w, "index", nil)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PasteHandler ...
 | 
			
		||||
func (s *Server) PasteHandler() httprouter.Handle {
 | 
			
		||||
	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
 | 
			
		||||
		err := r.ParseForm()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			http.Error(w, "Internal Error", http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		uuid := shortuuid.NewWithNamespace(s.config.fqdn)
 | 
			
		||||
		blob := r.Form.Get("blob")
 | 
			
		||||
		s.store.Set(uuid, blob, cache.DefaultExpiration)
 | 
			
		||||
 | 
			
		||||
		u, err := url.Parse(fmt.Sprintf("./%s", uuid))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			http.Error(w, "Internal Error", http.StatusInternalServerError)
 | 
			
		||||
		}
 | 
			
		||||
		http.Redirect(w, r, r.URL.ResolveReference(u).String(), http.StatusFound)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ViewHandler ...
 | 
			
		||||
func (s *Server) ViewHandler() httprouter.Handle {
 | 
			
		||||
	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
 | 
			
		||||
		uuid := p.ByName("uuid")
 | 
			
		||||
		if uuid == "" {
 | 
			
		||||
			http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		blob, ok := s.store.Get(uuid)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			http.Error(w, "Not Found", http.StatusNotFound)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		s.render(w, "view", struct{ Blob string }{Blob: blob.(string)})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListenAndServe ...
 | 
			
		||||
func (s *Server) ListenAndServe() {
 | 
			
		||||
	log.Fatal(http.ListenAndServe(s.bind, s.router))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) initRoutes() {
 | 
			
		||||
	s.router.GET("/", s.IndexHandler())
 | 
			
		||||
	s.router.POST("/", s.PasteHandler())
 | 
			
		||||
	s.router.GET("/:uuid", s.ViewHandler())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewServer ...
 | 
			
		||||
func NewServer(bind string, config Config) *Server {
 | 
			
		||||
	server := &Server{
 | 
			
		||||
		bind:      bind,
 | 
			
		||||
		config:    config,
 | 
			
		||||
		router:    httprouter.New(),
 | 
			
		||||
		store:     cache.New(5*time.Minute, 10*time.Minute),
 | 
			
		||||
		templates: templice.New(rice.MustFindBox("templates")),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := server.templates.Load()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Panicf("error loading templates: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server.initRoutes()
 | 
			
		||||
 | 
			
		||||
	return server
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								templates/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								templates/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
<html>
 | 
			
		||||
	<head>
 | 
			
		||||
		<title>pastebin</title>
 | 
			
		||||
	</head>
 | 
			
		||||
	
 | 
			
		||||
	<body>
 | 
			
		||||
		<p>Enter your text here:</p>
 | 
			
		||||
		<form method="POST" action="">
 | 
			
		||||
			<textarea name="blob" cols=80 rows=24></textarea>
 | 
			
		||||
			<input type="submit">
 | 
			
		||||
		</form>
 | 
			
		||||
	</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										10
									
								
								templates/view.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								templates/view.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<html>
 | 
			
		||||
	<head>
 | 
			
		||||
		<title>pastebin</title>
 | 
			
		||||
	</head>
 | 
			
		||||
	
 | 
			
		||||
	<body>
 | 
			
		||||
		<pre>{{.Blob}}</pre>
 | 
			
		||||
	</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										19
									
								
								utils.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								utils.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RandomString ...
 | 
			
		||||
func RandomString(length int) string {
 | 
			
		||||
	bytes := make([]byte, length)
 | 
			
		||||
	rand.Read(bytes)
 | 
			
		||||
	for i, b := range bytes {
 | 
			
		||||
		bytes[i] = alphabet[b%byte(len(alphabet))]
 | 
			
		||||
	}
 | 
			
		||||
	return string(bytes)
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user