Golang实现一个批量自动化执行树莓派指令的软件(1)文本加密&配置&命令行交互实现

发布于:2024-04-29 ⋅ 阅读:(31) ⋅ 点赞:(0)

简介

实现一个在配置文件设置信息,一运行就可以自动执行设定指令的软件。
这次实现的是 :
1. 加密解密模块, 用于加密密码, 在配置时配置已加密的密码就可以;
2. 需要配置,自然也就有配置文件的序列化反序列化;
3. 这么多操作如果都放到一个文件执行就需要命令行指令知道当前该执行的动作, 所以还有个命令行交互

环境描述

运行环境: Windows, 基于Golang, 暂时没有使用什么不可跨平台接口, 理论上支持Linux/MacOS
目标终端:树莓派DebianOS(主要做用它测试)

实现

加密解密

package utils

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"io"
)

type Encryption struct {
	Key []byte
}

func NewEncryption(key string) *Encryption {
	return &Encryption{Key: []byte(key)}
}

func (e *Encryption) Encrypt(text string) (string, error) {
	block, err := aes.NewCipher(e.Key)
	if err != nil {
		return "", err
	}
	textBytes := []byte(text)
	// 对于CBC模式,需要使用PKCS#7填充plaintext到blocksize的整数倍
	textBytes = e.pad(textBytes, aes.BlockSize)
	ciphertext := make([]byte, aes.BlockSize+len(textBytes))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return "", err
	}
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext[aes.BlockSize:], textBytes)
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

func (e *Encryption) Decrypt(text string) (string, error) {
	data, err := base64.StdEncoding.DecodeString(text)
	if err != nil {
		return "", err
	}
	block, err := aes.NewCipher(e.Key)
	if err != nil {
		return "", err
	}
	if len(data) < aes.BlockSize {
		return "", err
	}
	iv := data[:aes.BlockSize]
	data = data[aes.BlockSize:]
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(data, data)
	data = e.unpad(data, aes.BlockSize)
	return string(data), nil
}

// pad 使用PKCS#7标准填充数据
func (e *Encryption) pad(buf []byte, blockSize int) []byte {
	padding := blockSize - (len(buf) % blockSize)
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(buf, padtext...)
}

// unpad 移除PKCS#7标准填充的数据
func (e *Encryption) unpad(buf []byte, blockSize int) []byte {
	if len(buf)%blockSize != 0 {
		return nil
	}
	padding := int(buf[len(buf)-1])
	return buf[:len(buf)-padding]
}

配置

isettings.go

package utils

import (
	"errors"
)

type SettingsType int

const (
	SETTINGS_JSON SettingsType = 0
)

type ISettings interface {
	FromBytes(src []byte) error
	ToBytes() ([]byte, error)

	FromFile(filepath string) error
	ToFile(filepath string) error

	Data() interface{}
}

func NewSettings(typ SettingsType, model interface{}) (ISettings, error) {
	if nil == model {
		return nil, errors.New("model == nil")
	}
	switch typ {
	case SETTINGS_JSON:
		return NewJsonSettings(model)
	default:
		return nil, errors.New("wrong setting type")
	}
}

jsonsettings.go

package utils

import (
	"encoding/json"
	"os"
)

type JsonSettings struct {
	dat interface{}
}

func NewJsonSettings(v interface{}) (ISettings, error) {
	cfg := &JsonSettings{dat: v}
	return cfg, nil
}

func (c *JsonSettings) FromBytes(src []byte) error {
	return json.Unmarshal(src, c.dat)
}

func (c *JsonSettings) ToBytes() ([]byte, error) {
	return json.MarshalIndent(c.dat, "", "  ")
}

func (c *JsonSettings) FromFile(filepath string) error {
	bs, err := os.ReadFile(filepath)
	if nil != err {
		return err
	}
	err = c.FromBytes(bs)
	return err
}

func (c *JsonSettings) ToFile(filepath string) error {
	bs, err := c.ToBytes()
	if nil != err {
		return err
	}
	err = os.WriteFile(filepath, bs, 0666)

	return err
}

func (c *JsonSettings) Data() interface{} {
	return c.dat
}

命令行交互

package cmd

import (
	"github.com/spf13/cobra"
	"os"
)

var rootCommand = rootCmd()

/*
所有指令初始化
*/
func init() {
	rootCommand.AddCommand(runCmd())
	rootCommand.AddCommand(versionCmd())
	rootCommand.AddCommand(initCmd())
	rootCommand.AddCommand(encryptCmd())
}

func rootCmd() *cobra.Command {
	var cmd = &cobra.Command{
		Use:   "ssh_remote_access",
		Short: "SSH Remote Access Tool",
		Long:  "SSH Remote Access Tool, get help from https://listentome.blog.csdn.net/",
		Run:   rootRun,
	}
	cmd.Flags().BoolP("run", "r", false, "run job list")
	cmd.Flags().BoolP("init", "i", false, "initialize the tool")
	cmd.Flags().BoolP("version", "v", false, "get version")
	cmd.Flags().StringP("encrypt", "e", "", "encrypt the string")
	return cmd
}

func rootRun(cmd *cobra.Command, args []string) {
	var cmdStrings = []string{"run", "init", "version", "encrypt"}

	var matchCmd string
	for _, v := range cmdStrings {
		var flag = cmd.Flag(v)
		if flag != nil && flag.Changed {
			matchCmd = v
			break
		}
	}

	if matchCmd == "" {
		matchCmd = "help"
		cmd.Help()
		return
	}

	for _, v := range cmd.Commands() {
		if v.Name() == matchCmd {
			v.Run(cmd, args)
			return
		}
	}
}

func Execute() error {
	rootCommand.SetArgs(os.Args[1:])
	return rootCommand.Execute()
}

代码源

https://gitee.com/grayhsu/ssh_remote_access

其他

参考