sign_with_key.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package withkey
  2. import (
  3. "archive/zip"
  4. "bytes"
  5. "crypto/rsa"
  6. "crypto/sha256"
  7. "encoding/base64"
  8. "io"
  9. "path"
  10. "strconv"
  11. "time"
  12. "github.com/langgenius/dify-plugin-daemon/internal/utils/encryption"
  13. "github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
  14. "github.com/langgenius/dify-plugin-daemon/pkg/plugin_packager/decoder"
  15. )
  16. // SignPluginWithPrivateKey is a function that signs a plugin
  17. // It takes a plugin as a stream of bytes and a private key to sign it with RSA-4096
  18. func SignPluginWithPrivateKey(plugin []byte, privateKey *rsa.PrivateKey) ([]byte, error) {
  19. decoder, err := decoder.NewZipPluginDecoder(plugin)
  20. if err != nil {
  21. return nil, err
  22. }
  23. // create a new zip writer
  24. zipBuffer := new(bytes.Buffer)
  25. zipWriter := zip.NewWriter(zipBuffer)
  26. defer zipWriter.Close()
  27. // store temporary hash
  28. data := new(bytes.Buffer)
  29. // read one by one
  30. err = decoder.Walk(func(filename, dir string) error {
  31. file, err := decoder.ReadFile(path.Join(dir, filename))
  32. if err != nil {
  33. return err
  34. }
  35. // calculate sha256 hash of the file
  36. hash := sha256.New()
  37. hash.Write(file)
  38. hashed := hash.Sum(nil)
  39. // write the hash into data
  40. data.Write(hashed)
  41. // create a new file in the zip writer
  42. fileWriter, err := zipWriter.Create(path.Join(dir, filename))
  43. if err != nil {
  44. return err
  45. }
  46. _, err = io.Copy(fileWriter, bytes.NewReader(file))
  47. if err != nil {
  48. return err
  49. }
  50. return nil
  51. })
  52. if err != nil {
  53. return nil, err
  54. }
  55. // get current time
  56. ct := time.Now().Unix()
  57. // convert time to bytes
  58. timeString := strconv.FormatInt(ct, 10)
  59. // write the time into data
  60. data.Write([]byte(timeString))
  61. // sign the data
  62. signature, err := encryption.RSASign(privateKey, data.Bytes())
  63. if err != nil {
  64. return nil, err
  65. }
  66. // write the signature into the comment field of the zip file
  67. comments := parser.MarshalJson(map[string]any{
  68. "signature": base64.StdEncoding.EncodeToString(signature),
  69. "time": ct,
  70. })
  71. // write signature
  72. err = zipWriter.SetComment(comments)
  73. if err != nil {
  74. return nil, err
  75. }
  76. // close the zip writer
  77. err = zipWriter.Close()
  78. if err != nil {
  79. return nil, err
  80. }
  81. return zipBuffer.Bytes(), nil
  82. }