123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- package signer
- import (
- "archive/zip"
- "bytes"
- "crypto/sha256"
- "encoding/base64"
- "io"
- "strconv"
- "time"
- "github.com/langgenius/dify-plugin-daemon/internal/core/license/private_key"
- "github.com/langgenius/dify-plugin-daemon/internal/utils/encryption"
- "github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
- )
- /*
- DifyPlugin is a file type that represents a plugin, it's designed to based on zip file format.
- When signing a plugin, we use RSA-4096 to create a signature for the plugin and write the signature
- into comment field of the zip file.
- */
- // SignPlugin is a function that signs a plugin
- // It takes a plugin as a stream of bytes and signs it with RSA-4096
- func SignPlugin(plugin []byte) ([]byte, error) {
- // load private key
- private_key, err := encryption.LoadPrivateKey(private_key.PRIVATE_KEY)
- if err != nil {
- return nil, err
- }
- // construct zip
- zip_reader, err := zip.NewReader(bytes.NewReader(plugin), int64(len(plugin)))
- if err != nil {
- return nil, err
- }
- data := new(bytes.Buffer)
- // read one by one
- for _, file := range zip_reader.File {
- // read file bytes
- file_reader, err := file.Open()
- if err != nil {
- return nil, err
- }
- defer file_reader.Close()
- temp_data := new(bytes.Buffer)
- _, err = temp_data.ReadFrom(file_reader)
- if err != nil {
- return nil, err
- }
- // calculate sha256 hash of the file
- hash := sha256.New()
- hash.Write(temp_data.Bytes())
- hashed := hash.Sum(nil)
- // write the hash into data
- data.Write(hashed)
- }
- // get current time
- ct := time.Now().Unix()
- // convert time to bytes
- time_string := strconv.FormatInt(ct, 10)
- // write the time into data
- data.Write([]byte(time_string))
- // sign the data
- signature, err := encryption.RSASign(private_key, data.Bytes())
- if err != nil {
- return nil, err
- }
- // write the signature into the comment field of the zip file
- zip_buffer := new(bytes.Buffer)
- zip_writer := zip.NewWriter(zip_buffer)
- for _, file := range zip_reader.File {
- file_writer, err := zip_writer.Create(file.Name)
- if err != nil {
- return nil, err
- }
- file_reader, err := file.Open()
- if err != nil {
- return nil, err
- }
- defer file_reader.Close()
- _, err = io.Copy(file_writer, file_reader)
- if err != nil {
- return nil, err
- }
- }
- comments := parser.MarshalJson(map[string]any{
- "signature": base64.StdEncoding.EncodeToString(signature),
- "time": ct,
- })
- // write signature
- err = zip_writer.SetComment(comments)
- if err != nil {
- return nil, err
- }
- // close the zip writer
- err = zip_writer.Close()
- if err != nil {
- return nil, err
- }
- return zip_buffer.Bytes(), nil
- }
|