sign.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package signer
  2. import (
  3. "archive/zip"
  4. "bytes"
  5. "crypto/sha256"
  6. "encoding/base64"
  7. "io"
  8. "strconv"
  9. "time"
  10. "github.com/langgenius/dify-plugin-daemon/internal/core/license/private_key"
  11. "github.com/langgenius/dify-plugin-daemon/internal/utils/encryption"
  12. "github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
  13. )
  14. /*
  15. DifyPlugin is a file type that represents a plugin, it's designed to based on zip file format.
  16. When signing a plugin, we use RSA-4096 to create a signature for the plugin and write the signature
  17. into comment field of the zip file.
  18. */
  19. // SignPlugin is a function that signs a plugin
  20. // It takes a plugin as a stream of bytes and signs it with RSA-4096
  21. func SignPlugin(plugin []byte) ([]byte, error) {
  22. // load private key
  23. private_key, err := encryption.LoadPrivateKey(private_key.PRIVATE_KEY)
  24. if err != nil {
  25. return nil, err
  26. }
  27. // construct zip
  28. zip_reader, err := zip.NewReader(bytes.NewReader(plugin), int64(len(plugin)))
  29. if err != nil {
  30. return nil, err
  31. }
  32. data := new(bytes.Buffer)
  33. // read one by one
  34. for _, file := range zip_reader.File {
  35. // read file bytes
  36. file_reader, err := file.Open()
  37. if err != nil {
  38. return nil, err
  39. }
  40. defer file_reader.Close()
  41. temp_data := new(bytes.Buffer)
  42. _, err = temp_data.ReadFrom(file_reader)
  43. if err != nil {
  44. return nil, err
  45. }
  46. // calculate sha256 hash of the file
  47. hash := sha256.New()
  48. hash.Write(temp_data.Bytes())
  49. hashed := hash.Sum(nil)
  50. // write the hash into data
  51. data.Write(hashed)
  52. }
  53. // get current time
  54. ct := time.Now().Unix()
  55. // convert time to bytes
  56. time_string := strconv.FormatInt(ct, 10)
  57. // write the time into data
  58. data.Write([]byte(time_string))
  59. // sign the data
  60. signature, err := encryption.RSASign(private_key, data.Bytes())
  61. if err != nil {
  62. return nil, err
  63. }
  64. // write the signature into the comment field of the zip file
  65. zip_buffer := new(bytes.Buffer)
  66. zip_writer := zip.NewWriter(zip_buffer)
  67. for _, file := range zip_reader.File {
  68. file_writer, err := zip_writer.Create(file.Name)
  69. if err != nil {
  70. return nil, err
  71. }
  72. file_reader, err := file.Open()
  73. if err != nil {
  74. return nil, err
  75. }
  76. defer file_reader.Close()
  77. _, err = io.Copy(file_writer, file_reader)
  78. if err != nil {
  79. return nil, err
  80. }
  81. }
  82. comments := parser.MarshalJson(map[string]string{
  83. "signature": base64.StdEncoding.EncodeToString(signature),
  84. "time": time_string,
  85. })
  86. // write signature
  87. err = zip_writer.SetComment(comments)
  88. if err != nil {
  89. return nil, err
  90. }
  91. // close the zip writer
  92. err = zip_writer.Close()
  93. if err != nil {
  94. return nil, err
  95. }
  96. return zip_buffer.Bytes(), nil
  97. }