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)
})
}
middleware/cookie
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)
})
}
Click to show internal directories.
Click to hide internal directories.