feat: Add SHA256, SHA512 and SHA3 hash algos

This commit is contained in:
christiangoeschel 2025-03-30 03:02:25 -04:00
parent 52d469ed34
commit 0567c6e3eb
Signed by: christiangoeschel
GPG Key ID: 9C5DF8B5AF67BFB2
7 changed files with 190 additions and 49 deletions

View File

@ -1,4 +1,5 @@
.DEFAULT_GOAL := build
INSTALL_DIR ::= /usr/local/bin
.PHONY:fmt vet build
fmt:
@ -10,6 +11,9 @@ vet: fmt
build: vet
go build -o ./build/arrakis
install: build
sudo cp ./build/arrakis $(INSTALL_DIR)/
clean:
go clean
rm ./build/*

34
api/g10k.go Normal file
View File

@ -0,0 +1,34 @@
/*
Copyright © 2025 Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package api
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"os/exec"
)
func runG10K(c *gin.Context) {
fmt.Printf("Authorized call :)")
cmd := exec.Command("/usr/bin/touch", "/home/cgoesche/arrakis.txt")
cmd.Run()
c.JSON(http.StatusOK, gin.H{
"success": "Authorized :D",
"target": "g10k"})
}

View File

@ -26,11 +26,11 @@ import (
"net/http"
)
func SetupRouter(config *settings.Config) error {
func SetupRouter(config settings.Config) error {
router := gin.Default()
netAddr := config.ListenAddress + ":" + strconv.Itoa(config.ListenPort)
netAddr := config.Network.ListenAddress + ":" + strconv.Itoa(config.Network.ListenPort)
router.POST("/g10k", authWebhook(&config.Token))
router.POST("/g10k", authMiddleware(config.API.AuthMode, config.API.Token))
if err := startRouter(router, netAddr); err != nil {
return fmt.Errorf("Could not start router %s", err)
@ -43,8 +43,13 @@ func startRouter(r *gin.Engine, a string) error {
return r.Run(a)
}
func authWebhook(t *string) gin.HandlerFunc {
func authMiddleware(m bool, t string) gin.HandlerFunc {
return func(c *gin.Context) {
// authMode is false bypasses token check
if m == false {
runG10K(c)
return
}
authHeader := c.GetHeader("Authorization")
@ -62,10 +67,13 @@ func authWebhook(t *string) gin.HandlerFunc {
}
tokenString := authToken[1]
if tokenString != *(t) {
if tokenString != t {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})
c.AbortWithStatus(http.StatusUnauthorized)
return
}
runG10K(c)
}
}

View File

@ -22,18 +22,22 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var (
configFile string
netAddr string
port int
authMode bool
token string
debugMode bool
configFile string
netAddr string
port int
enableTLS bool
authMode bool
token string
tokenHashAlgo string
printHashAlgorithms bool
debugMode bool
config settings.Config
@ -44,6 +48,9 @@ var (
it is also a lightweight webhook API server that aims to handle webhooks triggered by
arbitrary Git repository events and, depending on the payload, perform user-defined actions.`,
Version: app.Version,
CompletionOptions: cobra.CompletionOptions{
HiddenDefaultCmd: true,
},
}
)
@ -58,19 +65,22 @@ func Execute() {
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().BoolVarP(&debugMode, "debug", "d", settings.SetDefault().Logging.DebugMode, "enable verbose output for debugging")
serverCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "configuration file to use")
serverCmd.PersistentFlags().StringVarP(&netAddr, "address", "a", settings.SetDefault().ListenAddress, "network address (e.g. 0.0.0.0)")
serverCmd.PersistentFlags().IntVarP(&port, "port", "p", settings.SetDefault().ListenPort, "port to listen on")
serverCmd.PersistentFlags().BoolVar(&authMode, "auth", settings.SetDefault().AuthMode, "enable verbose output for debugging")
serverCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "API token (implies --auth)")
serverCmd.PersistentFlags().BoolVarP(&debugMode, "debug", "d", settings.SetDefault().DebugMode, "enable verbose output for debugging")
// serverCmd.MarkFlagsRequiredTogether("auth", "token")
serverCmd.PersistentFlags().StringVarP(&netAddr, "address", "a", settings.SetDefault().Network.ListenAddress, "network address (e.g. 0.0.0.0)")
serverCmd.PersistentFlags().IntVarP(&port, "port", "p", settings.SetDefault().Network.ListenPort, "port to listen on")
serverCmd.PersistentFlags().BoolVarP(&enableTLS, "tls", "s", settings.SetDefault().Network.EnableTLS, "enable TLS")
serverCmd.PersistentFlags().BoolVar(&authMode, "auth", settings.SetDefault().API.AuthMode, "enable verbose output for debugging")
serverCmd.PersistentFlags().StringVarP(&token, "token", "t", settings.SetDefault().API.Token, "API token (implies --auth)")
tokenCmd.PersistentFlags().StringVarP(&tokenHashAlgo, "algorithm", "a", settings.SetDefault().API.TokenHashAlgorithm, "specify the token hashing algorithm")
viper.BindPFlag("address", serverCmd.PersistentFlags().Lookup("address"))
viper.BindPFlag("port", serverCmd.PersistentFlags().Lookup("port"))
viper.BindPFlag("debug", serverCmd.PersistentFlags().Lookup("debug"))
viper.BindPFlag("auth", serverCmd.PersistentFlags().Lookup("auth"))
viper.BindPFlag("token", serverCmd.PersistentFlags().Lookup("token"))
viper.BindPFlag("logging.debug", rootCmd.PersistentFlags().Lookup("debug"))
viper.BindPFlag("network.address", serverCmd.PersistentFlags().Lookup("address"))
viper.BindPFlag("network.port", serverCmd.PersistentFlags().Lookup("port"))
viper.BindPFlag("network.enableTLS", serverCmd.PersistentFlags().Lookup("tls"))
viper.BindPFlag("api.authMode", serverCmd.PersistentFlags().Lookup("auth"))
viper.BindPFlag("api.token", serverCmd.PersistentFlags().Lookup("token"))
viper.BindPFlag("api.tokenHashAlgorithm", tokenCmd.PersistentFlags().Lookup("algorithm"))
rootCmd.AddCommand(serverCmd)
rootCmd.AddCommand(tokenCmd)
@ -89,7 +99,7 @@ func initConfig() {
}
var configPath string
configPath = filepath.Join(configDir, "arrakis")
configPath = filepath.Join(configDir, app.Name)
viper.AddConfigPath(configPath)
viper.SetConfigType("yaml")
@ -98,6 +108,9 @@ func initConfig() {
viper.SetEnvPrefix(app.Name)
viper.AutomaticEnv()
// Needed so that the viper engine can map the right suboptions
// from the YAML configuration to the env
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
@ -108,8 +121,11 @@ func initConfig() {
os.Exit(1)
}
if authMode && config.Token == "" {
fmt.Printf("Token missing for auth mode")
if authMode && config.API.Token == "" {
fmt.Printf("API token missing for auth mode. Please ")
os.Exit(2)
} else if !authMode && config.API.Token != "" {
fmt.Printf("You have to enable authMode when using an API token")
os.Exit(2)
}
}

View File

@ -38,11 +38,9 @@ var serverCmd = &cobra.Command{
}
func serverStart() error {
if err := api.SetupRouter(&config); err != nil {
if err := api.SetupRouter(config); err != nil {
return err
}
fmt.Printf("Listening on Port: %d\n", config.ListenPort)
return nil
}

View File

@ -17,35 +17,94 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package cmd
import (
"fmt"
"crypto/rand"
"crypto/sha256"
"crypto/sha3"
"crypto/sha512"
"fmt"
"github.com/spf13/cobra"
"regexp"
)
var tokenCmd = &cobra.Command{
Use: "token",
Args: cobra.MatchAll(cobra.RangeArgs(0, 3), cobra.OnlyValidArgs),
Short: "Generate an API token",
Long: `When the --auth, -a is used at the command line
API calls will require an API Token.`,
Long: `When the --auth or -a flag is used at the command line
API calls will require an API Token either.`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := genToken(); err != nil {
if err := genToken(config.API.TokenHashAlgorithm); err != nil {
return fmt.Errorf("Error: %s", err)
}
return nil
},
}
func genToken() error {
s := "Random text to hash"
func genToken(a string) error {
var (
token string
err error
)
s := rand.Text()
sha3Pat := regexp.MustCompile(`^sha3-.*$`)
switch a {
case "sha256":
token, err = genSHA256(s)
case "sha512":
token, err = genSHA512(s)
default:
if sha3Pat.MatchString(a) {
token, err = genSHA3(s, a)
} else {
return fmt.Errorf("Unknown hash algorithm %s\n", a)
}
}
fmt.Printf(`Using %s to generate an API Token
Please store this in a safe location and do not share it with anyone
API Token:
%x
`, a, token)
return err
}
func genSHA256(s string) (string, error) {
h := sha256.New()
h.Write([]byte(s))
t := string(h.Sum(nil))
return t, nil
}
func genSHA512(s string) (string, error) {
h := sha512.New()
h.Write([]byte(s))
t := string(h.Sum(nil))
return t, nil
}
func genSHA3(s string, a string) (string, error) {
var h *sha3.SHA3
switch a {
case "sha3-224":
h = sha3.New224()
case "sha3-256":
h = sha3.New256()
case "sha3-384":
h = sha3.New384()
case "sha3-512":
h = sha3.New512()
default:
return "", fmt.Errorf("Unknown hash SHA3 algorithm size!")
}
h.Write([]byte(s))
t := string(h.Sum(nil))
bs := h.Sum(nil)
fmt.Printf(`Please store this in a safe location and do not share with anyone\n
API Token: %x`, bs)
return nil
return t, nil
}

View File

@ -16,20 +16,42 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package settings
type Config struct {
type Network struct {
ListenAddress string `mapstructure:"address"`
ListenPort int `mapstructure:"port"`
AuthMode bool `mapstructure:"auth"`
Token string `mapstructure:"token"`
DebugMode bool `mapstructure:"debug"`
EnableTLS bool `mapstructure:"enableTLS"`
}
type API struct {
AuthMode bool `mapstructure:"authMode"`
Token string `mapstructure:"token"`
TokenHashAlgorithm string `mapstructure:"tokenHashAlgorithm"`
}
type Logging struct {
DebugMode bool `mapstructure:"debug"`
}
type Config struct {
Network Network `mapstructure:"network"`
API API `mapstructure:"api"`
Logging Logging `mapstructure:"logging"`
}
func SetDefault() Config {
return Config{
ListenAddress: "127.0.0.1",
ListenPort: 8080,
AuthMode: false,
Token: "",
DebugMode: false,
Network: Network{
ListenAddress: "127.0.0.1",
ListenPort: 8080,
EnableTLS: false,
},
API: API{
AuthMode: false,
Token: "",
TokenHashAlgorithm: "sha256",
},
Logging: Logging{
DebugMode: false,
},
}
}