tcpproto

package module
v1.7.6 Latest Latest
Warning

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

Go to latest
Published: Oct 17, 2022 License: GPL-2.0 Imports: 27 Imported by: 0

README

tcpproto

Simple http-like layer ontop of TCP. This package currently supports:

  • Getting system information from requests (request.SysInfo()):
    • Hostname
    • CPU
    • Platform (OS)
    • Mac Address
    • Max Memory
    • Max Disk
  • Encrypting certain headers client side, with an RSA public key
    • Only works if public/private key is provided, and CONF.Use_Crypto=true
  • Cookies encrypted with the SECRET_KEY
  • Non-encrypted cookies
  • File inside of requests (Single file only)
  • Max size of requests
  • Handling based upon COMMAND: header
  • Support for middleware before and after calling the main handler

Installation:

go get github.com/Nigel2392/tcpproto

Usage:

  • The config struct is pretty basic, but you should not edit it manually. The config is predefined, and you can get it by calling tcpproto.GetConfig() or by using SetConfig().
type Config struct {
	SecretKey          string
	LOGGER             *Logger
	BUFF_SIZE          int
	Default_Auth       func(rq *Request, resp *Response) error
	Include_Sysinfo    bool
	Use_Crypto         bool
	MAX_CONTENT_LENGTH int
	MAX_HEADER_SIZE    int
}
// Predefined byte-sizes
const (
	DISABLED     = 0
	KILOBYTE     = 1024
	MEGABYTE     = 1024 * KILOBYTE
	GIGABYTE     = 1024 * MEGABYTE
	TEN_GIGABYTE = 10 * GIGABYTE
)
					       
conf := tcpproto.SetConfig(
	"SECRET_KEY", 		// Secret key for encryption
	"DEBUG",    		// Logger level
	2048,     			// Buffer size
	tcpproto.DISABLED, 	// Max content length
	true, 				// Include system info
	true,  				// Use crypto
	func(rq *Request, resp *Response) error {return nil} // Default authentication function.
)

Then we can get to start sending requests. A typical response/request looks like this:

CONTENT_LENGTH: CONTENT_LENGTH
COMMAND: COMMAND
CUSTOM_HEADER: CUSTOM_HEADER
CUSTOM_HEADER1: CUSTOM_HEADER1
CUSTOM_HEADER2: CUSTOM_HEADER2
CUSTOM_HEADER3: CUSTOM_HEADER3
HAS_FILE: HAS_FILE 
FILE_NAME: FILE_NAME 
FILE_SIZE: FILE_SIZE 
FILE_BOUNDARY: FILE_BOUNDARY 

FILE_BOUNDARY
FILE CONTENT
FILE_BOUNDARY

CONTENT CONTENT CONTENT
CONTENT CONTENT CONTENT
CONTENT CONTENT CONTENT

Where anything that has to do with files, can optionally be left out.
To add a file, you can use the following:

request.AddFile(filename string, content []byte, boundary string)

The following is needed:
CONTENT_LENGTH and COMMAND
Content length is used to make sure the whole request is parsed properly, and chunks we not forgotten.
Command is used to add callbacks to the request/response cycle, where you can edit either one.

Server

A typical server looks like this:

func main() {
	ipaddr := "127.0.0.1"
	port := 22392
	// If CONF.Use_Crypto is disabled, you do not have to provide the private RSA key,
	// it can be left as an empty string.
	s := tcpproto.InitServer(ipaddr, port, "PRIVATE_KEY.pem")
	s.AddMiddlewareBeforeResp(AuthMiddleware) // Middleware to be called before the callback is called.
	s.AddMiddlewareAfterResp(tcpproto.LogMiddleware) // Middleware to be called after the callback is called.
	s.AddCallback("SET", SET) // The callback to be called, derived from "COMMAND" header.
	s.AddCallback("GET", GET)
	if err := s.Start(); err != nil {
		os.Exit(1)
	}
}
Middleware

To add middleware, or callbacks, the function needs to take the following arguments:

func MiddlewareOrCallback(rq *tcpproto.Request, resp *tcpproto.Response){
	// Do stuff here
}

In these middleware and callbacks you can ofcourse access all headers with request.Headers (Cookies are also stored here) Or optionally, you can encrypt data with the SECRET_KEY provided to the CONFIG.

Storing data client side

This data is then sent, like HTTP cookies, on every request. To encrypt data, you can use the following:

response.Lock(key string, data string)

To set some cookies in the response, you can use the following:

response.Remember(key string, data string)

To remove the encrypted data from the client

response.ForgetVault(key string)

To remove a cookie from the client

response.Forget(key string)

When the client has sent this data, you could look at it like so:

response.SetValues 	// Cookies
response.Vault		// Vault
response.Headers 	// Headers
response.Data		// Client side vault
Client information

If you have enabled Include_Sysinfo in the CONFIG, you can access the following method in on the request:

var system_information tcpproto.SysInfo
system_information = request.SysInfo()

You then have access to the following information:

system_information.Hostname 	// The hostname of the client
system_information.Platform 	// The platform of the client
system_information.CPU 			// The CPU of the client
system_information.RAM 			// The RAM of the client
system_information.Disk 		// The disk of the client
system_information.MacAddr 		// The MAC address of the client

Client:

A typical client looks like this:

// Initialise request
request := InitRequest()

// Set some headers
// CONTENT_LENGTH is automatically added when generating the request.
request.Headers["COMMAND"] = "SET"
request.Headers["HEADER-TEST-1"] = "VALUE-TEST-1" 
request.Headers["HEADER-TEST-2"] = "VALUE-TEST-2" 
request.Headers["HEADER-TEST-3"] = "VALUE-TEST-3" 

// Set request content
request.Content = []byte("TEST_CONTENT\n")

// Initialize client
// If CONF.Use_Crypto is disabled, you do not have to provide the public RSA key,
// it can be left as an empty string.
client := InitClient("127.0.0.1", 12239, "PUBLIKKEY.pem")

// Connect to server
if err := client.Connect(); err != nil {
	err = errors.New("error connecting to server: " + err.Error())
	t.Error(err)
}

// Set some "cookies"
client.Cookies["TEST0"] = InitCookie("TEST0", "TEST0")

// Add something to the client side vault, this is encrypted with a public key, and decrypted by the server. 
// This only works if CONF.Use_Crypto is enabled.
client.Vault("Cookiename", "Cookievalue")

// Get the response when sending the data to the server
response, err = client.Send(request)
if err != nil {
	err = errors.New("error sending request: " + err.Error())
	t.Error(err)
}
// Close the client when done
if err := client.Close(); err != nil {
	err = errors.New("error closing client connection: " + err.Error())
	t.Error(err)
}

As you can see, the client receives the response back when sending data to a server. This data fits into the following struct:

// Response the server sends back
type Response struct {
	Headers   map[string]string
	SetValues map[string]string
	DelValues []string
	Vault     map[string]string
	Content   []byte
	File      *FileData
	Error     []error
}

// Request to send to the server
type Request struct {
	Headers            map[string]string
	Vault              map[string]string
	Content            []byte
	File               *FileData
	Data               map[string]string
	User               *User
	Conn               net.Conn
}

Documentation

Index

Constants

View Source
const (
	DISABLED     = 0
	KILOBYTE     = 1024
	MEGABYTE     = 1024 * KILOBYTE
	GIGABYTE     = 1024 * MEGABYTE
	TEN_GIGABYTE = 10 * GIGABYTE
)

Variables

View Source
var CONF = InitConfig("SECRET_KEY", "DEBUG", 2048, DISABLED, true, true, PEM, Authenticate)
View Source
var PEM embed.FS

Functions

func Authenticate

func Authenticate(rq *Request, resp *Response) error

func Base64ToBytes

func Base64ToBytes(s string) []byte

func Base64ToKey

func Base64ToKey(s string) *[32]byte

func BytesToBase64

func BytesToBase64(b []byte) string

func Colorize

func Colorize(level int, msg string) string

func Decrypt

func Decrypt(ciphertext []byte, key *[32]byte) (plaintext []byte, err error)

Decrypt decrypts data using 256-bit AES-GCM. This both hides the content of the data and provides a check that it hasn't been altered. Expects input form nonce|ciphertext|tag where '|' indicates concatenation.

func DecryptString

func DecryptString(s string, key *[32]byte) (string, error)

func DecryptWithPrivateKey

func DecryptWithPrivateKey(ciphertext []byte, priv *rsa.PrivateKey) []byte

DecryptWithPrivateKey decrypts data with private key

func Encrypt

func Encrypt(plaintext []byte, key *[32]byte) (ciphertext []byte, err error)

Encrypt encrypts data using 256-bit AES-GCM. This both hides the content of the data and provides a check that it hasn't been altered. Output takes the form nonce|ciphertext|tag where '|' indicates concatenation.

func EncryptString

func EncryptString(s string, key *[32]byte) (string, error)

func EncryptWithPublicKey

func EncryptWithPublicKey(msg []byte, pub *rsa.PublicKey) []byte

EncryptWithPublicKey encrypts data with public key

func ExportPrivate_PEM_Key

func ExportPrivate_PEM_Key(key *rsa.PrivateKey, filename string)

func ExportPublic_PEM_Key

func ExportPublic_PEM_Key(key *rsa.PublicKey, filename string)

func GenerateKeyPair

func GenerateKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey)

func GetMACAddr

func GetMACAddr() (string, error)

func ImportPrivate_PEM_Key

func ImportPrivate_PEM_Key(filename string) *rsa.PrivateKey

func ImportPublic_PEM_Key

func ImportPublic_PEM_Key(filename string) *rsa.PublicKey

func KeyToBase64

func KeyToBase64(key *[32]byte) string

func LogMiddleware

func LogMiddleware(rq *Request, resp *Response)

func NewEncryptionKey

func NewEncryptionKey() *[32]byte

NewEncryptionKey generates a random 256-bit key for Encrypt() and Decrypt(). It panics if the source of randomness fails.

func PadStr

func PadStr(s string, l int) string

func PrivKeySTR_to_PrivKey

func PrivKeySTR_to_PrivKey(privkeystr string) *rsa.PrivateKey

func PubKeySTR_to_PubKey

func PubKeySTR_to_PubKey(pubkeystr string) *rsa.PublicKey

func TransferCookies added in v1.6.8

func TransferCookies(rq *Request, resp *Response)

func TransferValues

func TransferValues(rq *Request, resp *Response)

func TrimExtraSpaces

func TrimExtraSpaces(s string) string

func UnpadStr

func UnpadStr(s string) string

func WrapTime

func WrapTime(t string, msg string) string

Types

type Client

type Client struct {
	IP          string
	Port        int
	Conn        net.Conn
	Cookies     map[string]*Cookie
	ClientVault map[string]string
	PUBKEY      *rsa.PublicKey
}

func InitClient

func InitClient(ip string, port int, pubkey_file string) *Client

func (*Client) Addr

func (c *Client) Addr() string

func (*Client) Close

func (c *Client) Close() error

func (*Client) Connect

func (c *Client) Connect() error

func (*Client) ParseResponse

func (c *Client) ParseResponse(rq *Request, header map[string]string, recv_data []byte) (*Response, error)

func (*Client) Send

func (c *Client) Send(rq *Request) (*Response, error)

func (*Client) UpdateCookies

func (c *Client) UpdateCookies(remember map[string]string, forget []string)

func (*Client) Vault

func (c *Client) Vault(key string, value string) error

type Config

type Config struct {
	SecretKey          string
	LOGGER             *Logger
	BUFF_SIZE          int
	Default_Auth       func(rq *Request, resp *Response) error
	Include_Sysinfo    bool
	Use_Crypto         bool
	MAX_CONTENT_LENGTH int
	MAX_HEADER_SIZE    int
	FS                 fs.FS
}

func GetConfig

func GetConfig() *Config

func InitConfig

func InitConfig(secret_key string, loglevel string, buff_size int, max_length int, use_crypto bool, include_sysinfo bool, fs fs.FS, authenticate func(rq *Request, resp *Response) error) *Config

func SetConfig

func SetConfig(secret_key string, loglevel string, buff_size int, max_length int, use_crypto bool, include_sysinfo bool, fs fs.FS, authenticate func(rq *Request, resp *Response) error) *Config

func (*Config) GenVault

func (c *Config) GenVault(key string, value string) (string, error)

func (*Config) GetVault

func (c *Config) GetVault(value string) (string, string, bool)
type Cookie struct {
	Name  string
	Value string
}

func InitCookie

func InitCookie(name string, value string) *Cookie

type Cookies

type Cookies struct {
	// contains filtered or unexported fields
}

func InitCookies

func InitCookies() *Cookies

func (*Cookies) AddCookie

func (c *Cookies) AddCookie(cookie *Cookie)

func (*Cookies) GetCookie

func (c *Cookies) GetCookie(name string) *Cookie

type FileData

type FileData struct {
	Name     string
	Size     int
	Boundary string
	Present  bool
	Content  []byte
}

func (*FileData) EndBoundary

func (fdata *FileData) EndBoundary() []byte

func (*FileData) StartBoundary

func (fdata *FileData) StartBoundary() []byte

type Logger

type Logger struct {
	Level string `json:"level"`
}

func NewLogger

func NewLogger(level string) *Logger

func (*Logger) Debug

func (l *Logger) Debug(msg string)

func (*Logger) Error

func (l *Logger) Error(msg string)

func (*Logger) GetLevel

func (l *Logger) GetLevel() int

func (*Logger) GetLevelFromType

func (l *Logger) GetLevelFromType(t string) int

func (*Logger) Info

func (l *Logger) Info(msg string)

func (*Logger) Test

func (l *Logger) Test(msg string)

func (*Logger) Warning

func (l *Logger) Warning(msg string)

func (*Logger) Write

func (l *Logger) Write(t string, msg string)

type Middleware

type Middleware struct {
	BeforeResponse func(rq *Request, resp *Response)
	AfterResponse  func(rq *Request, resp *Response)
	Before         bool
}

type Request

type Request struct {
	Headers map[string]string
	Vault   map[string]string
	Content []byte
	File    *FileData
	Data    map[string]string
	User    *User
	Conn    net.Conn
	// contains filtered or unexported fields
}

func InitRequest

func InitRequest(args ...string) *Request

func (*Request) AddCookie

func (rq *Request) AddCookie(key string, value string)

func (*Request) AddFile

func (rq *Request) AddFile(filename string, file []byte, boundary string)

func (*Request) AddHeader

func (rq *Request) AddHeader(key string, value string)

func (*Request) ContentLength

func (rq *Request) ContentLength() int

func (*Request) DecryptVault

func (rq *Request) DecryptVault() map[string]string

func (*Request) Generate

func (rq *Request) Generate() ([]byte, error)

func (*Request) MacAddr

func (rq *Request) MacAddr() string

func (*Request) ParseFile

func (rq *Request) ParseFile() error

func (*Request) ParseFileData

func (rq *Request) ParseFileData() ([]byte, error)

func (*Request) SysInfo

func (rq *Request) SysInfo() *SysInfo

type Response

type Response struct {
	Headers   map[string]string
	SetValues map[string]string
	DelValues []string
	Vault     map[string]string
	Content   []byte
	File      *FileData
	Error     []error
}

func InitResponse

func InitResponse(args ...string) *Response

func (*Response) AddError

func (resp *Response) AddError(err string)

func (*Response) AddFile

func (resp *Response) AddFile(filename string, file []byte, boundary string)

func (*Response) Bytes

func (resp *Response) Bytes() []byte

func (*Response) ContentLength

func (resp *Response) ContentLength() int

func (*Response) DecodeHeaders

func (resp *Response) DecodeHeaders(headers map[string]string) (map[string]string, []string, error)

func (*Response) Forget

func (resp *Response) Forget(key string) *Response

func (*Response) ForgetVault

func (resp *Response) ForgetVault(key string)

func (*Response) GenHeader

func (resp *Response) GenHeader() string

func (*Response) Generate

func (resp *Response) Generate() []byte

func (*Response) GetVault

func (resp *Response) GetVault(key string) (string, bool)

func (*Response) Lock

func (resp *Response) Lock(key string, value string) *Response

func (*Response) ParseFile

func (resp *Response) ParseFile() error

func (*Response) ParseFileData

func (resp *Response) ParseFileData() ([]byte, error)

func (*Response) Remember

func (resp *Response) Remember(k string, v string) *Response

type Server

type Server struct {
	IP         string
	Config     *Config
	Port       int
	Callbacks  map[string]func(rq *Request, resp *Response)
	Middleware []*Middleware
	PRIVKEY    *rsa.PrivateKey
	// contains filtered or unexported fields
}

func InitServer

func InitServer(ip string, port int, privkey_file string) *Server

func (*Server) AddCallback

func (s *Server) AddCallback(key string, callback func(rq *Request, resp *Response))

Add a COMMAND callback to the server

func (*Server) AddMiddlewareAfterResp

func (s *Server) AddMiddlewareAfterResp(middleware func(rq *Request, resp *Response))

Middleware to be used after the response is created

func (*Server) AddMiddlewareBeforeResp

func (s *Server) AddMiddlewareBeforeResp(middleware func(rq *Request, resp *Response))

Middleware to be used before the response is created

func (*Server) Addr

func (s *Server) Addr() string

func (*Server) DecryptClientVault

func (s *Server) DecryptClientVault(rq *Request) error

func (*Server) ExecCallback

func (s *Server) ExecCallback(rq *Request, resp *Response) error

Execute the callback for the given request

func (*Server) MiddlewareAfterResponse

func (s *Server) MiddlewareAfterResponse(rq *Request, resp *Response)

Execute middleware after the response is created

func (*Server) MiddlewareBeforeResponse

func (s *Server) MiddlewareBeforeResponse(rq *Request, resp *Response)

Execute middleware before the response is created

func (*Server) ParseConnection

func (s *Server) ParseConnection(conn net.Conn) (*Request, *Response, error)

func (*Server) Send

func (s *Server) Send(conn net.Conn, resp *Response) error

func (*Server) Serve

func (s *Server) Serve() error

func (*Server) Start

func (s *Server) Start() error

type SysInfo

type SysInfo struct {
	Hostname string `json:"hostname"`
	Platform string `json:"platform"`
	CPU      string `json:"cpu"`
	RAM      uint64 `json:"ram"`
	Disk     uint64 `json:"disk"`
	MacAddr  string `json:"macaddr"`
}

SysInfo saves the basic system information

func GetSysInfo

func GetSysInfo() *SysInfo

func (*SysInfo) ToJSON

func (s *SysInfo) ToJSON() string

type User

type User struct {
	ID              int
	Username        string
	Email           string
	Password        string
	IsAdmin         bool
	IsAuthenticated bool
	SysInfo         *SysInfo
}

Jump to

Keyboard shortcuts

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