diff --git a/config/config.go b/config/config.go index 4a269fc..283622a 100644 --- a/config/config.go +++ b/config/config.go @@ -2,6 +2,7 @@ package config import ( "flag" + "github.com/GeertJohan/go.rice" "gopkg.in/yaml.v2" "io/ioutil" "os" @@ -25,6 +26,8 @@ type Config struct { const ( CaptchaRecaptcha = "recaptcha" + CaptchaInternal = "internal" + CaptchaHybrid = "hybrid" CaptchaDisabled = "disabled" ) diff --git a/http/admin/handler.go b/http/admin/handler.go index 763e4b4..a8e630a 100644 --- a/http/admin/handler.go +++ b/http/admin/handler.go @@ -11,24 +11,18 @@ import ( "time" ) -var riceConf = rice.Config{ - LocateOrder: []rice.LocateMethod{ - rice.LocateWorkingDirectory, - rice.LocateEmbedded, - rice.LocateAppended, - }, -} - -var box = riceConf.MustFindBox("http/admin/res/") - var ( panelTmpl = template.New("admin/panel") loginTmpl = template.New("admin/login") statusTmpl = template.New("admin/status") ) -func init() { +func LoadTemplates() error { var err error + box, err := rice.FindBox("res/") + if err != nil { + panic(err) + } panelTmpl, err = panelTmpl.Parse(box.MustString("panel.html")) if err != nil { panic(err) diff --git a/http/admin/rice-box.go b/http/admin/rice-box.go new file mode 100644 index 0000000..b3f834b --- /dev/null +++ b/http/admin/rice-box.go @@ -0,0 +1,55 @@ +package admin + +import ( + "github.com/GeertJohan/go.rice/embedded" + "time" +) + +func init() { + + // define files + file2 := &embedded.EmbeddedFile{ + Filename: `index.html`, + FileModTime: time.Unix(1489315188, 0), + Content: string("\n\n\n \n \n {{.Config.Site.Title}} Admin Login\n \n \n \n\n\n
\n
\n \n
\n \n
\n
\n \n
\n
\n \n \n
\n \n
\n\n"), + } + file3 := &embedded.EmbeddedFile{ + Filename: `panel.html`, + FileModTime: time.Unix(1489566364, 0), + Content: string("\n\n\n \n \n {{.Config.Site.Title}} Admin Panel\n \n \n \n\n\n
\n Welcome {{.Admin.Id}}
\n
\n \n \n \n
\n

\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Action\n \n New Board\n \n
\n Short Name\n \n \n
\n Long Name\n \n \n
\n \n \n
\n
\n
\n

\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Action\n \n New Administrator\n \n
\n ID\n \n \n
\n Password\n \n \n
\n \n \n
\n
\n
\n

\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Action\n \n Delete Administrator\n \n
\n ID\n \n \n
\n \n \n
\n
\n
\n

\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n
\n Action\n \n Cleanup Database\n \n
\n \n \n
\n
\n
\n

\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Action\n \n Set Board Rules\n \n
\n Board Name (Short)\n \n \n
\n Rules\n \n \n \n
\n \n \n
\n
\n
\n

\n\n"), + } + file4 := &embedded.EmbeddedFile{ + Filename: `status.html`, + FileModTime: time.Unix(1489525499, 0), + Content: string("\n\n\n \n \n {{.Config.Site.Title}} Status\n \n \n \n\n\n
\n

Runtime Statistics

\n
\n
\n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Start Time\n \n {{.Uptime.human}}\n
\n Uptime (Precise)\n \n {{ .Uptime.hours | printf \"%.4f\"}} hours
\n {{ .Uptime.seconds | printf \"%.4f\"}} seconds\n
\n Num. CPU\n \n {{.GC.numcpu}}\n
\n Num. GoRoutines\n \n {{.GC.numgor}}\n
\n Go Version
\n Arch/OS/Compiler\n
\n {{.GC.version}}
\n {{.GC.arch}} / {{.GC.os}} / {{.GC.compiler}}\n
\n Current Allocs\n \n {{.GC.memory.alloc}}\n
\n Cumulative Allocs\n \n {{.GC.memory.calloc}}\n
\n Used Sys Memory\n \n {{.GC.memory.sysmem}}\n
\n Pointer Lookups\n \n {{.GC.memory.lookups}}\n
\n MAllocs\n \n {{.GC.memory.mallocs}}\n
\n MFrees\n \n {{.GC.memory.frees}}\n
\n Live Objects\n \n {{.GC.memory.liveobj}}\n
\n Heap Allocated\n \n {{.GC.memory.heapalloc}}\n
\n Heap Released\n \n {{.GC.memory.heaprelease}}\n
\n GC Metadata\n \n {{.GC.memory.gcmeta}}\n
\n GC Pause\n \n {{.GC.memory.pause}}\n
\n GC Invokations\n \n {{.GC.memory.gctimes}}\n
\n GC Forced\n \n {{.GC.memory.fgctimes}}\n
\n GC CPU Usage\n \n {{.GC.memory.cpufrac}}\n
\n
\n
\n

\n\n"), + } + + // define dirs + dir1 := &embedded.EmbeddedDir{ + Filename: ``, + DirModTime: time.Unix(1489566364, 0), + ChildFiles: []*embedded.EmbeddedFile{ + file2, // index.html + file3, // panel.html + file4, // status.html + + }, + } + + // link ChildDirs + dir1.ChildDirs = []*embedded.EmbeddedDir{} + + // register embeddedBox + embedded.RegisterEmbeddedBox(`res/`, &embedded.EmbeddedBox{ + Name: `res/`, + Time: time.Unix(1489566364, 0), + Dirs: map[string]*embedded.EmbeddedDir{ + "": dir1, + }, + Files: map[string]*embedded.EmbeddedFile{ + "index.html": file2, + "panel.html": file3, + "status.html": file4, + }, + }) +} diff --git a/http/board/handler.go b/http/board/handler.go index 71b5c2c..5f0fd18 100644 --- a/http/board/handler.go +++ b/http/board/handler.go @@ -15,16 +15,6 @@ import ( "time" ) -var riceConf = rice.Config{ - LocateOrder: []rice.LocateMethod{ - rice.LocateWorkingDirectory, - rice.LocateEmbedded, - rice.LocateAppended, - }, -} - -var box = riceConf.MustFindBox("http/board/res/") - var ( tmpls = template.New("base") @@ -57,24 +47,27 @@ var ( } ) -func init() { - var err error +func LoadTemplates() error { + box, err := rice.FindBox("res/") + if err != nil { + return err + } tmpls = tmpls.Funcs(hdlFMap) tmpls, err = tmpls.New("thread/postlists").Parse(box.MustString("thread.tmpl.html")) if err != nil { - panic(err) + return err } _, err = tmpls.New("board/dir").Parse(box.MustString("dir.html")) if err != nil { - panic(err) + return err } _, err = tmpls.New("board/board").Parse(box.MustString("board.html")) if err != nil { - panic(err) + return err } _, err = tmpls.New("board/thread").Parse(box.MustString("thread.html")) if err != nil { - panic(err) + return err } } diff --git a/http/board/rice-box.go b/http/board/rice-box.go new file mode 100644 index 0000000..4d3d51b --- /dev/null +++ b/http/board/rice-box.go @@ -0,0 +1,62 @@ +package board + +import ( + "github.com/GeertJohan/go.rice/embedded" + "time" +) + +func init() { + + // define files + file2 := &embedded.EmbeddedFile{ + Filename: `board.html`, + FileModTime: time.Unix(1489412682, 0), + Content: string("\n\n\n \n \n {{.Config.Site.Title}} - /{{.Board.ShortName}}/\n \n \n\n\n
\n

/{{.Board.ShortName}}/

\n

{{.Board.LongName}}

\n
\n{{ $boardlink := .Board.ShortName }}\n{{ if .Session }}\n{{ if eq (.Session.CAttr \"mode\") \"admin\" }}\nLogged in as Admin\n{{ end }}\n{{ if eq (.Session.CAttr \"mode\") \"mod\" }}\nLogged in as Mod for {{ .Session.CAttr \"board\" }}\n{{ end }}\n{{ end }}\n
\n{{ template \"thread/post\" . }}\n
\n {{ $board := .Board }}\n {{ $csrf := .CSRFToken }}\n {{ $session := .Session }}\n {{range .Threads}}\n {{ template \"thread/postlists\" dict \"Thread\" . \"Board\" $board \"CSRFToken\" $csrf \"Session\" $session }}\n {{end}}\n
\n\n"), + } + file3 := &embedded.EmbeddedFile{ + Filename: `dir.html`, + FileModTime: time.Unix(1489315156, 0), + Content: string("\n\n\n \n \n {{.Config.Site.Title}} Boards\n \n \n\n\n
\n

{{.Config.Site.Title}}

\n

{{.Config.Site.Description}}

\n
\n
\n
\n

Boards

\n
\n
\n \n
\n
\n\n"), + } + file4 := &embedded.EmbeddedFile{ + Filename: `thread.html`, + FileModTime: time.Unix(1489412660, 0), + Content: string("\n\n\n \n \n {{.Config.Site.Title}} - /{{.Board.ShortName}}/\n \n \n\n\n
\n

/{{.Board.ShortName}}/

\n

{{.Board.LongName}}

\n

{{.Thread.ID}}

\n
\n{{ $boardlink := .Board.ShortName }}\n
\n{{ template \"thread/post\" . }}\n{{ template \"thread/postlists\" . }}\n\n"), + } + file5 := &embedded.EmbeddedFile{ + Filename: `thread.tmpl.html`, + FileModTime: time.Unix(1489566591, 0), + Content: string("{{ define \"thread/post\" }}\n
\n {{ if .Thread }}\n
\n {{ else }}\n \n {{ end }}\n \n \n {{ if .PreviousError }}\n \n \n \n \n {{ end }}\n \n \n \n \n \n \n \n \n \n \n \n \n {{ if ne .Config.Captcha.Mode \"disabled\" }}\n \n \n \n \n {{ end }}\n {{ if (isModSession .Session) }}\n \n \n \n \n {{ end }}\n \n \n \n \n {{ if .Board.Metadata.rules }}\n \n \n \n \n {{ end }}\n \n
\n Error\n \n {{.PreviousError}}\n
\n TripCode\n \n \n \n
\n Comment\n \n \n
\n Image File\n \n \n
\n Captcha\n \n {{ $captchaId := makeCaptcha }}\n \"Captcha\n \n
\n \n \n
\n Mod Post\n \n \n {{ if (isAdminSession .Session) }}\n \n {{ end }}\n
\n\n \n \n
\n Rules\n \n {{ renderText .Board.Metadata.rules }}\n
\n
\n
\n
\n{{ end }}\n\n{{ define \"thread/reply\" }}\n \n {{dateFromID .Reply.ID | formatDate}}\n {{ if .Session }}\n {{ if eq (.Session.CAttr \"mode\") \"admin\" }}\n
\n \n \n \n \n \n \n {{ end }}\n {{ end }}\n \n {{ if not .Reply.Metadata.spamscore }}\n {{ $score := (rateSpam .Reply.Text) }}\n {{printf \"[SpamScore: %f]\" $score }}\n {{printf \"[Captcha: %.3f%%]\" (percentFloat (captchaProb $score)) }}\n {{printf \"[OLD]\"}}\n {{ else }}\n {{ printf \"[SpamScore: %s]\" .Reply.Metadata.spamscore }}\n {{ printf \"[Captcha: %s %%]\" .Reply.Metadata.captchaprob }}\n {{ end }}\n \n \n No.{{.Reply.ID}}\n \n {{ if .Reply.Thumbnail }}\n
\n \n \n \n {{ end }}\n {{ if .Reply.Metadata.deleted }}\n
\n {{ renderText .Reply.Text }}\n
\n {{ else }}\n
\n {{ renderText .Reply.Text}}\n
\n {{ end }}\n{{ end }}\n\n{{ define \"thread/main\" }}\n
\n {{ $boardlink := .Board.ShortName }}\n {{ $threadrid := .Thread.GetReply.ID }}\n {{ $threadid := .Thread.ID }}\n {{ $csrf := .CSRFToken }}\n {{ $session := .Session }}\n {{ with .Thread }}\n {{ with .GetReply }}\n {{ with dict \"Reply\" . \"Boardlink\" $boardlink \"CSRF\" $csrf \"ThreadID\" $threadid \"Session\" $session }}\n {{ template \"thread/reply\" . }}\n {{ end }}\n {{ end }}\n {{range .GetReplies}}\n {{ if ne .ID $threadrid }}\n \n \n
>>\n {{ with dict \"Reply\" . \"Boardlink\" $boardlink \"CSRF\" $csrf \"ThreadID\" $threadid \"Session\" $session }}\n {{ template \"thread/reply\" . }}\n {{ end }}\n
\n {{end}}\n {{end}}\n {{end}}\n

\n
\n{{ end }}\n\n{{ template \"thread/main\" . }}"), + } + + // define dirs + dir1 := &embedded.EmbeddedDir{ + Filename: ``, + DirModTime: time.Unix(1489566591, 0), + ChildFiles: []*embedded.EmbeddedFile{ + file2, // board.html + file3, // dir.html + file4, // thread.html + file5, // thread.tmpl.html + + }, + } + + // link ChildDirs + dir1.ChildDirs = []*embedded.EmbeddedDir{} + + // register embeddedBox + embedded.RegisterEmbeddedBox(`res/`, &embedded.EmbeddedBox{ + Name: `res/`, + Time: time.Unix(1489566591, 0), + Dirs: map[string]*embedded.EmbeddedDir{ + "": dir1, + }, + Files: map[string]*embedded.EmbeddedFile{ + "board.html": file2, + "dir.html": file3, + "thread.html": file4, + "thread.tmpl.html": file5, + }, + }) +} diff --git a/http/errw/handler.go b/http/errw/handler.go index a1c854d..9c436ee 100644 --- a/http/errw/handler.go +++ b/http/errw/handler.go @@ -9,26 +9,20 @@ import ( "net/http" ) -var riceConf = rice.Config{ - LocateOrder: []rice.LocateMethod{ - rice.LocateWorkingDirectory, - rice.LocateEmbedded, - rice.LocateAppended, - }, -} - -var box = riceConf.MustFindBox("http/errw/res/") - var ( errorTmpl = template.New("errw/error") ) -func init() { - var err error +func LoadTemplates() error { + box, err := rice.FindBox("res/") + if err != nil { + return err + } errorTmpl, err = errorTmpl.Parse(box.MustString("error.html")) if err != nil { - panic(err) + return err } + return nil } type ErrorWithTitle interface { diff --git a/http/errw/rice-box.go b/http/errw/rice-box.go new file mode 100644 index 0000000..dce39e3 --- /dev/null +++ b/http/errw/rice-box.go @@ -0,0 +1,41 @@ +package errw + +import ( + "github.com/GeertJohan/go.rice/embedded" + "time" +) + +func init() { + + // define files + file2 := &embedded.EmbeddedFile{ + Filename: `error.html`, + FileModTime: time.Unix(1489238440, 0), + Content: string("\n\n\n \n \n {{.Config.Site.Title}} Admin Login\n \n\n\n
\n

{{.Error.Title}}


\n

{{.Error.Code}}


\n

{{.Error.Description}}

\n
\n\n"), + } + + // define dirs + dir1 := &embedded.EmbeddedDir{ + Filename: ``, + DirModTime: time.Unix(1489240168, 0), + ChildFiles: []*embedded.EmbeddedFile{ + file2, // error.html + + }, + } + + // link ChildDirs + dir1.ChildDirs = []*embedded.EmbeddedDir{} + + // register embeddedBox + embedded.RegisterEmbeddedBox(`res/`, &embedded.EmbeddedBox{ + Name: `res/`, + Time: time.Unix(1489240168, 0), + Dirs: map[string]*embedded.EmbeddedDir{ + "": dir1, + }, + Files: map[string]*embedded.EmbeddedFile{ + "error.html": file2, + }, + }) +} diff --git a/http/rice-box.go b/http/rice-box.go new file mode 100644 index 0000000..c7f2fb1 --- /dev/null +++ b/http/rice-box.go @@ -0,0 +1,55 @@ +package http + +import ( + "github.com/GeertJohan/go.rice/embedded" + "time" +) + +func init() { + + // define files + file2 := &embedded.EmbeddedFile{ + Filename: `admin.css`, + FileModTime: time.Unix(1489250860, 0), + Content: string("/* CUSTOM CSS */\ndiv.admin.login {\n border: 1px solid black;\n width: 500px;\n margin: auto;\n margin-top: 100px;\n}\n.admin.form.row {\n margin: auto;\n padding: 5px;\n width: 90%;\n height: 22px;\n left: 0;\n right: 0;\n display: flex;\n}\n.admin.form.input {\n font-family: \"monospace\";\n width: 100%;\n height: 100%;\n padding: 2px;\n display: inline;\n}\n.admin.form.input.halfsize {\n width: 50%;\n}"), + } + file3 := &embedded.EmbeddedFile{ + Filename: `custom.css`, + FileModTime: time.Unix(1489426703, 0), + Content: string("h1 {\n font-size: 32px;\n}\n\nh2 {\n font-size: 24px;\n}\n\nh3 {\n font-size: 16px;\n}\n\ndiv {\n display: block;\n margin: 0;\n padding: 0;\n}\n\nblockquote blockquote {\n word-wrap: break-word;\n word-break: break-all;\n white-space: normal;\n padding: 2px;\n margin-bottom: 1em;\n margin-top: 1em;\n margin-left: 40px;\n margin-right: 40px;\n}\n\n\n.delform {\n display: inline;\n margin: 0;\n padding: 0;\n}\n.delform input {\n display: inline;\n}\n\n.deleted {\n color: #707070;\n}\n\n.reply-table {\n display: block;\n}\n\n.reply {\n display: table;\n}"), + } + file4 := &embedded.EmbeddedFile{ + Filename: `style.css`, + FileModTime: time.Unix(1489426859, 0), + Content: string("/* The following CSS is mostly taken from Wakaba, big thanks for the devs there! <3 */\n\nhtml, body {\n background:#FFFFEE;\n color:#800000;\n}\na {\n color:#0000EE;\n}\na:hover {\n color:#DD0000;\n}\n.adminbar {\n text-align:right;\n clear:both;\n float:right;\n}\n.logo {\n clear:both;\n text-align:center;\n font-size:2em;\n color:#800000;\n width:100%;\n}\n.theader {\n background:#E04000;\n text-align:center;\n padding:2px;\n color:#FFFFFF;\n width:100%;\n}\n.postarea {\n}\n.rules {\n font-size:0.7em;\n}\n.postblock {\n background:#EEAA88;\n color:#800000;\n font-weight:800;\n}\n.footer {\n text-align:center;\n font-size:12px;\n font-family:serif;\n}\n.passvalid {\n background:#EEAA88;\n text-align:center;\n width:100%;\n color:#ffffff;\n}\n.dellist {\n font-weight: bold;\n text-align:center;\n}\n.delbuttons {\n text-align:center;\n padding-bottom:4px;\n\n}\n.managehead {\n background:#AAAA66;\n color:#400000;\n padding:0px;\n}\n.postlists {\n background:#FFFFFF;\n width:100%;\n padding:0px;\n color:#800000;\n}\n.row1 {\n background:#EEEECC;\n color:#800000;\n}\n.row2 {\n background:#DDDDAA;\n color:#800000;\n}\n.unkfunc {\n background:inert;\n color:#789922;\n}\n.filesize {\n text-decoration:none;\n}\n.filetitle {\n background:inherit;\n font-size:1.2em;\n color:#CC1105;\n font-weight:800;\n}\n.postername {\n color:#117743;\n font-weight:bold;\n}\n.postertrip {\n color:#228854;\n}\n.oldpost {\n color:#CC1105;\n font-weight:800;\n}\n.omittedposts {\n color:#707070;\n}\n.reply {\n background:#F0E0D6;\n color:#800000;\n}\n.doubledash {\n vertical-align:top;\n clear:both;\n float:left;\n}\n.replytitle {\n font-size: 1.2em;\n color:#CC1105;\n font-weight:800;\n}\n.commentpostername {\n color:#117743;\n font-weight:800;\n}\n.thumbnailmsg {\n font-size: small;\n color:#800000;\n}\n\n\n\n.abbrev {\n color:#707070;\n}\n.highlight {\n background:#F0E0D6;\n color:#800000;\n border: 2px dashed #EEAA88;\n}\n\n/* From pl files */\n\n/* futaba_style.pl */\n\nform { margin-bottom: 0px }\nform .trap { display:none }\n.postarea { text-align: center }\n.postarea table { margin: 0px auto; text-align: left }\n.thumb { border: none; float: left; margin: 2px 20px }\n.nothumb { float: left; background: #eee; border: 2px dashed #aaa; text-align: center; margin: 2px 20px; padding: 1em 0.5em 1em 0.5em; }\n\n.reflink a { color: inherit; text-decoration: none }\n.reply .filesize { margin-left: 20px }\n.userdelete { float: right; text-align: center; white-space: nowrap }\n.replypage .replylink { display: none }"), + } + + // define dirs + dir1 := &embedded.EmbeddedDir{ + Filename: ``, + DirModTime: time.Unix(1489426859, 0), + ChildFiles: []*embedded.EmbeddedFile{ + file2, // admin.css + file3, // custom.css + file4, // style.css + + }, + } + + // link ChildDirs + dir1.ChildDirs = []*embedded.EmbeddedDir{} + + // register embeddedBox + embedded.RegisterEmbeddedBox(`res/`, &embedded.EmbeddedBox{ + Name: `res/`, + Time: time.Unix(1489426859, 0), + Dirs: map[string]*embedded.EmbeddedDir{ + "": dir1, + }, + Files: map[string]*embedded.EmbeddedFile{ + "admin.css": file2, + "custom.css": file3, + "style.css": file4, + }, + }) +} diff --git a/http/server.go b/http/server.go index 37f1888..4cc3d32 100644 --- a/http/server.go +++ b/http/server.go @@ -8,6 +8,7 @@ import ( "go.rls.moe/nyx/config" "go.rls.moe/nyx/http/admin" "go.rls.moe/nyx/http/board" + "go.rls.moe/nyx/http/errw" "go.rls.moe/nyx/http/middle" "net/http" "time" @@ -21,7 +22,20 @@ var riceConf = rice.Config{ }, } -func Start(config *config.Config) { +func Start(config *config.Config) error { + err := admin.LoadTemplates() + if err != nil { + return err + } + err = board.LoadTemplates() + if err != nil { + return err + } + err = errw.LoadTemplates() + if err != nil { + return err + } + r := chi.NewRouter() fmt.Println("Setting up Router") @@ -37,7 +51,7 @@ func Start(config *config.Config) { { mw, err := middle.Database(config) if err != nil { - panic(err) + return err } r.Use(mw) } @@ -45,7 +59,10 @@ func Start(config *config.Config) { r.Route("/admin/", admin.AdminRouter) r.Route("/mod/", admin.ModRouter) { - box := riceConf.MustFindBox("http/res") + box, err := rice.FindBox("res/") + if err != nil { + return err + } atFileServer := http.StripPrefix("/@/", http.FileServer(box.HTTPBox())) r.Mount("/@/", atFileServer) }