瀏覽代碼

feat: verifier

Yeuoly 1 年之前
父節點
當前提交
3772c09e0f

+ 46 - 0
cmd/license/verify/main.go

@@ -0,0 +1,46 @@
+package main
+
+import (
+	"flag"
+	"os"
+
+	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_packager/decoder"
+	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_packager/verifier"
+	"github.com/langgenius/dify-plugin-daemon/internal/utils/log"
+)
+
+func main() {
+	var (
+		in_path string
+		help    bool
+	)
+
+	flag.StringVar(&in_path, "in", "", "input plugin file path")
+	flag.BoolVar(&help, "help", false, "show help")
+	flag.Parse()
+
+	if help || in_path == "" {
+		flag.PrintDefaults()
+		os.Exit(0)
+	}
+
+	// read plugin
+	plugin, err := os.ReadFile(in_path)
+	if err != nil {
+		log.Panic("failed to read plugin file %v", err)
+	}
+
+	// decode
+	decoder, err := decoder.NewZipPluginDecoder(plugin)
+	if err != nil {
+		log.Panic("failed to create plugin decoder , plugin path: %s, error: %v", in_path, err)
+	}
+
+	// sign plugin
+	err = verifier.VerifyPlugin(decoder)
+	if err != nil {
+		log.Panic("failed to verify plugin %v", err)
+	}
+
+	log.Info("plugin verified successfully")
+}

+ 2 - 0
internal/core/plugin_packager/decoder/decoder.go

@@ -5,4 +5,6 @@ type PluginDecoder interface {
 	Walk(fn func(filename string, dir string) error) error
 	ReadFile(filename string) ([]byte, error)
 	Close() error
+	Signature() (string, error)
+	CreateTime() (int64, error)
 }

+ 8 - 0
internal/core/plugin_packager/decoder/fs.go

@@ -70,3 +70,11 @@ func (d *FSPluginDecoder) Close() error {
 func (d *FSPluginDecoder) ReadFile(filename string) ([]byte, error) {
 	return os.ReadFile(path.Join(d.root, filename))
 }
+
+func (d *FSPluginDecoder) Signature() (string, error) {
+	return "", nil
+}
+
+func (d *FSPluginDecoder) CreateTime() (int64, error) {
+	return 0, nil
+}

+ 63 - 0
internal/core/plugin_packager/decoder/zip.go

@@ -4,6 +4,8 @@ import (
 	"archive/zip"
 	"bytes"
 	"path"
+
+	"github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
 )
 
 type ZipPluginDecoder struct {
@@ -11,6 +13,9 @@ type ZipPluginDecoder struct {
 
 	reader *zip.Reader
 	err    error
+
+	sig         string
+	create_time int64
 }
 
 func NewZipPluginDecoder(binary []byte) (*ZipPluginDecoder, error) {
@@ -76,3 +81,61 @@ func (z *ZipPluginDecoder) ReadFile(filename string) ([]byte, error) {
 
 	return data.Bytes(), nil
 }
+
+func (z *ZipPluginDecoder) decode() error {
+	if z.reader == nil {
+		return z.err
+	}
+
+	type signatureData struct {
+		Signature string `json:"signature"`
+		Time      int64  `json:"time"`
+	}
+
+	signature_data, err := parser.UnmarshalJson[signatureData](z.reader.Comment)
+	if err != nil {
+		return err
+	}
+
+	plugin_sig := signature_data.Signature
+	plugin_time := signature_data.Time
+
+	z.sig = plugin_sig
+	z.create_time = plugin_time
+
+	return nil
+}
+
+func (z *ZipPluginDecoder) Signature() (string, error) {
+	if z.sig != "" {
+		return z.sig, nil
+	}
+
+	if z.reader == nil {
+		return "", z.err
+	}
+
+	err := z.decode()
+	if err != nil {
+		return "", err
+	}
+
+	return z.sig, nil
+}
+
+func (z *ZipPluginDecoder) CreateTime() (int64, error) {
+	if z.create_time != 0 {
+		return z.create_time, nil
+	}
+
+	if z.reader == nil {
+		return 0, z.err
+	}
+
+	err := z.decode()
+	if err != nil {
+		return 0, err
+	}
+
+	return z.create_time, nil
+}

+ 20 - 36
internal/core/plugin_packager/verifier/verifier.go

@@ -1,79 +1,63 @@
 package verifier
 
 import (
-	"archive/zip"
 	"bytes"
 	"crypto/sha256"
 	"encoding/base64"
+	"path"
 	"strconv"
 
 	"github.com/langgenius/dify-plugin-daemon/internal/core/license/public_key"
+	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_packager/decoder"
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/encryption"
-	"github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
 )
 
 // VerifyPlugin is a function that verifies the signature of a plugin
-// It takes a plugin as a stream of bytes and verifies the signature
-func VerifyPlugin(archive []byte) error {
+// It takes a plugin decoder and verifies the signature
+func VerifyPlugin(decoder decoder.PluginDecoder) error {
 	// load public key
 	public_key, err := encryption.LoadPublicKey(public_key.PUBLIC_KEY)
 	if err != nil {
 		return err
 	}
 
-	// construct zip
-	zip_reader, err := zip.NewReader(bytes.NewReader(archive), int64(len(archive)))
-	if err != nil {
-		return err
-	}
-
 	data := new(bytes.Buffer)
 	// read one by one
-	for _, file := range zip_reader.File {
+	err = decoder.Walk(func(filename, dir string) error {
 		// read file bytes
-		file_reader, err := file.Open()
-		if err != nil {
-			return err
-		}
-		defer file_reader.Close()
-
-		temp_data := new(bytes.Buffer)
-		_, err = temp_data.ReadFrom(file_reader)
+		file, err := decoder.ReadFile(path.Join(dir, filename))
 		if err != nil {
 			return err
 		}
 
 		hash := sha256.New()
-		hash.Write(temp_data.Bytes())
-		hashed := hash.Sum(nil)
+		hash.Write(file)
 
 		// write the hash into data
-		data.Write(hashed)
+		data.Write(hash.Sum(nil))
+		return nil
+	})
+
+	if err != nil {
+		return err
 	}
 
 	// get the signature
-	signature := zip_reader.Comment
-
-	type signatureData struct {
-		Signature string `json:"signature"`
-		Time      int64  `json:"time"`
+	signature, err := decoder.Signature()
+	if err != nil {
+		return err
 	}
 
-	signature_data, err := parser.UnmarshalJson[signatureData](signature)
+	// get the time
+	created_at, err := decoder.CreateTime()
 	if err != nil {
 		return err
 	}
 
-	plugin_sig := signature_data.Signature
-	plugin_time := signature_data.Time
-
-	// convert time to bytes
-	time_string := strconv.FormatInt(plugin_time, 10)
-
 	// write the time into data
-	data.Write([]byte(time_string))
+	data.Write([]byte(strconv.FormatInt(created_at, 10)))
 
-	sig_bytes, err := base64.StdEncoding.DecodeString(plugin_sig)
+	sig_bytes, err := base64.StdEncoding.DecodeString(signature)
 	if err != nil {
 		return err
 	}