Compare commits

..

5 Commits

25 changed files with 533 additions and 454 deletions

View File

@ -3,9 +3,7 @@
# Fast Pastebin
Easy-to-use-and-install pastebin software written in Go. No bells or
whistles, no websockets and even NO JAVASCRIPT!(*)
(*) Except fontawesome, because it's awesome :).
whistles, no websockets and even NO JAVASCRIPT!
# Current functionality.

View File

@ -27,11 +27,10 @@ package http
import (
// stdlib
"net/http"
"strings"
// local
"github.com/pztrn/fastpastebin/api/http/static"
"github.com/pztrn/fastpastebin/captcha"
"github.com/pztrn/fastpastebin/templater"
// other
"github.com/alecthomas/chroma/lexers"
@ -40,11 +39,6 @@ import (
// Index of this site.
func indexGet(ec echo.Context) error {
htmlRaw, err := static.ReadFile("index.html")
if err != nil {
return ec.String(http.StatusNotFound, "index.html wasn't found!")
}
// Generate list of available languages to highlight.
availableLexers := lexers.Names(false)
@ -53,11 +47,10 @@ func indexGet(ec echo.Context) error {
availableLexersSelectOpts += "<option value='" + availableLexers[i] + "'>" + availableLexers[i] + "</option>"
}
html := strings.Replace(string(htmlRaw), "{lexers}", availableLexersSelectOpts, 1)
// Captcha.
captchaString := captcha.NewCaptcha()
html = strings.Replace(html, "{captchaString}", captchaString, -1)
return ec.HTML(http.StatusOK, html)
htmlData := templater.GetTemplate(ec, "index.html", map[string]string{"lexers": availableLexersSelectOpts, "captchaString": captchaString})
return ec.HTML(http.StatusOK, htmlData)
}

View File

@ -1,5 +1,5 @@
// Code generated by fileb0x at "2018-05-18 22:25:13.180720675 +0500 +05 m=+0.030971779" from config file "fileb0x.yml" DO NOT EDIT.
// modification hash(1679c5529785a2e624071b2679319ecb.608888160ddb195ed89fce5ab290ff92)
// Code generated by fileb0x at "2018-05-26 13:58:30.612342807 +0500 +05 m=+0.013490397" from config file "fileb0x.yml" DO NOT EDIT.
// modification hash(e9e210106a4d77680942064c40d06a3e.522a9cc525fa984df98098d4c3992752)
package static

View File

@ -1,5 +1,5 @@
// Code generaTed by fileb0x at "2018-05-01 18:35:23.702577304 +0500 +05 m=+0.047872409" from config file "fileb0x.yml" DO NOT EDIT.
// modified(2018-05-01 18:35:02 +0500 +05)
// Code generaTed by fileb0x at "2018-05-26 13:29:06.05698436 +0500 +05 m=+0.013970976" from config file "fileb0x.yml" DO NOT EDIT.
// modified(2018-05-26 13:29:04.002355958 +0500 +05)
// original path: assets/error.html
package static
@ -10,7 +10,7 @@ import (
)
// FileErrorHTML is "/error.html"
var FileErrorHTML = []byte("\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x68\x74\x6d\x6c\x3e\x0a\x3c\x68\x74\x6d\x6c\x3e\x0a\x0a\x3c\x68\x65\x61\x64\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x63\x68\x61\x72\x73\x65\x74\x3d\x22\x75\x74\x66\x2d\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x6e\x61\x6d\x65\x3d\x22\x76\x69\x65\x77\x70\x6f\x72\x74\x22\x20\x63\x6f\x6e\x74\x65\x6e\x74\x3d\x22\x77\x69\x64\x74\x68\x3d\x64\x65\x76\x69\x63\x65\x2d\x77\x69\x64\x74\x68\x2c\x20\x69\x6e\x69\x74\x69\x61\x6c\x2d\x73\x63\x61\x6c\x65\x3d\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x74\x69\x74\x6c\x65\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x20\x2d\x20\x45\x52\x52\x4f\x52\x21\x3c\x2f\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x62\x75\x6c\x6d\x61\x2d\x30\x2e\x37\x2e\x30\x2e\x6d\x69\x6e\x2e\x63\x73\x73\x22\x3e\x0a\x20\x20\x20\x20\x3c\x73\x63\x72\x69\x70\x74\x20\x64\x65\x66\x65\x72\x20\x73\x72\x63\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x6a\x73\x2f\x66\x6f\x6e\x74\x61\x77\x65\x73\x6f\x6d\x65\x2d\x35\x2e\x30\x2e\x37\x2e\x6a\x73\x22\x3e\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x73\x74\x79\x6c\x65\x2e\x63\x73\x73\x22\x3e\x0a\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x0a\x3c\x62\x6f\x64\x79\x3e\x0a\x20\x20\x20\x20\x3c\x6e\x61\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x20\x69\x73\x2d\x64\x61\x72\x6b\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x72\x61\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x22\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x70\x61\x73\x74\x65\x73\x2f\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x50\x61\x73\x74\x65\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x75\x72\x67\x65\x72\x20\x62\x75\x72\x67\x65\x72\x22\x20\x64\x61\x74\x61\x2d\x74\x61\x72\x67\x65\x74\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x69\x64\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x6d\x65\x6e\x75\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x73\x74\x61\x72\x74\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x65\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6e\x61\x76\x3e\x0a\x20\x20\x20\x20\x3c\x73\x65\x63\x74\x69\x6f\x6e\x20\x63\x6c\x61\x73\x73\x3d\x22\x73\x65\x63\x74\x69\x6f\x6e\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x3e\x7b\x65\x72\x72\x6f\x72\x7d\x3c\x2f\x70\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x73\x65\x63\x74\x69\x6f\x6e\x3e\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x0a\x0a\x3c\x2f\x68\x74\x6d\x6c\x3e")
var FileErrorHTML = []byte("\x3c\x73\x65\x63\x74\x69\x6f\x6e\x20\x63\x6c\x61\x73\x73\x3d\x22\x73\x65\x63\x74\x69\x6f\x6e\x22\x3e\x0a\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x62\x6f\x78\x20\x68\x61\x73\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x2d\x77\x61\x72\x6e\x69\x6e\x67\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x3e\x7b\x65\x72\x72\x6f\x72\x7d\x3c\x2f\x70\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x3c\x2f\x73\x65\x63\x74\x69\x6f\x6e\x3e")
func init() {

View File

@ -0,0 +1,35 @@
// Code generaTed by fileb0x at "2018-05-26 12:55:42.087956217 +0500 +05 m=+0.009637095" from config file "fileb0x.yml" DO NOT EDIT.
// modified(2018-05-26 12:54:22.9990735 +0500 +05)
// original path: assets/footer.html
package static
import (
"os"
)
// FileFooterHTML is "/footer.html"
var FileFooterHTML = []byte("\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x63\x6f\x6e\x74\x61\x69\x6e\x65\x72\x22\x3e\x0a\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x63\x6f\x6e\x74\x65\x6e\x74\x20\x68\x61\x73\x2d\x74\x65\x78\x74\x2d\x63\x65\x6e\x74\x65\x72\x65\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x72\x6f\x6e\x67\x3e\x46\x61\x73\x74\x20\x70\x61\x73\x74\x65\x20\x62\x69\x6e\x3c\x2f\x73\x74\x72\x6f\x6e\x67\x3e\x20\x76\x65\x72\x73\x69\x6f\x6e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x72\x6f\x6e\x67\x3e\x7b\x76\x65\x72\x73\x69\x6f\x6e\x7d\x3c\x2f\x73\x74\x72\x6f\x6e\x67\x3e\x20\x62\x79\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x68\x72\x65\x66\x3d\x22\x68\x74\x74\x70\x73\x3a\x2f\x2f\x70\x7a\x74\x72\x6e\x2e\x6e\x61\x6d\x65\x22\x3e\x53\x74\x61\x6e\x69\x73\x6c\x61\x76\x20\x4e\x2e\x20\x61\x6b\x61\x20\x70\x7a\x74\x72\x6e\x3c\x2f\x61\x3e\x2e\x20\x54\x68\x65\x20\x73\x6f\x75\x72\x63\x65\x20\x63\x6f\x64\x65\x20\x69\x73\x20\x6c\x69\x63\x65\x6e\x73\x65\x64\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x68\x72\x65\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x6f\x70\x65\x6e\x73\x6f\x75\x72\x63\x65\x2e\x6f\x72\x67\x2f\x6c\x69\x63\x65\x6e\x73\x65\x73\x2f\x6d\x69\x74\x2d\x6c\x69\x63\x65\x6e\x73\x65\x2e\x70\x68\x70\x22\x3e\x4d\x49\x54\x3c\x2f\x61\x3e\x2e\x20\x47\x65\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x68\x72\x65\x66\x3d\x22\x68\x74\x74\x70\x73\x3a\x2f\x2f\x67\x69\x74\x68\x75\x62\x2e\x63\x6f\x6d\x2f\x70\x7a\x74\x72\x6e\x2f\x66\x61\x73\x74\x70\x61\x73\x74\x65\x62\x69\x6e\x22\x3e\x73\x6f\x75\x72\x63\x65\x20\x6f\x72\x20\x62\x69\x6e\x61\x72\x79\x20\x72\x65\x6c\x65\x61\x73\x65\x73\x20\x68\x65\x72\x65\x3c\x2f\x61\x3e\x21\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x70\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x3c\x2f\x64\x69\x76\x3e")
func init() {
f, err := FS.OpenFile(CTX, "/footer.html", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
if err != nil {
panic(err)
}
_, err = f.Write(FileFooterHTML)
if err != nil {
panic(err)
}
err = f.Close()
if err != nil {
panic(err)
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,35 @@
// Code generaTed by fileb0x at "2018-05-26 12:42:22.452857215 +0500 +05 m=+0.054711585" from config file "fileb0x.yml" DO NOT EDIT.
// modified(2018-05-26 12:41:36.015758918 +0500 +05)
// original path: assets/main.html
package static
import (
"os"
)
// FileMainHTML is "/main.html"
var FileMainHTML = []byte("\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x68\x74\x6d\x6c\x3e\x0a\x3c\x68\x74\x6d\x6c\x3e\x0a\x0a\x3c\x68\x65\x61\x64\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x63\x68\x61\x72\x73\x65\x74\x3d\x22\x75\x74\x66\x2d\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x6e\x61\x6d\x65\x3d\x22\x76\x69\x65\x77\x70\x6f\x72\x74\x22\x20\x63\x6f\x6e\x74\x65\x6e\x74\x3d\x22\x77\x69\x64\x74\x68\x3d\x64\x65\x76\x69\x63\x65\x2d\x77\x69\x64\x74\x68\x2c\x20\x69\x6e\x69\x74\x69\x61\x6c\x2d\x73\x63\x61\x6c\x65\x3d\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x74\x69\x74\x6c\x65\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x3c\x2f\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x62\x75\x6c\x6d\x61\x2d\x30\x2e\x37\x2e\x30\x2e\x6d\x69\x6e\x2e\x63\x73\x73\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x62\x75\x6c\x6d\x61\x2d\x74\x6f\x6f\x6c\x74\x69\x70\x2d\x31\x2e\x30\x2e\x34\x2e\x6d\x69\x6e\x2e\x63\x73\x73\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x73\x74\x79\x6c\x65\x2e\x63\x73\x73\x22\x3e\x0a\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x0a\x3c\x62\x6f\x64\x79\x3e\x0a\x20\x20\x20\x20\x7b\x6e\x61\x76\x69\x67\x61\x74\x69\x6f\x6e\x7d\x20\x7b\x64\x6f\x63\x75\x6d\x65\x6e\x74\x42\x6f\x64\x79\x7d\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x0a\x3c\x66\x6f\x6f\x74\x65\x72\x20\x63\x6c\x61\x73\x73\x3d\x22\x66\x6f\x6f\x74\x65\x72\x22\x3e\x0a\x20\x20\x20\x20\x7b\x66\x6f\x6f\x74\x65\x72\x7d\x0a\x3c\x2f\x66\x6f\x6f\x74\x65\x72\x3e\x0a\x0a\x3c\x2f\x68\x74\x6d\x6c\x3e")
func init() {
f, err := FS.OpenFile(CTX, "/main.html", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
if err != nil {
panic(err)
}
_, err = f.Write(FileMainHTML)
if err != nil {
panic(err)
}
err = f.Close()
if err != nil {
panic(err)
}
}

View File

@ -0,0 +1,35 @@
// Code generaTed by fileb0x at "2018-05-26 13:58:30.613412852 +0500 +05 m=+0.014560424" from config file "fileb0x.yml" DO NOT EDIT.
// modified(2018-05-26 13:57:14.88231462 +0500 +05)
// original path: assets/navigation.html
package static
import (
"os"
)
// FileNavigationHTML is "/navigation.html"
var FileNavigationHTML = []byte("\x3c\x6e\x61\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x20\x69\x73\x2d\x64\x61\x72\x6b\x22\x3e\x0a\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x72\x61\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x22\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x70\x61\x73\x74\x65\x73\x2f\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x50\x61\x73\x74\x65\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x69\x64\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x6d\x65\x6e\x75\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x73\x74\x61\x72\x74\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x65\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x3c\x2f\x6e\x61\x76\x3e")
func init() {
f, err := FS.OpenFile(CTX, "/navigation.html", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
if err != nil {
panic(err)
}
_, err = f.Write(FileNavigationHTML)
if err != nil {
panic(err)
}
err = f.Close()
if err != nil {
panic(err)
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
// Code generaTed by fileb0x at "2018-05-18 22:25:13.191256649 +0500 +05 m=+0.041507879" from config file "fileb0x.yml" DO NOT EDIT.
// modified(2018-05-18 22:17:55.447214662 +0500 +05)
// Code generaTed by fileb0x at "2018-05-26 13:47:21.417964779 +0500 +05 m=+0.019030606" from config file "fileb0x.yml" DO NOT EDIT.
// modified(2018-05-26 13:41:01.75233841 +0500 +05)
// original path: assets/pastelist_list.html
package static
@ -10,7 +10,7 @@ import (
)
// FilePastelistListHTML is "/pastelist_list.html"
var FilePastelistListHTML = []byte("\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x68\x74\x6d\x6c\x3e\x0a\x3c\x68\x74\x6d\x6c\x3e\x0a\x0a\x3c\x68\x65\x61\x64\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x63\x68\x61\x72\x73\x65\x74\x3d\x22\x75\x74\x66\x2d\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x6e\x61\x6d\x65\x3d\x22\x76\x69\x65\x77\x70\x6f\x72\x74\x22\x20\x63\x6f\x6e\x74\x65\x6e\x74\x3d\x22\x77\x69\x64\x74\x68\x3d\x64\x65\x76\x69\x63\x65\x2d\x77\x69\x64\x74\x68\x2c\x20\x69\x6e\x69\x74\x69\x61\x6c\x2d\x73\x63\x61\x6c\x65\x3d\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x74\x69\x74\x6c\x65\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x20\x2d\x20\x50\x61\x73\x74\x65\x73\x3c\x2f\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x62\x75\x6c\x6d\x61\x2d\x30\x2e\x37\x2e\x30\x2e\x6d\x69\x6e\x2e\x63\x73\x73\x22\x3e\x0a\x20\x20\x20\x20\x3c\x73\x63\x72\x69\x70\x74\x20\x64\x65\x66\x65\x72\x20\x73\x72\x63\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x6a\x73\x2f\x66\x6f\x6e\x74\x61\x77\x65\x73\x6f\x6d\x65\x2d\x35\x2e\x30\x2e\x37\x2e\x6a\x73\x22\x3e\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x73\x74\x79\x6c\x65\x2e\x63\x73\x73\x22\x3e\x0a\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x0a\x3c\x62\x6f\x64\x79\x3e\x0a\x20\x20\x20\x20\x3c\x6e\x61\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x20\x69\x73\x2d\x64\x61\x72\x6b\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x72\x61\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x22\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x70\x61\x73\x74\x65\x73\x2f\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x50\x61\x73\x74\x65\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x75\x72\x67\x65\x72\x20\x62\x75\x72\x67\x65\x72\x22\x20\x64\x61\x74\x61\x2d\x74\x61\x72\x67\x65\x74\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x69\x64\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x6d\x65\x6e\x75\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x73\x74\x61\x72\x74\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x65\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6e\x61\x76\x3e\x0a\x20\x20\x20\x20\x3c\x73\x65\x63\x74\x69\x6f\x6e\x20\x63\x6c\x61\x73\x73\x3d\x22\x73\x65\x63\x74\x69\x6f\x6e\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x73\x74\x65\x73\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x73\x65\x63\x74\x69\x6f\x6e\x3e\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x0a\x0a\x3c\x2f\x68\x74\x6d\x6c\x3e")
var FilePastelistListHTML = []byte("\x3c\x73\x65\x63\x74\x69\x6f\x6e\x20\x63\x6c\x61\x73\x73\x3d\x22\x73\x65\x63\x74\x69\x6f\x6e\x22\x3e\x0a\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x7d\x0a\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x73\x74\x65\x73\x7d\x0a\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x7d\x0a\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x3c\x2f\x73\x65\x63\x74\x69\x6f\x6e\x3e")
func init() {

View File

@ -1,40 +1,5 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fast Paste Bin - ERROR!</title>
<link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css">
<script defer src="/static/js/fontawesome-5.0.7.js"></script>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<nav class="navbar is-dark">
<div class="navbar-brand">
<a class="navbar-item" href="/">Fast Paste Bin</a>
<a class="navbar-item" href="/pastes/">
Pastes
</a>
<div class="navbar-burger burger" data-target="navbarItems">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="navbarItems" class="navbar-menu">
<div class="navbar-start">
</div>
<div class="navbar-end">
</div>
</div>
</nav>
<section class="section">
<section class="section">
<div class="box has-background-warning">
<p>{error}</p>
</section>
</body>
</html>
</div>
</section>

11
assets/footer.html Normal file
View File

@ -0,0 +1,11 @@
<div class="container">
<div class="content has-text-centered">
<p>
<strong>Fast paste bin</strong> version
<strong>{version}</strong> by
<a href="https://pztrn.name">Stanislav N. aka pztrn</a>. The source code is licensed
<a href="http://opensource.org/licenses/mit-license.php">MIT</a>. Get
<a href="https://github.com/pztrn/fastpastebin">source or binary releases here</a>!
</p>
</div>
</div>

View File

@ -1,39 +1,4 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fast Paste Bin</title>
<link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css">
<link rel="stylesheet" href="/static/css/bulma-tooltip-1.0.4.min.css">
<script defer src="/static/js/fontawesome-5.0.7.js"></script>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<nav class="navbar is-dark">
<div class="navbar-brand">
<a class="navbar-item" href="/">Fast Paste Bin</a>
<a class="navbar-item" href="/pastes/">
Pastes
</a>
<div class="navbar-burger burger" data-target="navbarItems">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="navbarItems" class="navbar-menu">
<div class="navbar-start">
</div>
<div class="navbar-end">
</div>
</div>
</nav>
<section class="section">
<section class="section">
<form action="/paste/" method="POST" autocomplete="off">
<div class="columns">
<div class="column is-8 field">
@ -114,7 +79,4 @@
</div>
</div>
</form>
</section>
</body>
</html>
</section>

20
assets/main.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fast Paste Bin</title>
<link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css">
<link rel="stylesheet" href="/static/css/bulma-tooltip-1.0.4.min.css">
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
{navigation} {documentBody}
</body>
<footer class="footer">
{footer}
</footer>
</html>

16
assets/navigation.html Normal file
View File

@ -0,0 +1,16 @@
<nav class="navbar is-dark">
<div class="navbar-brand">
<a class="navbar-item" href="/">Fast Paste Bin</a>
<a class="navbar-item" href="/pastes/">
Pastes
</a>
</div>
<div id="navbarItems" class="navbar-menu">
<div class="navbar-start">
</div>
<div class="navbar-end">
</div>
</div>
</nav>

View File

@ -1,38 +1,4 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fast Paste Bin - Paste is protected with password</title>
<link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css">
<script defer src="/static/js/fontawesome-5.0.7.js"></script>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<nav class="navbar is-dark">
<div class="navbar-brand">
<a class="navbar-item" href="/">Fast Paste Bin</a>
<a class="navbar-item" href="/pastes/">
Pastes
</a>
<div class="navbar-burger burger" data-target="navbarItems">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="navbarItems" class="navbar-menu">
<div class="navbar-start">
</div>
<div class="navbar-end">
</div>
</div>
</nav>
<section class="section">
<section class="section">
<div class="content">
<div class="columns">
<div class="column is-4 is-offset-4">
@ -63,7 +29,4 @@
</div>
</div>
</div>
</section>
</body>
</html>
</section>

View File

@ -1,38 +1,4 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fast Paste Bin - Paste #{pasteID}</title>
<link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css">
<script defer src="/static/js/fontawesome-5.0.7.js"></script>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<nav class="navbar is-dark">
<div class="navbar-brand">
<a class="navbar-item" href="/">Fast Paste Bin</a>
<a class="navbar-item" href="/pastes/">
Pastes
</a>
<div class="navbar-burger burger" data-target="navbarItems">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="navbarItems" class="navbar-menu">
<div class="navbar-start">
</div>
<div class="navbar-end">
</div>
</div>
</nav>
<section class="section">
<section class="section">
<div class="content">
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<thead>
@ -62,10 +28,7 @@
</tbody>
</table>
</div>
</section>
<div class="paste-data">
</section>
<div class="paste-data">
{pastedata}
</div>
</body>
</html>
</div>

View File

@ -1,38 +1,4 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fast Paste Bin - Pastes</title>
<link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css">
<script defer src="/static/js/fontawesome-5.0.7.js"></script>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<nav class="navbar is-dark">
<div class="navbar-brand">
<a class="navbar-item" href="/">Fast Paste Bin</a>
<a class="navbar-item" href="/pastes/">
Pastes
</a>
<div class="navbar-burger burger" data-target="navbarItems">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div id="navbarItems" class="navbar-menu">
<div class="navbar-start">
</div>
<div class="navbar-end">
</div>
</div>
</nav>
<section class="section">
<section class="section">
<div>
{pagination}
</div>
@ -42,7 +8,4 @@
<div>
{pagination}
</div>
</section>
</body>
</html>
</section>

View File

@ -37,6 +37,7 @@ import (
"github.com/pztrn/fastpastebin/database"
"github.com/pztrn/fastpastebin/database/migrations"
"github.com/pztrn/fastpastebin/pastes"
"github.com/pztrn/fastpastebin/templater"
)
func main() {
@ -57,6 +58,7 @@ func main() {
c.Database.Initialize()
migrations.New(c)
migrations.Migrate()
templater.Initialize(c)
api.New(c)
api.InitializeAPI()

View File

@ -114,6 +114,23 @@ func (c *Context) LoadConfiguration() {
// Yay! See what it gets!
c.Logger.Debug().Msgf("Parsed configuration: %+v", c.Config)
// Set log level.
c.Logger.Info().Msgf("Setting logger level: %s", c.Config.Logging.LogLevel)
switch c.Config.Logging.LogLevel {
case "DEBUG":
zerolog.SetGlobalLevel(zerolog.DebugLevel)
case "INFO":
zerolog.SetGlobalLevel(zerolog.InfoLevel)
case "WARN":
zerolog.SetGlobalLevel(zerolog.WarnLevel)
case "ERROR":
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
case "FATAL":
zerolog.SetGlobalLevel(zerolog.FatalLevel)
case "PANIC":
zerolog.SetGlobalLevel(zerolog.PanicLevel)
}
}
// RegisterDatabaseInterface registers database interface for later use.

View File

@ -24,6 +24,11 @@
package context
const (
// Version .
Version = "0.1.1"
)
// New creates new context.
func New() *Context {
return &Context{}

View File

@ -95,7 +95,10 @@ custom:
# end: files
- files:
- "assets/error.html"
- "assets/footer.html"
- "assets/index.html"
- "assets/main.html"
- "assets/navigation.html"
- "assets/pagination_ellipsis.html"
- "assets/pagination_link_current.html"
- "assets/pagination_link.html"

View File

@ -34,9 +34,9 @@ import (
"time"
// local
"github.com/pztrn/fastpastebin/api/http/static"
"github.com/pztrn/fastpastebin/captcha"
"github.com/pztrn/fastpastebin/pagination"
"github.com/pztrn/fastpastebin/templater"
// other
"github.com/alecthomas/chroma"
@ -54,11 +54,6 @@ var (
// GET for "/paste/PASTE_ID" and "/paste/PASTE_ID/TIMESTAMP" (private pastes).
func pasteGET(ec echo.Context) error {
errhtml, err := static.ReadFile("error.html")
if err != nil {
return ec.String(http.StatusNotFound, "error.html wasn't found!")
}
pasteIDRaw := ec.Param("id")
// We already get numbers from string, so we will not check strconv.Atoi()
// error.
@ -69,14 +64,14 @@ func pasteGET(ec echo.Context) error {
paste, err1 := GetByID(pasteID)
if err1 != nil {
c.Logger.Error().Msgf("Failed to get paste #%d: %s", pasteID, err1.Error())
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Paste #"+strconv.Itoa(pasteID)+" not found", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Paste #"+strconv.Itoa(pasteID)+" not found")
return ec.HTML(http.StatusBadRequest, errtpl)
}
if paste.IsExpired() {
c.Logger.Error().Msgf("Paste #%d is expired", pasteID)
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Paste #"+strconv.Itoa(pasteID)+" not found", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Paste #"+strconv.Itoa(pasteID)+" not found")
return ec.HTML(http.StatusBadRequest, errtpl)
}
// Check if we have a private paste and it's parameters are correct.
@ -85,14 +80,14 @@ func pasteGET(ec echo.Context) error {
tsProvided, err2 := strconv.ParseInt(tsProvidedStr, 10, 64)
if err2 != nil {
c.Logger.Error().Msgf("Invalid timestamp '%s' provided for getting private paste #%d: %s", tsProvidedStr, pasteID, err2.Error())
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Paste #"+strconv.Itoa(pasteID)+" not found", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Paste #"+strconv.Itoa(pasteID)+" not found")
return ec.HTML(http.StatusBadRequest, errtpl)
}
pasteTs := paste.CreatedAt.Unix()
if tsProvided != pasteTs {
c.Logger.Error().Msgf("Incorrect timestamp '%v' provided for private paste #%d, waiting for %v", tsProvidedStr, pasteID, strconv.FormatInt(pasteTs, 10))
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Paste #"+strconv.Itoa(pasteID)+" not found", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Paste #"+strconv.Itoa(pasteID)+" not found")
return ec.HTML(http.StatusBadRequest, errtpl)
}
}
@ -117,24 +112,20 @@ func pasteGET(ec echo.Context) error {
// If all okay - do nothing :)
}
pasteHTML, err2 := static.ReadFile("paste.html")
if err2 != nil {
return ec.String(http.StatusNotFound, "parse.html wasn't found!")
}
// Format template with paste data.
pasteHTMLAsString := strings.Replace(string(pasteHTML), "{pasteTitle}", paste.Title, 1)
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteID}", strconv.Itoa(paste.ID), -1)
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteDate}", paste.CreatedAt.Format("2006-01-02 @ 15:04:05"), 1)
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteExpiration}", paste.GetExpirationTime().Format("2006-01-02 @ 15:04:05"), 1)
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteLanguage}", paste.Language, 1)
// Format paste data map.
pasteData := make(map[string]string)
pasteData["pasteTitle"] = paste.Title
pasteData["pasteID"] = strconv.Itoa(paste.ID)
pasteData["pasteDate"] = paste.CreatedAt.Format("2006-01-02 @ 15:04:05") + " UTC"
pasteData["pasteExpiration"] = paste.GetExpirationTime().Format("2006-01-02 @ 15:04:05") + " UTC"
pasteData["pasteLanguage"] = paste.Language
if paste.Private {
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteType}", "<span class='has-text-danger'>Private</span>", 1)
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteTs}", strconv.FormatInt(paste.CreatedAt.Unix(), 10)+"/", 1)
pasteData["pasteType"] = "<span class='has-text-danger'>Private</span>"
pasteData["pasteTs"] = strconv.FormatInt(paste.CreatedAt.Unix(), 10) + "/"
} else {
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteType}", "<span class='has-text-success'>Public</span>", 1)
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteTs}", "", 1)
pasteData["pasteType"] = "<span class='has-text-success'>Public</span>"
pasteData["pasteTs"] = ""
}
// Highlight.
@ -164,26 +155,16 @@ func pasteGET(ec echo.Context) error {
if err4 != nil {
c.Logger.Error().Msgf("Failed to format paste data: %s", err4.Error())
}
pasteData["pastedata"] = buf.String()
// Escape paste data.
//pasteData := html.EscapeString(buf.String())
pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pastedata}", buf.String(), 1)
// Get template and format it.
pasteHTML := templater.GetTemplate(ec, "paste.html", pasteData)
return ec.HTML(http.StatusOK, string(pasteHTMLAsString))
return ec.HTML(http.StatusOK, pasteHTML)
}
// GET for "/paste/PASTE_ID/TIMESTAMP/verify" - a password verify page.
func pastePasswordedVerifyGet(ec echo.Context) error {
verifyHTMLRaw, err := static.ReadFile("passworded_paste_verify.html")
if err != nil {
return ec.String(http.StatusNotFound, "passworded_paste_verify.html wasn't found!")
}
errhtml, err := static.ReadFile("error.html")
if err != nil {
return ec.String(http.StatusNotFound, "error.html wasn't found!")
}
pasteIDRaw := ec.Param("id")
timestampRaw := ec.Param("timestamp")
// We already get numbers from string, so we will not check strconv.Atoi()
@ -194,8 +175,8 @@ func pastePasswordedVerifyGet(ec echo.Context) error {
paste, err1 := GetByID(pasteID)
if err1 != nil {
c.Logger.Error().Msgf("Failed to get paste #%d: %s", pasteID, err1.Error())
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Paste #"+strconv.Itoa(pasteID)+" not found", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Paste #"+pasteIDRaw+" not found")
return ec.HTML(http.StatusBadRequest, errtpl)
}
// Check for auth cookie. If present - redirect to paste.
@ -215,19 +196,18 @@ func pastePasswordedVerifyGet(ec echo.Context) error {
c.Logger.Debug().Msg("Invalid cookie, showing auth page")
}
verifyHTML := strings.Replace(string(verifyHTMLRaw), "{pasteID}", strconv.Itoa(pasteID), -1)
verifyHTML = strings.Replace(verifyHTML, "{pasteTimestamp}", timestampRaw, 1)
// HTML data.
htmlData := make(map[string]string)
htmlData["pasteID"] = strconv.Itoa(pasteID)
htmlData["pasteTimestamp"] = timestampRaw
verifyHTML := templater.GetTemplate(ec, "passworded_paste_verify.html", htmlData)
return ec.HTML(http.StatusOK, verifyHTML)
}
// POST for "/paste/PASTE_ID/TIMESTAMP/verify" - a password verify page.
func pastePasswordedVerifyPost(ec echo.Context) error {
errhtml, err := static.ReadFile("error.html")
if err != nil {
return ec.String(http.StatusNotFound, "error.html wasn't found!")
}
pasteIDRaw := ec.Param("id")
timestampRaw := ec.Param("timestamp")
// We already get numbers from string, so we will not check strconv.Atoi()
@ -239,14 +219,15 @@ func pastePasswordedVerifyPost(ec echo.Context) error {
paste, err1 := GetByID(pasteID)
if err1 != nil {
c.Logger.Error().Msgf("Failed to get paste #%d: %s", pasteID, err1.Error())
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Paste #"+strconv.Itoa(pasteID)+" not found", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Paste #"+strconv.Itoa(pasteID)+" not found")
return ec.HTML(http.StatusBadRequest, errtpl)
}
params, err2 := ec.FormParams()
if err2 != nil {
c.Logger.Debug().Msg("No form parameters passed")
return ec.HTML(http.StatusBadRequest, string(errhtml))
errtpl := templater.GetErrorTemplate(ec, "Paste #"+strconv.Itoa(pasteID)+" not found")
return ec.HTML(http.StatusBadRequest, errtpl)
}
if paste.VerifyPassword(params["paste-password"][0]) {
@ -261,43 +242,38 @@ func pastePasswordedVerifyPost(ec echo.Context) error {
return ec.Redirect(http.StatusFound, "/paste/"+strconv.Itoa(pasteID)+"/"+timestampRaw)
}
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Invalid password. Please, try again.", 1)
return ec.HTML(http.StatusBadRequest, string(errhtmlAsString))
errtpl := templater.GetErrorTemplate(ec, "Invalid password. Please, try again.")
return ec.HTML(http.StatusBadRequest, string(errtpl))
}
// POST for "/paste/" which will create new paste and redirect to
// "/pastes/CREATED_PASTE_ID".
func pastePOST(ec echo.Context) error {
errhtml, err := static.ReadFile("error.html")
if err != nil {
return ec.String(http.StatusNotFound, "error.html wasn't found!")
}
params, err := ec.FormParams()
if err != nil {
c.Logger.Debug().Msg("No form parameters passed")
return ec.HTML(http.StatusBadRequest, string(errhtml))
errtpl := templater.GetErrorTemplate(ec, "Cannot create empty paste")
return ec.HTML(http.StatusBadRequest, errtpl)
}
c.Logger.Debug().Msgf("Received parameters: %+v", params)
// Do nothing if paste contents is empty.
if len(params["paste-contents"][0]) == 0 {
c.Logger.Debug().Msg("Empty paste submitted, ignoring")
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Empty pastes aren't allowed.", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Empty pastes aren't allowed.")
return ec.HTML(http.StatusBadRequest, errtpl)
}
if !strings.ContainsAny(params["paste-keep-for"][0], "Mmhd") {
c.Logger.Debug().Msgf("'Keep paste for' field have invalid value: %s", params["paste-keep-for"][0])
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).")
return ec.HTML(http.StatusBadRequest, errtpl)
}
// Verify captcha.
if !captcha.Verify(params["paste-captcha-id"][0], params["paste-captcha-solution"][0]) {
c.Logger.Debug().Msgf("Invalid captcha solution for captcha ID '%s': %s", params["paste-captcha-id"][0], params["paste-captcha-solution"][0])
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Invalid captcha solution.", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Invalid captcha solution.")
return ec.HTML(http.StatusBadRequest, errtpl)
}
paste := &Paste{
@ -319,8 +295,8 @@ func pastePOST(ec echo.Context) error {
keepFor, err1 := strconv.Atoi(keepForRaw)
if err1 != nil {
c.Logger.Debug().Msgf("Failed to parse 'Keep for' integer: %s", err1.Error())
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).")
return ec.HTML(http.StatusBadRequest, errtpl)
}
paste.KeepFor = keepFor
@ -342,19 +318,19 @@ func pastePOST(ec echo.Context) error {
paste.Private = false
privateCheckbox, privateCheckboxFound := params["paste-private"]
pastePassword, pastePasswordFound := params["paste-password"]
if privateCheckboxFound && privateCheckbox[0] == "on" || pastePasswordFound && len(pastePassword[0]) != 0 {
if privateCheckboxFound && privateCheckbox[0] == "on" || pastePasswordFound && pastePassword[0] != "" {
paste.Private = true
}
if len(pastePassword) != 0 {
if pastePassword[0] != "" {
paste.CreatePassword(pastePassword[0])
}
id, err2 := Save(paste)
if err2 != nil {
c.Logger.Debug().Msgf("Failed to save paste: %s", err2.Error())
errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Failed to save paste. Please, try again later.", 1)
return ec.HTML(http.StatusBadRequest, errhtmlAsString)
errtpl := templater.GetErrorTemplate(ec, "Failed to save paste. Please, try again later.")
return ec.HTML(http.StatusBadRequest, errtpl)
}
newPasteIDAsString := strconv.FormatInt(id, 10)
@ -415,16 +391,6 @@ func pasteRawGET(ec echo.Context) error {
// GET for "/pastes/", a list of publicly available pastes.
func pastesGET(ec echo.Context) error {
pasteListHTML, err1 := static.ReadFile("pastelist_list.html")
if err1 != nil {
return ec.String(http.StatusNotFound, "pastelist_list.html wasn't found!")
}
pasteElementHTML, err2 := static.ReadFile("pastelist_paste.html")
if err2 != nil {
return ec.String(http.StatusNotFound, "pastelist_paste.html wasn't found!")
}
pageFromParamRaw := ec.Param("page")
var page = 1
if pageFromParamRaw != "" {
@ -443,16 +409,17 @@ func pastesGET(ec echo.Context) error {
// Show "No pastes to show" on any error for now.
if err3 != nil {
c.Logger.Error().Msgf("Failed to get pastes list from database: %s", err3.Error())
pasteListHTMLAsString := strings.Replace(string(pasteListHTML), "{pastes}", pastesString, 1)
return ec.HTML(http.StatusOK, string(pasteListHTMLAsString))
noPastesToShowTpl := templater.GetErrorTemplate(ec, "No pastes to show.")
return ec.HTML(http.StatusOK, noPastesToShowTpl)
}
if len(pastes) > 0 {
pastesString = ""
for i := range pastes {
pasteString := strings.Replace(string(pasteElementHTML), "{pasteID}", strconv.Itoa(pastes[i].ID), 2)
pasteString = strings.Replace(pasteString, "{pasteTitle}", pastes[i].Title, 1)
pasteString = strings.Replace(pasteString, "{pasteDate}", pastes[i].CreatedAt.Format("2006-01-02 @ 15:04:05"), 1)
pasteDataMap := make(map[string]string)
pasteDataMap["pasteID"] = strconv.Itoa(pastes[i].ID)
pasteDataMap["pasteTitle"] = pastes[i].Title
pasteDataMap["pasteDate"] = pastes[i].CreatedAt.Format("2006-01-02 @ 15:04:05") + " UTC"
// Get max 4 lines of each paste.
pasteDataSplitted := strings.Split(pastes[i].Data, "\n")
@ -462,18 +429,20 @@ func pastesGET(ec echo.Context) error {
} else {
pasteData = strings.Join(pasteDataSplitted[0:4], "\n")
}
pasteString = strings.Replace(pasteString, "{pasteData}", pasteData, 1)
pastesString += pasteString
pasteDataMap["pasteData"] = pasteData
pasteTpl := templater.GetRawTemplate(ec, "pastelist_paste.html", pasteDataMap)
pastesString += pasteTpl
}
}
pasteListHTMLAsString := strings.Replace(string(pasteListHTML), "{pastes}", pastesString, 1)
// Pagination.
pages := GetPastesPages()
c.Logger.Debug().Msgf("Total pages: %d, current: %d", pages, page)
paginationHTML := pagination.CreateHTML(page, pages, "/pastes/")
pasteListHTMLAsString = strings.Replace(pasteListHTMLAsString, "{pagination}", paginationHTML, -1)
return ec.HTML(http.StatusOK, string(pasteListHTMLAsString))
pasteListTpl := templater.GetTemplate(ec, "pastelist_list.html", map[string]string{"pastes": pastesString, "pagination": paginationHTML})
return ec.HTML(http.StatusOK, string(pasteListTpl))
}

124
templater/exported.go Normal file
View File

@ -0,0 +1,124 @@
// Fast Paste Bin - uberfast and easy-to-use pastebin.
//
// Copyright (c) 2018, Stanislav N. aka pztrn and Fast Paste Bin
// developers.
//
// 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.
package templater
import (
// stdlib
"net/http"
"strings"
// local
"github.com/pztrn/fastpastebin/api/http/static"
"github.com/pztrn/fastpastebin/context"
// other
"github.com/labstack/echo"
)
var (
c *context.Context
)
// GetErrorTemplate returns formatted error template.
// If error.html wasn't found - it will return "error.html not found"
// message as simple string.
func GetErrorTemplate(ec echo.Context, errorText string) string {
// Getting main error template.
mainhtml := GetTemplate(ec, "error.html", map[string]string{"error": errorText})
return mainhtml
}
// GetRawTemplate returns only raw template data.
func GetRawTemplate(ec echo.Context, templateName string, data map[string]string) string {
// Getting main template.
tplRaw, err := static.ReadFile(templateName)
if err != nil {
ec.String(http.StatusBadRequest, templateName+" not found.")
return ""
}
tpl := string(tplRaw)
// Replace placeholders with data from data map.
for placeholder, value := range data {
tpl = strings.Replace(tpl, "{"+placeholder+"}", value, -1)
}
return tpl
}
// GetTemplate returns formatted template that can be outputted to client.
func GetTemplate(ec echo.Context, name string, data map[string]string) string {
c.Logger.Debug().Msgf("Requested template '%s'", name)
// Getting main template.
mainhtml, err := static.ReadFile("main.html")
if err != nil {
ec.String(http.StatusBadRequest, "main.html not found.")
return ""
}
// Getting navigation.
navhtml, err1 := static.ReadFile("navigation.html")
if err1 != nil {
ec.String(http.StatusBadRequest, "navigation.html not found.")
return ""
}
// Getting footer.
footerhtml, err2 := static.ReadFile("footer.html")
if err2 != nil {
ec.String(http.StatusBadRequest, "footer.html not found.")
return ""
}
// Format main template.
tpl := strings.Replace(string(mainhtml), "{navigation}", string(navhtml), 1)
tpl = strings.Replace(tpl, "{footer}", string(footerhtml), 1)
// Version.
tpl = strings.Replace(tpl, "{version}", context.Version, 1)
// Get requested template.
reqhtml, err3 := static.ReadFile(name)
if err3 != nil {
ec.String(http.StatusBadRequest, name+" not found.")
return ""
}
// Replace documentBody.
tpl = strings.Replace(tpl, "{documentBody}", string(reqhtml), 1)
// Replace placeholders with data from data map.
for placeholder, value := range data {
tpl = strings.Replace(tpl, "{"+placeholder+"}", value, -1)
}
return tpl
}
// Initialize initializes package.
func Initialize(cc *context.Context) {
c = cc
}