Files
Michael Wesemann 274f6a6905 [mike@mwxm4]
2026-05-22 11:31:52 +02:00

362 lines
11 KiB
Go

// ======================================================================================= go toolbox (mwx'2026)
package main
import (
"bufio"
"crypto/rand"
"database/sql"
"encoding/base64"
"flag"
"fmt"
"io"
"math/big"
"net"
"net/http"
"os"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/Masterminds/semver/v3"
"github.com/eknkc/basex"
"github.com/fatih/color"
"github.com/minio/selfupdate"
"github.com/spf13/viper"
"github.com/tidwall/gjson"
)
var tbversion = "0.5.0"
var CHRS = "VW9IdGJ6eXh1T25DRHdrc2M5MlhOQVNQcEJFWnJhWVY2ZEowaFJLdmoxNUdxVDRJZkZpTTdRZW0zTFc4Z2w="
var LR = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func checkforupdate(URL string) { // ----------------------------------------------------- check for new version
prg := prgname()
resp, err := http.Get(URL+"/version.txt")
if err == nil {
scanner := bufio.NewScanner(resp.Body)
if scanner.Scan() {
lversion := strings.TrimSpace(scanner.Text())
sv_version, err := semver.NewVersion(version)
if err == nil {
sv_lversion, err := semver.NewVersion(lversion)
if err == nil {
if (sv_lversion.GreaterThan(sv_version)) {
ans:=Yesno(SF("new '%s' version found (%s -> %s), update now?",
prg,sv_version,sv_lversion),true,false);
if (ans) {
updateurl:=SF("%s/%s_%s_%s_%s",URL,prg,lversion,runtime.GOOS,runtime.GOARCH)
if err := doupdate(updateurl); err != nil {
PO(SF("Update failed: %v\n", err))
os.Exit(1)
}
PO("Update successful!","please run your last command again")
os.Exit(0)
}
}
}
}
}
resp.Body.Close()
}
}
func doupdate(url string) error { // ----------------------------------------------------------------- do update
resp, err := http.Get(url)
if err != nil { return err }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { return fmt.Errorf("server returned status: %v", resp.Status) }
err = selfupdate.Apply(resp.Body, selfupdate.Options{})
if err != nil { return err }
return nil
}
func checkaccess(NETS []string) { // ------------------------------------------------- check ip net based access
match:=0;
for _, validnet := range NETS {
addrs, err := net.InterfaceAddrs()
if err != nil { PE("Error getting addresses"); os.Exit(1) }
_, ipNet, err := net.ParseCIDR(validnet)
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
if (ipNet.Contains(ipnet.IP)) { match++ }
}
}
}
}
if (match==0) { PE("access violation, permission denied"); os.Exit(1) }
}
func Enc(str string) string { // ----------------------------------------------------------------- encode string
enc, _ := basex.NewEncoding(Db64(CHRS))
return enc.Encode([]byte(Rndstr(2) + str))
}
func Dec(str string) string { // ----------------------------------------------------------------- decode string
enc, _ := basex.NewEncoding(Db64(CHRS))
b, _ := enc.Decode(str)
return string(b[2:])
}
func Db64(txt string) string { // ------------------------------------------------------------- string to base64
d, _ := base64.StdEncoding.DecodeString(txt)
return string(d)
}
func Rndstr(n int) string { // ------------------------------------------------------- random string with length
b := make([]rune, n)
for i := range b {
n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(LR))))
b[i] = LR[n.Int64()]
}
return string(b)
}
func Input(msg string, def string) string { // -------------------------------- AlecAivazis/survey: input string
tmp := ""
err := survey.AskOne(&survey.Input{Message: msg, Default: def}, &tmp)
if err != nil {
if err == terminal.InterruptErr {
P(Crb("Interrupted."))
os.Exit(0)
}
}
return tmp
}
func Inputpw(msg string) string { // ---------------------------------------- AlecAivazis/survey: input password
tmp := ""
err := survey.AskOne(&survey.Password{Message: msg}, &tmp)
if err != nil {
if err == terminal.InterruptErr {
P(Crb("Interrupted."))
os.Exit(0)
}
}
return tmp
}
func Yesno(msg string, def bool, overwrite bool) bool { // -------------------------- AlecAivazis/survey: yes/no
if (overwrite) { return true }
var err error
tmp := ""
if def {
err = survey.AskOne(&survey.Select{Message: msg, Options: []string{"Yes", "No"}}, &tmp)
} else {
err = survey.AskOne(&survey.Select{Message: msg, Options: []string{"No", "Yes"}}, &tmp)
}
if err != nil {
if err == terminal.InterruptErr {
P(Crb("Interrupted."))
os.Exit(0)
}
}
if tmp == "Yes" {
return true
} else {
return false
}
}
func Getid(n int) string { // --------------------------------------------------------- get base62 random string
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
ret := make([]byte, n)
for i := 0; i < n; i++ {
num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
ret[i] = letters[num.Int64()]
}
return string(ret)
}
func GETid(n int) string { // --------------------------------------------------------- get base36 random string
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ret := make([]byte, n)
for i := 0; i < n; i++ {
num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
ret[i] = letters[num.Int64()]
}
return string(ret)
}
func Mytable(rows *sql.Rows) []map[string]interface{} { // ----------------------------- load mysql result table
defer rows.Close()
columns, _ := rows.Columns()
count := len(columns)
tableData := make([]map[string]interface{}, 0)
values := make([]interface{}, count)
valuePtrs := make([]interface{}, count)
for rows.Next() {
for i := 0; i < count; i++ {
valuePtrs[i] = &values[i]
}
rows.Scan(valuePtrs...)
entry := make(map[string]interface{})
for i, col := range columns {
var v interface{}
val := values[i]
b, ok := val.([]byte)
if ok {
v = string(b)
} else {
v = val
}
entry[col] = v
}
tableData = append(tableData, entry)
}
return (tableData)
}
func Checkip(network string, ip string) bool { // ---------- check if ip is in range (cidr address or single ip)
if net.ParseIP(ip) == nil {
return false
}
_, subnet, err := net.ParseCIDR(network)
if err == nil {
if subnet.Contains(net.ParseIP(ip)) {
return true
}
} else {
if network == ip {
return true
}
}
return false
}
func Isflagpassed(name string) bool { // -------------------------------------------------- check if flag is set
found := false
flag.Visit(func(f *flag.Flag) {
if f.Name == name {
found = true
}
})
return found
}
func Body(r *http.Response) string { // ------------------------------------------------------------ http body
body, err := io.ReadAll(r.Body)
if err == nil {
return string(body)
}
return ""
}
func Atoi(s string) int { // ------------------------------------------------------------------------------ atoi
i, err := strconv.Atoi(s)
if err != nil {
return 0
}
return i
}
func Itoa(i int) string { // ------------------------------------------------------------------------------ itoa
return strconv.Itoa(i)
}
func GJA(j string, k string) []string { // -------------------------------------------------- convert gjson array
var ret []string
for _, c := range gjson.Get(j, k).Array() {
ret = append(ret, c.String())
}
return ret
}
// ------------------------------------------------------------------------------------------------ print simple
func P(a ...any) (n int, err error) { return fmt.Fprintln(os.Stdout, a...) }
func PN(a ...any) (n int, err error) { return fmt.Fprint(os.Stdout, a...) }
func PF(format string, a ...any) (n int, err error) { return fmt.Fprintf(os.Stdout, format, a...) }
func SF(format string, a ...any) string { return fmt.Sprintf(format, a...) }
func PE(msg ...string) (n int, err error) {
if (len(msg)==2) { return fmt.Fprintf(os.Stdout, "%s: %s (%s)\n", Crb("ERROR"), Cwb(msg[0]),msg[1]) }
return fmt.Fprintf(os.Stdout, "%s: %s\n", Crb("ERROR"), Cwb(msg[0]))
}
func PO(msg ...string) (n int, err error) {
if (len(msg)==2) { return fmt.Fprintf(os.Stdout, "%s: %s (%s)\n", Cgb("OK"), Cwb(msg[0]),msg[1]) }
return fmt.Fprintf(os.Stdout, "%s: %s\n", Cgb("OK"), Cwb(msg[0]))
}
// ------------------------------------------------------------------------------------------ regular expression
func ReplaceFirst(re *regexp.Regexp, str, replace string) string {
loc := re.FindStringIndex(str)
if loc == nil { return str }
return str[:loc[0]] + replace + str[loc[1]:]
}
// -------------------------------------------------------------------------------------------- string functions
func Shortstr(s string, length int) string {
runes := []rune(s)
if len(runes) <= length {
return s
}
return string(runes[:length-2]) + ".."
}
func SR(str string, n int) string { return strings.Repeat(str, n) }
func RemoveAllMatches(slice []string, target string) []string { // remove matching string from array
result := slice[:0]
for _, v := range slice {
if v != target {
result = append(result, v)
}
}
return result
}
// -------------------------------------------------------------------------------------------- system functions
func prgname() string { // program name
exepath, err := os.Executable()
if err != nil {
PE(SF("Error getting executable path: %s", err))
return ""
}
exename := filepath.Base(exepath)
return exename
}
// ------------------------------------------------------------------------------------------ viper abbrevations
func VX(key string) bool { return viper.IsSet(key) }
func VS(key string) string { return viper.GetString(key) }
func VSS(key string) []string { return viper.GetStringSlice(key) }
func VB(key string) bool { return viper.GetBool(key) }
func VI(key string) int { return viper.GetInt(key) }
// ------------------------------------------------------------------------------------------------- text colors
var Cr func(...interface{}) string = color.New(color.FgRed).SprintFunc()
var Cg func(...interface{}) string = color.New(color.FgGreen).SprintFunc()
var Cy func(...interface{}) string = color.New(color.FgYellow).SprintFunc()
var Cb func(...interface{}) string = color.New(color.FgBlue).SprintFunc()
var Cm func(...interface{}) string = color.New(color.FgMagenta).SprintFunc()
var Cc func(...interface{}) string = color.New(color.FgCyan).SprintFunc()
var Cw func(...interface{}) string = color.New(color.FgWhite).SprintFunc()
var Crb func(...interface{}) string = color.New(color.Bold, color.FgRed).SprintFunc()
var Cgb func(...interface{}) string = color.New(color.Bold, color.FgGreen).SprintFunc()
var Cyb func(...interface{}) string = color.New(color.Bold, color.FgYellow).SprintFunc()
var Cbb func(...interface{}) string = color.New(color.Bold, color.FgBlue).SprintFunc()
var Cmb func(...interface{}) string = color.New(color.Bold, color.FgMagenta).SprintFunc()
var Ccb func(...interface{}) string = color.New(color.Bold, color.FgCyan).SprintFunc()
var Cwb func(...interface{}) string = color.New(color.Bold, color.FgWhite).SprintFunc()
// ========================================================================================================= END