Skip to content

Commit

Permalink
chore: function comments
Browse files Browse the repository at this point in the history
  • Loading branch information
AnnikaV9 committed Nov 10, 2024
1 parent 4914da3 commit 370237e
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 8 deletions.
24 changes: 16 additions & 8 deletions build/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ import (
"github.com/fatih/color"
)

/**
* Builds a Containerfile for a given language.
*
* @param string lang
* @param string setup
* @return string Containerfile content
*/
func ContainerFile(lang, setup string) string {
header := "FROM docker.io/alpine:latest"
prefix := "RUN apk update --no-cache && apk upgrade --no-cache && apk add --no-cache libc-dev musl-dev "
Expand All @@ -41,16 +48,17 @@ func ContainerFile(lang, setup string) string {
return fmt.Sprintf("%s\n%s%s && %s", header, prefix, setup, suffix)
}

func Cleanup(tempFile string) {
if err := os.Remove("TEMP_CONTAINERFILE"); err != nil {
color.Red("Error removing temporary file: %v", err)
os.Exit(1)
}
}

/**
* Builds images for all languages.
*/
func BuildImages() {
tempFile := "TEMP_CONTAINERFILE"
defer Cleanup(tempFile)
defer func() {
if err := os.Remove(tempFile); err != nil {
color.Red("Error removing temporary file: %v", err)
os.Exit(1)
}
}()

var builds Builds

Expand Down
12 changes: 12 additions & 0 deletions config/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ import (
"github.com/charmbracelet/log"
)

/**
* Loads the configuration from the given path.
*
* @param path string Path to the configuration file
* @return *Config Configuration object
*/
func LoadConfig(path string) *Config {
var config Config
if _, err := toml.DecodeFile(path, &config); err != nil {
Expand All @@ -31,6 +37,12 @@ func LoadConfig(path string) *Config {
return &config
}

/**
* Loads the language map from the given path.
*
* @param path string Path to the language map file
* @return *server.LangMap Language map object
*/
func LoadLangs(path string) *server.LangMap {
var langs server.LangMap
if _, err := toml.DecodeFile(path, &langs); err != nil {
Expand Down
15 changes: 15 additions & 0 deletions control/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ import (
"golang.org/x/crypto/argon2"
)

/**
* Checks if the user key is valid. Runs argon2id on
* requests until a valid request is made, then caches
* the key.
*
* @param userKey string User key
* @param serverKey []string Server key
*/
func (ks *KeyStore) CheckKey(userKey string, serverKey []string) bool {
if cachedKey, ok := ks.cachedKey.Load().(string); ok && userKey == cachedKey {
return true
Expand All @@ -39,6 +47,13 @@ func (ks *KeyStore) CheckKey(userKey string, serverKey []string) bool {
return false
}

/**
* Initializes the key store.
*
* @param keyFile string Key file
* @return *KeyStore Key store
* @return []string Key and salt
*/
func InitializeKeystore(keyFile string) (*KeyStore, []string) {
file, err := os.ReadFile(keyFile)
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions control/limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,26 @@ import (
"golang.org/x/time/rate"
)

/**
* Creates a new rate limiter.
*
* @return *RateLimiter Rate limiter object
*/
func NewRateLimiter() *RateLimiter {
return &RateLimiter{
clients: make(map[string]*Client),
}
}

/**
* Checks if a client should be rate limited or
* allowed to continue.
*
* @param ip string IP address of the client
* @param burst int Burst rate
* @param refill int Refill rate
* @return *rate.Limiter Rate limiter object
*/
func (rl *RateLimiter) LimitClient(ip string, burst, refill int) *rate.Limiter {
rl.mu.RLock()
user, exists := rl.clients[ip]
Expand All @@ -43,6 +57,10 @@ func (rl *RateLimiter) LimitClient(ip string, burst, refill int) *rate.Limiter {
return user.limiter
}

/**
* Starts a cleanup routine to remove old clients
* from the rate limiter. Run as a goroutine.
*/
func (rl *RateLimiter) StartCleanup() {
go func() {
for {
Expand All @@ -58,6 +76,16 @@ func (rl *RateLimiter) StartCleanup() {
}()
}

/**
* Checks if a client should be rate limited or
* allowed to continue. This is a wrapper around
* LimitClient and Allow.
*
* @param ip string IP address of the client
* @param burst int Burst rate
* @param refill int Refill rate
* @return bool True if the client should be rate limited
*/
func (rl *RateLimiter) CheckClient(ip string, burst, refill int) bool {
limiter := rl.LimitClient(ip, burst, refill)
return limiter.Allow()
Expand Down
3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ import (

const VERSION = "1.6.0"

/**
* The entry point of the application.
*/
func main() {
logger := log.NewWithOptions(os.Stderr, log.Options{
ReportTimestamp: true,
Expand Down
26 changes: 26 additions & 0 deletions podman/podman.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,43 @@ import (
"github.com/karlseguin/ccache/v3"
)

/**
* Creates a new LRU cache for caching exec results
* and a new Executor instance.
*
* @param timeout int Timeout for execution
* @param podmanPath string Path to podman executable
* @return *Executor New Executor instance
*/
func NewExecutor(timeout int, podmanPath string) *Executor {
cache := ccache.New(ccache.Configure[map[string]interface{}]().MaxSize(100).ItemsToPrune(10))
return &Executor{execCache: cache, timeout: timeout, podmanPath: podmanPath}
}

/**
* Cleans up the temp directory. Called on SIGINT and
* SIGTERM.
*/
func Cleanup() {
if err := os.RemoveAll(filepath.Join(".", "run")); err != nil {
log.Error("Could not clean up temp dir", "Error", err)
}
}

/**
* Runs the given code in a podman container. The code is
* dumped into a temp file, which is then mounted into the
* container.
*
* @param code string Code to run
* @param entry string Entry point for the container
* @param cArgs string Args for the interpreter or compiler
* @param ext string File extension of the code
* @param timeout int Timeout for execution
* @param enableCache bool Enable caching of exec results
* @return int HTTP status code
* @return map[string]interface{} Response body
*/
func (ex *Executor) RunCode(code, entry, cArgs, ext string, timeout int, enableCache bool) (int, map[string]interface{}) {
argsSlice := strings.Fields(cArgs)
for i, arg := range argsSlice {
Expand Down
6 changes: 6 additions & 0 deletions routes/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ import (
"whipcode/server"
)

/**
* Ping endpoint for health checks.
*
* @param w http.ResponseWriter Response writer
* @param _ *http.Request Request object
*/
func Ping(w http.ResponseWriter, _ *http.Request) {
server.Send(w, http.StatusOK, []byte("pong"), "text/plain")
}
15 changes: 15 additions & 0 deletions routes/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ import (
"whipcode/server"
)

/**
* Helper function for accepting a string or int value.
*
* @param l *StrInt StrInt object
* @param b []byte Byte array
* @return error Error object
*/
func (l *StrInt) UnmarshalJSON(b []byte) error {
var intValue int
if err := json.Unmarshal(b, &intValue); err == nil {
Expand All @@ -46,6 +53,14 @@ func (l *StrInt) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &l.value)
}

/**
* Run endpoint for running code in a container. This is
* the main endpoint for the application.
* Calls podman.RunCode
*
* @param w http.ResponseWriter Response writer
* @param r *http.Request Request object
*/
func Run(w http.ResponseWriter, r *http.Request) {
masterKey := r.Header.Get("X-Master-Key")

Expand Down
25 changes: 25 additions & 0 deletions server/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,20 @@ const (
ExecutorContextKey contextKey = "executor"
)

/**
* Middleware for the /run endpoint that caps the
* request body size and passes various parameters
* to the handler.
*
* @param f http.HandlerFunc Handler
* @param params ScopedMiddleWareParams Parameters
* @return http.HandlerFunc Handler
*/
func ScopedMiddleWare(f http.HandlerFunc, params ScopedMiddleWareParams) http.HandlerFunc {
/**
* @param w http.ResponseWriter Response writer
* @param r *http.Request Request object
*/
return func(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, int64(params.MaxBytesSize))

Expand All @@ -48,7 +61,19 @@ func ScopedMiddleWare(f http.HandlerFunc, params ScopedMiddleWareParams) http.Ha
}
}

/**
* Global middleware for all requests that performs
* rate limiting and host checks.
*
* @param handler http.Handler Handler
* @param params MiddleWareParams Parameters
* @return http.Handler Handler
*/
func MiddleWare(handler http.Handler, params MiddleWareParams) http.Handler {
/**
* @param w http.ResponseWriter - Response writer
* @param r *http.Request - Request object
*/
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
host, _, _ := net.SplitHostPort(r.RemoteAddr)
details := fmt.Sprintf("%s %s %s", host, r.Method, r.URL)
Expand Down
9 changes: 9 additions & 0 deletions server/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ import (
"github.com/charmbracelet/log"
)

/**
* Send sends a response to the client.
*
* @param w http.ResponseWriter Response writer
* @param status int Status code to return
* @param message []byte Message to send
* @param contentType ...string Content type to
* send, defaults to application/json
*/
func Send(w http.ResponseWriter, status int, message []byte, contentType ...string) {
cType := "application/json"
if len(contentType) > 0 {
Expand Down
10 changes: 10 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ import (
"github.com/charmbracelet/log"
)

/**
* Starts the server with the given port, handler, and
* TLS settings.
*
* @param port int Port to use
* @param handler http.Handler Handler to use
* @param enableTLS bool Whether to enable TLS
* @param tlsDir string Directory for the TLS files
* @param timeout int Configured execution timeout
*/
func StartServer(port int, handler http.Handler, enableTLS bool, tlsDir string, timeout int) {
log.Info("Starting whipcode", "Port", port, "TLS", enableTLS)

Expand Down
17 changes: 17 additions & 0 deletions utils/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ import (
"golang.org/x/crypto/argon2"
)

/**
* Generate a random string of a specified length.
*
* @param length int Length of the string
* @return string Random string
*/
func RandomString(length int) string {
bytes := make([]byte, length)
if _, err := rand.Read(bytes); err != nil {
Expand All @@ -37,6 +43,13 @@ func RandomString(length int) string {
return hex.EncodeToString(bytes)
}

/**
* Generate a form for the user to input the salt
* and key.
*
* @return string Salt
* @return string Key
*/
func KeyForm() (string, string) {
var salt string
var key string
Expand Down Expand Up @@ -65,6 +78,10 @@ func KeyForm() (string, string) {
return strings.TrimSpace(salt), strings.TrimSpace(key)
}

/**
* Generate a master key file with a salt and argon2
* hash of the key.
*/
func GenKey() {
salt, key := KeyForm()

Expand Down
12 changes: 12 additions & 0 deletions utils/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ import (
"github.com/fatih/color"
)

/**
* Generate a form for the user to input the master
* key and port.
*
* @return string Master key
* @return string Port
*/
func TestForm() (string, string) {
var key string
var port string
Expand Down Expand Up @@ -76,6 +83,11 @@ func TestForm() (string, string) {
return strings.TrimSpace(key), strings.TrimSpace(port)
}

/**
* Run the self-test for the application. This
* will send a request for each language to the
* server with a test payload.
*/
func SelfTest() {
key, port := TestForm()

Expand Down

0 comments on commit 370237e

Please sign in to comment.