简介
实现一个在配置文件设置信息,一运行就可以自动执行设定指令的软件。
这次实现的是 :
1. 加密解密模块, 用于加密密码, 在配置时配置已加密的密码就可以;
2. 需要配置,自然也就有配置文件的序列化反序列化;
3. 这么多操作如果都放到一个文件执行就需要命令行指令知道当前该执行的动作, 所以还有个命令行交互
环境描述
运行环境 : Windows, 基于Golang, 暂时没有使用什么不可跨平台接口, 理论上支持Linux/MacOS
目标终端:树莓派DebianOS(主要做用它测试)
实现
加密解密
cpp
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
cpp
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
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
}
命令行交互
go
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