micro

module
v0.0.0-...-839d480 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2022 License: BSD-3-Clause

README

micro


A mirco framework (WARNING: work in progress).

Package tree


  • app
  • ctxkey
  • log
    • debug
  • mux
  • orm
  • session

Environment variables


Variable Description
MICRO_DATABASE_URL data source name
MICRO_SMTP_ADDR self-explanatory
MICRO_SECRET_KEY data encryption key (must be 32bits)

Examples


Main
// mysite
package main

import (
	"context"
	"mysite/controllers/about"
	"mysite/controllers/auth/reset"
	"mysite/controllers/auth/signin"
	"mysite/controllers/auth/signout"
	"mysite/controllers/auth/signup"
	"mysite/controllers/dashboard"
	"mysite/controllers/index"
	isAuth "mysite/src/middleware/auth/is"
	mustBeAuth "mysite/src/middleware/auth/must"
	"mysite/src/middleware/cookie"
	createToken "mysite/src/middleware/csrftoken/token"
	vaidateToken "mysite/src/middleware/csrftoken/validate"
	"net/http"
	"net/http/pprof"

	"bitbucket.org/_mikey/micro/app"
	"bitbucket.org/_mikey/micro/log/debug"
	"bitbucket.org/_mikey/micro/mux"
)

func main() {
	debug.Trace.Println(app.New(app.Config{
		Addr: ":8000",
		Handler: mux.NewWithContext(
			context.Background(),
			[]*mux.Route{
				// index --------------------------------------------------
				{
					Path:       "/",
					Method:     "GET",
					Middleware: []func(http.Handler) http.Handler{cookie.M, mustBeAuth.M, createToken.M},
					Handler:    &index.Controller{},
				},
				{
					Path:       "/",
					Method:     "HEAD",
					Handler:    &index.Controller{},
				},
				// about --------------------------------------------------
				{
					Path:       "/about",
					Method:     "GET",
					Middleware: []func(http.Handler) http.Handler{cookie.M, mustBeAuth.M, createToken.M},
					Handler:    &about.Controller{},
				},
				{
					Path:       "/about",
					Method:     "HEAD",
					Handler:    &about.Controller{},
				},
				// dashboard --------------------------------------------------
				{
					Path:       "/dashboard",
					Method:     "GET",
					Middleware: []func(http.Handler) http.Handler{cookie.M, mustBeAuth.M, createToken.M},
					Handler:    &dashboard.Controller{},
				},
				{
					Path:       "/dashboard",
					Method:     "HEAD",
					Handler:    &dashboard.Controller{},
				},
				// signin --------------------------------------------------
				{
					Path:       "/signin",
					Method:     "GET",
					Middleware: []func(http.Handler) http.Handler{cookie.M, isAuth.M, createToken.M},
					Handler:    &signin.Controller{},
				},
				{
					Path:       "/signin",
					Method:     "HEAD",
					Handler:    &signin.Controller{},
				},
				{
					Path:       "/signin",
					Method:     "POST",
					Middleware: []func(http.Handler) http.Handler{cookie.M, isAuth.M, validateToken.M},
					Handler:    &signin.Controller{},
				},
				// signout --------------------------------------------------
				{
					Path:       "/signout",
					Method:     "HEAD",
					Handler:    &signout.Controller{},
				},
				{
					Path:       "/signout",
					Method:     "POST",
					Middleware: []func(http.Handler) http.Handler{cookie.M, mustBeAuth.M, validateToken.M},
					Handler:    &signout.Controller{},
				},
				// signup --------------------------------------------------
				{
					Path:       "/signup",
					Method:     "GET",
					Middleware: []func(http.Handler) http.Handler{cookie.M, isAuth.M, createToken.M},
					Handler:    &signup.Controller{},
				},
				{
					Path:       "/signup",
					Method:     "HEAD",
					Handler:    &signup.Controller{},
				},
				{
					Path:       "/signup",
					Method:     "POST",
					Middleware: []func(http.Handler) http.Handler{cookie.M, isAuth.M, validateToken.M},
					Handler:    &signup.Controller{},
				},
				// reset --------------------------------------------------
				{
					Path:       "/reset",
					Method:     "GET",
					Middleware: []func(http.Handler) http.Handler{cookie.M, isAuth.M, createToken.M},
					Handler:    &reset.Controller{},
				},
				{
					Path:       "/reset",
					Method:     "HEAD",
					Handler:    &reset.Controller{},
				},
				{
					Path:       "/reset",
					Method:     "POST",
					Middleware: []func(http.Handler) http.Handler{cookie.M, isAuth.M, validateToken.M},
					Handler:    &reset.Controller{},
				},
				// public --------------------------------------------------
				{
					Path:    "/public/",
					Method:  "GET",
					Handler: http.StripPrefix("/public", http.FileServer(http.Dir("./public/"))),
				},
				// favicon.ico --------------------------------------------------
				{
					Path:   "/favicon.ico",
					Method: "GET",
					Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
						http.Redirect(w, r, "/public/favicon.ico", http.StatusPermanentRedirect)
					}),
				},
				// humans.txt --------------------------------------------------
				{
					Path:   "/humans.txt",
					Method: "GET",
					Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
						http.Redirect(w, r, "/public/humans.txt", http.StatusPermanentRedirect)
					}),
				},
				// robots.txt --------------------------------------------------
				{
					Path:   "/robots.txt",
					Method: "GET",
					Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
						http.Redirect(w, r, "/public/robots.txt", http.StatusPermanentRedirect)
					}),
				},
				// security.txt --------------------------------------------------
				{
					Path:   "/security.txt",
					Method: "GET",
					Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
						http.Redirect(w, r, "/public/security.txt", http.StatusPermanentRedirect)
					}),
				},
				// sitemap.xml --------------------------------------------------
				{
					Path:   "/sitemap.xml",
					Method: "GET",
					Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
						http.Redirect(w, r, "/public/sitemap.xml", http.StatusPermanentRedirect)
					}),
				},
				// /debug/pprof --------------------------------------------------
				{
					Path:    "/debug/pprof",
					Method:  "GET",
					Handler: http.HandlerFunc(pprof.Index),
				},
				// /debug/pprof/cmdline --------------------------------------------------
				{
					Path:    "/debug/pprof/cmdline",
					Method:  "GET",
					Handler: http.HandlerFunc(pprof.Cmdline),
				},
				// /debug/pprof/profile --------------------------------------------------
				{
					Path:    "/debug/pprof/profile",
					Method:  "GET",
					Handler: http.HandlerFunc(pprof.Profile),
				},
				// /debug/pprof/symbol --------------------------------------------------
				{
					Path:    "/debug/pprof/symbol",
					Method:  "GET",
					Handler: http.HandlerFunc(pprof.Symbol),
				},
				// /debug/pprof/trace --------------------------------------------------
				{
					Path:    "/debug/pprof/trace",
					Method:  "GET",
					Handler: http.HandlerFunc(pprof.Trace),
				},
				// /debug/pprof/profile/goroutine --------------------------------------------------
				{
					Path:    "/debug/pprof/profile/goroutine",
					Method:  "GET",
					Handler: pprof.Handler("goroutine"),
				},
				// /debug/pprof/profile/heap --------------------------------------------------
				{
					Path:    "/debug/pprof/profile/heap",
					Method:  "GET",
					Handler: pprof.Handler("heap"),
				},
				// /debug/pprof/profile/allocs --------------------------------------------------
				{
					Path:    "/debug/pprof/profile/allocs",
					Method:  "GET",
					Handler: pprof.Handler("allocs"),
				},
				// /debug/pprof/profile/threadcreate --------------------------------------------------
				{
					Path:    "/debug/pprof/profile/threadcreate",
					Method:  "GET",
					Handler: pprof.Handler("threadcreate"),
				},
				// /debug/pprof/profile/block --------------------------------------------------
				{
					Path:    "/debug/pprof/profile/block",
					Method:  "GET",
					Handler: pprof.Handler("block"),
				},
				// /debug/pprof/profile/mutex --------------------------------------------------
				{
					Path:    "/debug/pprof/profile/mutex",
					Method:  "GET",
					Handler: pprof.Handler("mutex"),
				},
			},
		),
		ErrorLog: debug.Error,
	}).Run())
}

Middleware


middleware/auth/is

Redirect the user to home page if they've already authenticated.

// Package is
package is

import (
	"net/http"

	"bitbucket.org/_mikey/micro/ctxkey"
	"bitbucket.org/_mikey/micro/session"
)

func M(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if sess, ok := r.Context().Value(ctxkey.NewKey("session")).(*session.Session); ok {
			if authenticated := sess.Get("authenticated"); authenticated == true {
				http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
				return
			}
		}
		next.ServeHTTP(w, r)
	})
}
middleware/auth/must

Redirect the user to the signin page if they're unauthenticated.

// Package must
package must

import (
	"context"
	"errors"
	"net/http"

	"bitbucket.org/_mikey/micro/ctxkey"
	"bitbucket.org/_mikey/micro/session"
)

func M(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if sess, ok := r.Context().Value(ctxkey.NewKey("session")).(*session.Session); ok {
			if authenticated := sess.Get("authenticated"); authenticated == true {
				next.ServeHTTP(w, r)
				return
			}
		}
		http.Redirect(w, r.WithContext(context.WithValue(r.Context(), ctxkey.NewKey("error"), errors.New("unauthenticated"))), "/signin?authenticated=false", http.StatusSeeOther)
	})
}

Create a cookie and start a session.

// Package cookie
package cookie

import (
	"context"
	"net/http"
	"time"

	"bitbucket.org/_mikey/micro/ctxkey"
	"bitbucket.org/_mikey/micro/session"
)

func M(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		sess, err := session.Store.Get(r)
		if err != nil {
			s := session.New(10 * time.Minute)
			if err = s.Start(w); err != nil {
				http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
				return
			}
			sess = s
		}
		next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), ctxkey.NewKey("session"), sess)))
	})
}
middleware/csrftoken/token

Create a random CSRF token.

// Package token
package token

import (
	"context"
	"net/http"

	"bitbucket.org/_mikey/micro/ctxkey"
	"bitbucket.org/_mikey/micro/session"
	"github.com/google/uuid"
)

func M(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		sess, ok := r.Context().Value(ctxkey.NewKey("session")).(*session.Session)
		if !ok {
			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			return
		}
		sess.Set("nonce", uuid.New().String())
		next.ServeHTTP(w, r)
	})
}
middleware/csrftoken/validate

Validate the CSRF token.

// Package validate
package validate

import (
	"net/http"

	"bitbucket.org/_mikey/micro/ctxkey"
	"bitbucket.org/_mikey/micro/session"
)

func M(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if sess, ok := r.Context().Value(ctxkey.NewKey("session")).(*session.Session); ok {
			if nonce := sess.Get("nonce"); r.PostFormValue("nonce") == nonce {
				next.ServeHTTP(w, r)
				return
			}
		}
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
	})
}

Directories

Path Synopsis
Package app provides an HTTP server
Package app provides an HTTP server
Package ctxkey
Package ctxkey
log
debug
Package debug
Package debug
Package mux implements an HTTP multiplexer/router
Package mux implements an HTTP multiplexer/router
Package session
Package session

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL