kamux

package
v1.0.47 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2022 License: BSD-3-Clause Imports: 45 Imported by: 0

Documentation

Index

Constants

View Source
const (
	GET int = iota
	POST
	PUT
	PATCH
	DELETE
	HEAD
	OPTIONS
	WS
	SSE
)

Variables

View Source
var (
	CORSDebug    = false
	ReadTimeout  = 5 * time.Second
	WriteTimeout = 20 * time.Second
	IdleTimeout  = 20 * time.Second
)
View Source
var Admin = func(handler Handler) Handler {
	const key utils.ContextKey = "user"
	return func(c *Context) {
		session, err := c.GetCookie("session")
		if err != nil || session == "" {

			c.DeleteCookie("session")
			http.Redirect(c.ResponseWriter, c.Request, "/admin/login", http.StatusTemporaryRedirect)
			return
		}
		if SESSION_ENCRYPTION {
			session, err = encryptor.Decrypt(session)
			if err != nil {
				c.Status(http.StatusTemporaryRedirect).Redirect("/admin/login")
				return
			}
		}
		user, err := orm.Model[models.User]().Where("uuid = ?", session).One()

		if err != nil {

			c.Status(http.StatusTemporaryRedirect).Redirect("/admin/login")
			return
		}

		if !user.IsAdmin {
			c.Status(403).Text("Middleware : Not allowed to access this page")
			return
		}

		ctx := context.WithValue(c.Request.Context(), key, user)
		*c = Context{
			ResponseWriter: c.ResponseWriter,
			Request:        c.Request.WithContext(ctx),
			Params:         c.Params,
		}

		handler(c)
	}
}
View Source
var Auth = func(handler Handler) Handler {
	const key utils.ContextKey = "user"
	return func(c *Context) {
		session, err := c.GetCookie("session")
		if err != nil || session == "" {

			c.DeleteCookie("session")
			handler(c)
			return
		}
		if SESSION_ENCRYPTION {
			session, err = encryptor.Decrypt(session)
			if err != nil {
				handler(c)
				return
			}
		}

		user, err := orm.Model[models.User]().Where("uuid = ?", session).One()
		if err != nil {

			handler(c)
			return
		}

		ctx := context.WithValue(c.Request.Context(), key, user)
		*c = Context{
			ResponseWriter: c.ResponseWriter,
			Request:        c.Request.WithContext(ctx),
			Params:         c.Params,
		}
		handler(c)
	}
}

AuthMiddleware can be added to any handler to get user cookie authentication and pass it to handler and templates

View Source
var BasicAuth = func(next Handler, user, pass string) Handler {
	return func(c *Context) {

		username, password, ok := c.Request.BasicAuth()
		if ok {

			usernameHash := sha256.Sum256([]byte(username))
			passwordHash := sha256.Sum256([]byte(password))
			expectedUsernameHash := sha256.Sum256([]byte(user))
			expectedPasswordHash := sha256.Sum256([]byte(pass))

			usernameMatch := (subtle.ConstantTimeCompare(usernameHash[:], expectedUsernameHash[:]) == 1)
			passwordMatch := (subtle.ConstantTimeCompare(passwordHash[:], expectedPasswordHash[:]) == 1)

			if usernameMatch && passwordMatch {
				next(c)
				return
			}
		}

		c.ResponseWriter.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
		http.Error(c.ResponseWriter, "Unauthorized", http.StatusUnauthorized)
	}
}
View Source
var COOKIE_EXPIRE = time.Now().Add(7 * 24 * time.Hour)

COOKIE_EXPIRE global cookie expiry time

View Source
var CORS = func(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		w.Header().Set("Access-Control-Allow-Headers:", "*")
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "*")
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusOK)
			return
		}

		next.ServeHTTP(w, r)
	})
}
View Source
var CSRF = func(handler http.Handler) http.Handler {

	tokBytes := make([]byte, 64)
	_, err := io.ReadFull(rand.Reader, tokBytes)
	logger.CheckError(err)

	massToken := csrf.MaskToken(tokBytes)
	toSendToken := base64.StdEncoding.EncodeToString(massToken)

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			token := r.Header.Get("X-CSRF-Token")
			if token == "" {
				http.SetCookie(w, &http.Cookie{
					Name:     "csrf_token",
					Value:    toSendToken,
					Path:     "/",
					Expires:  time.Now().Add(1 * time.Hour),
					Secure:   true,
					SameSite: http.SameSiteStrictMode,
				})
			}
		} else if r.Method == "POST" {
			token := r.Header.Get("X-CSRF-Token")
			if !csrf.VerifyToken(token, toSendToken) {
				w.WriteHeader(http.StatusBadRequest)
				json.NewEncoder(w).Encode(map[string]interface{}{
					"error": "CSRF not allowed",
				})
				return
			}
		}
		handler.ServeHTTP(w, r)
	})
}
View Source
var GZIP = func(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if strings.Contains(r.URL.Path, "metrics") {
			handler.ServeHTTP(w, r)
			return
		}

		for _, header := range r.Header["Upgrade"] {
			if header == "websocket" {

				handler.ServeHTTP(w, r)
				return
			}
		}
		if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
			gwriter := gzip.NewWrappedResponseWriter(w)
			defer gwriter.Flush()
			gwriter.Header().Set("Content-Encoding", "gzip")
			handler.ServeHTTP(gwriter, r)
			return
		}
		handler.ServeHTTP(w, r)
	})
}
View Source
var LIMITER = func(next http.Handler) http.Handler {
	var limiter = rate.NewLimiter(1, LIMITER_TOKENS)
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		v, ok := banned.Load(r.RemoteAddr)
		if ok {
			if time.Since(v.(time.Time)) > LIMITER_TIMEOUT {
				banned.Delete(r.RemoteAddr)
			} else {
				w.WriteHeader(http.StatusTooManyRequests)
				w.Write([]byte("<h1>YOU DID TOO MANY REQUEST, YOU HAVE BEEN BANNED FOR 5 MINUTES </h1>"))
				banned.Store(r.RemoteAddr, time.Now())
				return
			}
		}
		if !limiter.Allow() {
			w.WriteHeader(http.StatusTooManyRequests)
			w.Write([]byte("<h1>YOU DID TOO MANY REQUEST, YOU HAVE BEEN BANNED FOR 5 MINUTES </h1>"))
			banned.Store(r.RemoteAddr, time.Now())
			return
		}
		next.ServeHTTP(w, r)
	})
}
View Source
var LIMITER_TIMEOUT = 5 * time.Minute
View Source
var LIMITER_TOKENS = 50
View Source
var LOGS = func(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if utils.StringContains(r.URL.Path, "metrics", "sw.js", "favicon", "/static/", "/sse/", "/ws/", "/wss/") {
			h.ServeHTTP(w, r)
			return
		}

		for _, header := range r.Header["Upgrade"] {
			if header == "websocket" {

				h.ServeHTTP(w, r)
				return
			}
		}
		recorder := &logs.StatusRecorder{
			ResponseWriter: w,
			Status:         200,
		}
		t := time.Now()
		h.ServeHTTP(recorder, r)
		res := fmt.Sprintf("[%s] --> '%s' --> [%d]  from: %s ---------- Took: %v", r.Method, r.URL.Path, recorder.Status, r.RemoteAddr, time.Since(t))

		if recorder.Status >= 200 && recorder.Status < 400 {
			fmt.Printf(logger.Green, res)
		} else if recorder.Status >= 400 || recorder.Status < 200 {
			fmt.Printf(logger.Red, res)
		} else {
			fmt.Printf(logger.Yellow, res)
		}
		if settings.Config.Logs {
			logger.StreamLogs = append(logger.StreamLogs, res)
			eventbus.Publish("internal-logs", map[string]string{})
		}
	})
}
View Source
var MultipartSize = 10 << 20
View Source
var RECOVERY = func(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			err := recover()
			if err != nil {
				logger.Error(err)
				jsonBody, _ := json.Marshal(map[string]string{
					"error": "There was an internal server error",
				})
				w.Header().Set("Content-Type", "application/json")
				w.WriteHeader(http.StatusInternalServerError)
				w.Write(jsonBody)
			}
		}()
		next.ServeHTTP(w, r)
	})
}
View Source
var SESSION_ENCRYPTION = true
View Source
var Static embed.FS
View Source
var Templates embed.FS

Functions

func LoadTranslations

func LoadTranslations()

Types

type Context

type Context struct {
	http.ResponseWriter
	*http.Request
	Params map[string]string
	// contains filtered or unexported fields
}

Context is a wrapper of responseWriter, request, and params map

func (*Context) AddHeader added in v0.6.5

func (c *Context) AddHeader(key, value string)

AddHeader Add append a header value to key if exist

func (*Context) BodyJson added in v0.5.2

func (c *Context) BodyJson() map[string]any

BodyJson get json body from request and return map USAGE : data := c.BodyJson(r)

func (*Context) BodyText added in v0.6.5

func (c *Context) BodyText() string

func (*Context) DeleteCookie

func (c *Context) DeleteCookie(key string)

DeleteCookie delete cookie with specific key

func (*Context) DeleteFile

func (c *Context) DeleteFile(path string) error

DELETE FILE

func (*Context) Download

func (c *Context) Download(data_bytes []byte, asFilename string)

Download download data_bytes(content) asFilename(test.json,data.csv,...) to the client

func (*Context) EnableTranslations

func (c *Context) EnableTranslations()

EnableTranslations get user ip, then location country using nmap, so don't use it if u don't have it install, and then it parse csv file to find the language spoken in this country, to finaly set cookie 'lang' to 'en' or 'fr'...

func (*Context) GetCookie

func (c *Context) GetCookie(key string) (string, error)

GetCookie get cookie with specific key

func (*Context) GetUserIP

func (c *Context) GetUserIP() string

func (*Context) Html added in v0.6.0

func (c *Context) Html(template_name string, data map[string]any)

Html return template_name with data to the client

func (*Context) IsAuthenticated added in v0.7.7

func (c *Context) IsAuthenticated() bool

func (*Context) Json added in v0.6.0

func (c *Context) Json(data any)

Json return json to the client

func (*Context) JsonIndent added in v0.6.0

func (c *Context) JsonIndent(data any)

JsonIndent return json indented to the client

func (*Context) ParseMultipartForm added in v1.0.9

func (c *Context) ParseMultipartForm(size ...int64) (formData url.Values, formFiles map[string][]*multipart.FileHeader)

func (*Context) QueryParam

func (c *Context) QueryParam(name string) string

QueryParam get query param

func (*Context) Redirect added in v0.6.0

func (c *Context) Redirect(path string)

Redirect redirect the client to the specified path with a custom code

func (*Context) ServeEmbededFile

func (c *Context) ServeEmbededFile(content_type string, embed_file []byte)

ServeEmbededFile serve an embeded file from handler

func (*Context) ServeFile

func (c *Context) ServeFile(content_type, path_to_file string)

ServeFile serve a file from handler

func (*Context) SetCookie

func (c *Context) SetCookie(key, value string)

SetCookie set cookie given key and value

func (*Context) SetHeader added in v0.6.5

func (c *Context) SetHeader(key, value string)

SetHeader Set the header value to the new value, old removed

func (*Context) SetStatus added in v0.7.8

func (c *Context) SetStatus(statusCode int)

SetHeader Set the header value to the new value, old removed

func (*Context) Status added in v0.6.0

func (c *Context) Status(code int) *Context

Status set status to context, will not be writed to header

func (*Context) StreamResponse

func (c *Context) StreamResponse(response string) error

StreamResponse send SSE Streaming Response

func (*Context) Text added in v0.6.0

func (c *Context) Text(body string)

Text return text with custom code to the client

func (*Context) UploadFile

func (c *Context) UploadFile(received_filename, folder_out string, acceptedFormats ...string) (string, []byte, error)

UploadFile upload received_filename into folder_out and return url,fileByte,error

func (*Context) UploadFiles added in v0.5.0

func (c *Context) UploadFiles(received_filenames []string, folder_out string, acceptedFormats ...string) ([]string, [][]byte, error)

func (*Context) User added in v0.7.7

func (c *Context) User() models.User

type Handler

type Handler func(c *Context)

Handler

type M added in v1.0.8

type M map[string]any

type Route

type Route struct {
	Method  string
	Pattern *regexp.Regexp
	Handler
	WsHandler
	Clients         map[string]*websocket.Conn
	AllowedOrigines []string
}

Route

type Router

type Router struct {
	Routes       map[int][]Route
	DefaultRoute Handler
	Server       *http.Server
}

Router

func BareBone added in v1.0.3

func BareBone() *Router

func New

func New() *Router

New Create New Router from env file default: '.env'

func (*Router) AddEmbededTemplates

func (router *Router) AddEmbededTemplates(template_embed embed.FS, rootDir string) error

func (*Router) AddLocalTemplates

func (router *Router) AddLocalTemplates(pathToDir string) error

func (*Router) DELETE

func (router *Router) DELETE(pattern string, handler Handler, allowed_origines ...string)

DELETE handle DELETE to a route

func (*Router) Embed

func (r *Router) Embed(staticDir *embed.FS, templateDir *embed.FS)

GetEmbeded get embeded files and make them global

func (*Router) GET

func (router *Router) GET(pattern string, handler Handler)

GET handle GET to a route

func (*Router) HEAD added in v1.0.8

func (router *Router) HEAD(pattern string, handler Handler, allowed_origines ...string)

HEAD handle HEAD to a route

func (*Router) HandlerFunc added in v1.0.9

func (router *Router) HandlerFunc(method string, pattern string, handler http.HandlerFunc, allowed ...string)

HandlerFunc support standard library http.HandlerFunc

func (*Router) LoadEnv

func (router *Router) LoadEnv(files ...string)

LoadEnv load env vars from multiple files

func (*Router) NewFuncMap

func (router *Router) NewFuncMap(funcName string, function any)

func (*Router) OPTIONS added in v1.0.8

func (router *Router) OPTIONS(pattern string, handler Handler, allowed_origines ...string)

OPTIONS handle OPTIONS to a route

func (*Router) PATCH

func (router *Router) PATCH(pattern string, handler Handler, allowed_origines ...string)

PATCH handle PATCH to a route

func (*Router) POST

func (router *Router) POST(pattern string, handler Handler, allowed_origines ...string)

POST handle POST to a route

func (*Router) PUT

func (router *Router) PUT(pattern string, handler Handler, allowed_origines ...string)

PUT handle PUT to a route

func (*Router) Run

func (router *Router) Run()

Run start the server

func (*Router) SSE

func (router *Router) SSE(pattern string, handler Handler, allowed_origines ...string)

SSE handle SSE to a route

func (*Router) ServeEmbededDir

func (router *Router) ServeEmbededDir(pathLocalDir string, embeded embed.FS, webPath string)

func (*Router) ServeHTTP

func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP serveHTTP by handling methods,pattern,and params

func (*Router) ServeLocalDir

func (router *Router) ServeLocalDir(dirPath, webPath string)

func (*Router) UseMiddlewares

func (router *Router) UseMiddlewares(midws ...func(http.Handler) http.Handler)

UseMiddlewares chain global middlewares applied on the router

func (*Router) WS

func (router *Router) WS(pattern string, wsHandler WsHandler, allowed_origines ...string)

WS handle WS connection on a pattern

type WsContext

type WsContext struct {
	Ws     *websocket.Conn
	Params map[string]string
	Route
}

func (*WsContext) AddClient

func (c *WsContext) AddClient(key string)

AddClient add client to clients_list

func (*WsContext) Broadcast added in v0.6.0

func (c *WsContext) Broadcast(data any) error

Broadcast send message to all clients in c.Clients

func (*WsContext) BroadcastExceptCaller

func (c *WsContext) BroadcastExceptCaller(data map[string]any) error

BroadcastExceptCaller send message to all clients in c.Clients

func (*WsContext) Json added in v0.6.0

func (c *WsContext) Json(data map[string]any) error

Json send json to the client

func (*WsContext) ReceiveJson

func (c *WsContext) ReceiveJson() (map[string]any, error)

ReceiveJson receive json from ws and disconnect when stop receiving

func (*WsContext) ReceiveText

func (c *WsContext) ReceiveText() (string, error)

ReceiveText receive text from ws and disconnect when stop receiving

func (*WsContext) RemoveRequester

func (c *WsContext) RemoveRequester(name ...string)

RemoveRequester remove the client from Clients list in context

func (*WsContext) Text added in v0.6.0

func (c *WsContext) Text(data string) error

Text send text to the client

type WsHandler

type WsHandler func(c *WsContext)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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