summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelonai <einebeere@gmail.com>2021-07-26 21:52:58 +0200
committerMelonai <einebeere@gmail.com>2021-07-26 21:53:36 +0200
commit0ac82c133b78a14239beb9034380c44d95d4bad3 (patch)
tree3ba65b4e3e5ceafaf2180ea697cc7794a07da669
parent7819a23171145e8a626e8357e88446817c8785dc (diff)
downloadportgate-0ac82c133b78a14239beb9034380c44d95d4bad3.tar.zst
portgate-0ac82c133b78a14239beb9034380c44d95d4bad3.zip
Portgate pages and templates
-rw-r--r--assets/templates/_base.template.html11
-rw-r--r--assets/templates/authenticate.template.html3
-rw-r--r--assets/templates/information.template.html3
-rw-r--r--cmd/portgate.go5
-rw-r--r--handlers/handler.go54
-rw-r--r--handlers/portgate.go45
-rw-r--r--path.go10
-rw-r--r--templates.go55
8 files changed, 164 insertions, 22 deletions
diff --git a/assets/templates/_base.template.html b/assets/templates/_base.template.html
new file mode 100644
index 0000000..2ed25d1
--- /dev/null
+++ b/assets/templates/_base.template.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Portgate</title>
+</head>
+<body>
+ <h2>Portgate</h2>
+ {{template "content"}}
+</body>
+</html> \ No newline at end of file
diff --git a/assets/templates/authenticate.template.html b/assets/templates/authenticate.template.html
new file mode 100644
index 0000000..21f31e4
--- /dev/null
+++ b/assets/templates/authenticate.template.html
@@ -0,0 +1,3 @@
+{{define "content"}}
+<h1>This is the authentication page...</h1>
+{{end}} \ No newline at end of file
diff --git a/assets/templates/information.template.html b/assets/templates/information.template.html
new file mode 100644
index 0000000..e87885c
--- /dev/null
+++ b/assets/templates/information.template.html
@@ -0,0 +1,3 @@
+{{define "content"}}
+<h1>This is the information page...</h1>
+{{end}} \ No newline at end of file
diff --git a/cmd/portgate.go b/cmd/portgate.go
index afa756a..2bc0693 100644
--- a/cmd/portgate.go
+++ b/cmd/portgate.go
@@ -17,8 +17,11 @@ func main() {
log.Fatal("Failed to get Portgate config.")
}
+ // Load and Parse all Portgate templates
+ templates, _ := portgate.LoadAllTemplates()
+
// Create handler for requests
- handler := handlers.NewRequestHandler(&config)
+ handler := handlers.NewRequestHandler(&config, templates)
// Start to listen to the outside world.
log.Print("Listening for requests on port 8080.")
diff --git a/handlers/handler.go b/handlers/handler.go
index 6484c61..56801a3 100644
--- a/handlers/handler.go
+++ b/handlers/handler.go
@@ -5,6 +5,7 @@ import (
"github.com/valyala/fasthttp"
"net/http"
"portgate"
+ "strings"
)
// RequestHandler keeps data relevant to the request handlers.
@@ -13,12 +14,29 @@ type RequestHandler struct {
config *portgate.Config
// HTTP Client for requesting resources from the destination host.
client fasthttp.Client
+ // Handler for static Portgate assets.
+ staticHandler fasthttp.RequestHandler
+ // Templates for Portgate pages.
+ templates portgate.Templates
}
-func NewRequestHandler(config *portgate.Config) RequestHandler {
+// NewRequestHandler creates a new RequestHandler instance.
+func NewRequestHandler(config *portgate.Config, templates portgate.Templates) RequestHandler {
+ // Serves static Portgate files when called.
+ fs := fasthttp.FS{
+ Root: "./assets/static/",
+ PathRewrite: func(ctx *fasthttp.RequestCtx) []byte {
+ return []byte(strings.TrimPrefix(string(ctx.Path()), "/_portgate/static"))
+ },
+ PathNotFound: nil,
+ }
+ staticHandler := fs.NewRequestHandler()
+
return RequestHandler{
- config: config,
- client: fasthttp.Client{},
+ config: config,
+ client: fasthttp.Client{},
+ staticHandler: staticHandler,
+ templates: templates,
}
}
@@ -26,24 +44,26 @@ func NewRequestHandler(config *portgate.Config) RequestHandler {
func (h *RequestHandler) HandleRequest(ctx *fasthttp.RequestCtx) {
path := portgate.ParsePath(string(ctx.Path()))
+ if path.IsPortgatePath() {
+ h.handlePortgateRequest(ctx, path)
+ return
+ }
+
if path.DestinationIdentifier == -1 {
- // We were not given a port.
+ // We were not given a destination.
- if path.ResourcePath == "/_portgate" {
- h.handlePortgateRequest(ctx)
+ // Try to grab actual destination from Referer header.
+ // This can help us if the user followed an absolute link on a proxied page.
+ refererPath, err := portgate.ParsePathFromReferer(path, string(ctx.Request.Header.Referer()))
+ if err != nil || refererPath.DestinationIdentifier == -1 {
+ // The referer path also has no destination
+ h.handleUnknownRequest(ctx)
} else {
- // Try to grab actual destination from Referer header.
- refererPath, err := portgate.ParsePathFromReferer(path, string(ctx.Request.Header.Referer()))
- if err != nil || refererPath.DestinationIdentifier == -1 {
- // The referer path also has no destination
- h.handleUnknownRequest(ctx)
- } else {
- // We found the destination from the referer path, so we
- // redirect the user to the Portgate URL they should've requested.
+ // We found the destination from the referer path, so we
+ // redirect the user to the Portgate URL they should've requested.
- portgateUrl := fmt.Sprintf("/%d%s", refererPath.DestinationIdentifier, refererPath.ResourcePath)
- ctx.Redirect(portgateUrl, http.StatusTemporaryRedirect)
- }
+ portgateUrl := fmt.Sprintf("/%d%s", refererPath.DestinationIdentifier, refererPath.ResourcePath)
+ ctx.Redirect(portgateUrl, http.StatusTemporaryRedirect)
}
} else {
// We were given a port, so we have to pass the request through to the destination host.
diff --git a/handlers/portgate.go b/handlers/portgate.go
index 9d4f3ef..1cd9bb8 100644
--- a/handlers/portgate.go
+++ b/handlers/portgate.go
@@ -1,10 +1,47 @@
package handlers
-import "github.com/valyala/fasthttp"
+import (
+ "github.com/valyala/fasthttp"
+ "net/http"
+ "portgate"
+)
// handlePortgateRequest handles all Portgate specific request for either showing Portgate
// specific pages or handling creation of authorization tokens.
-func (h *RequestHandler) handlePortgateRequest(ctx *fasthttp.RequestCtx) {
- // TODO: Implement authentication, authorization
- _, _ = ctx.WriteString("Portgate request.")
+func (h *RequestHandler) handlePortgateRequest(ctx *fasthttp.RequestCtx, path portgate.Path) {
+ if path.IsPortgateStaticPath() {
+ h.staticHandler(ctx)
+ } else {
+ // TODO: Implement authentication, authorization
+ h.handlePortgateIndexRequest(ctx)
+ }
+}
+
+// handlePortgateIndexRequest delegates requests directed at /_portgate.
+func (h *RequestHandler) handlePortgateIndexRequest(ctx *fasthttp.RequestCtx) {
+ switch string(ctx.Method()) {
+ case "GET":
+ // If we received a GET request, the user wants to see either the login page,
+ // or an info page if they're already authenticated.
+ h.handlePortgatePageRequest(ctx)
+ case "POST":
+ // If we received a POST request, the user wants to get authorization to Portgate.
+ h.handleAuthenticateRequest(ctx)
+ }
+}
+
+// handlePortgatePageRequest renders the Portgate page with either the authentication page or
+// a basic information page.
+func (h *RequestHandler) handlePortgatePageRequest(ctx *fasthttp.RequestCtx) {
+ // We render the page template and pass it to the user.
+ ctx.Response.Header.SetContentType("text/html")
+ err := h.templates.ExecuteTemplate(ctx, "authenticate.template.html", nil)
+ if err != nil {
+ ctx.SetStatusCode(http.StatusInternalServerError)
+ _, _ = ctx.WriteString("An error occurred.")
+ }
+}
+
+func (h *RequestHandler) handleAuthenticateRequest(ctx *fasthttp.RequestCtx) {
+ // TODO
}
diff --git a/path.go b/path.go
index 3aa7816..82a8353 100644
--- a/path.go
+++ b/path.go
@@ -68,3 +68,13 @@ func ParsePathFromReferer(p Path, r string) (Path, error) {
ResourcePath: p.ResourcePath,
}, nil
}
+
+// IsPortgatePath returns whether the Path goes to Portgate.
+func (p *Path) IsPortgatePath() bool {
+ return p.DestinationIdentifier == -1 && strings.HasPrefix(p.ResourcePath, "/_portgate")
+}
+
+// IsPortgateStaticPath returns whether the Path goes to the Portgate static files.
+func (p *Path) IsPortgateStaticPath() bool {
+ return p.DestinationIdentifier == -1 && strings.HasPrefix(p.ResourcePath, "/_portgate/static")
+}
diff --git a/templates.go b/templates.go
new file mode 100644
index 0000000..25cb480
--- /dev/null
+++ b/templates.go
@@ -0,0 +1,55 @@
+package portgate
+
+import (
+ "errors"
+ "html/template"
+ "io"
+ "io/fs"
+ "path/filepath"
+ "strings"
+)
+
+// Templates houses all the Portgate page templates and can render them with correct styling.
+type Templates struct {
+ templateMap map[string]*template.Template
+}
+
+// LoadAllTemplates loads all Portgate templates from ./assets/templates/ and bundles them
+// into a single Templates instance.
+func LoadAllTemplates() (Templates, error) {
+ templateMap := make(map[string]*template.Template)
+
+ // We walk through every file in the templates folder.
+ err := filepath.Walk("./assets/templates", func(path string, info fs.FileInfo, err error) error {
+ // We only care about files which are actual templates and are not of special use (like "_base")
+ if !strings.HasPrefix(info.Name(), "_") && strings.HasSuffix(path, ".template.html") {
+ // We bundle the templates together with the base template so that we can render them together later.
+ t, err := template.ParseFiles("./assets/templates/_base.template.html", path)
+ if err == nil {
+ // We keep the parsed template in the templateMap by it's filename.
+ templateMap[info.Name()] = t
+ }
+ }
+
+ return err
+ })
+
+ if err != nil {
+ return Templates{}, err
+ }
+
+ return Templates{
+ templateMap: templateMap,
+ }, nil
+}
+
+// ExecuteTemplate executes a single template with the given name and data and writes it to the given
+// io.Writer, which is usually fasthttp.RequestCtx.
+func (templates *Templates) ExecuteTemplate(w io.Writer, name string, data interface{}) error {
+ t := templates.templateMap[name]
+ if t == nil {
+ return errors.New("Unknown template name: " + name)
+ }
+
+ return t.ExecuteTemplate(w, "_base.template.html", data)
+}