setup_endpoint.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package service
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/langgenius/dify-plugin-daemon/internal/core/dify_invocation"
  6. "github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager"
  7. "github.com/langgenius/dify-plugin-daemon/internal/db"
  8. "github.com/langgenius/dify-plugin-daemon/internal/service/install_service"
  9. "github.com/langgenius/dify-plugin-daemon/internal/types/exception"
  10. "github.com/langgenius/dify-plugin-daemon/internal/types/models"
  11. "github.com/langgenius/dify-plugin-daemon/internal/utils/cache/helper"
  12. "github.com/langgenius/dify-plugin-daemon/internal/utils/encryption"
  13. "github.com/langgenius/dify-plugin-daemon/pkg/entities"
  14. "github.com/langgenius/dify-plugin-daemon/pkg/entities/plugin_entities"
  15. )
  16. func SetupEndpoint(
  17. tenant_id string,
  18. user_id string,
  19. pluginUniqueIdentifier plugin_entities.PluginUniqueIdentifier,
  20. name string,
  21. settings map[string]any,
  22. ) *entities.Response {
  23. // try find plugin installation
  24. installation, err := db.GetOne[models.PluginInstallation](
  25. db.Equal("tenant_id", tenant_id),
  26. db.Equal("plugin_unique_identifier", pluginUniqueIdentifier.String()),
  27. )
  28. if err != nil {
  29. return exception.ErrPluginNotFound().ToResponse()
  30. }
  31. // try get plugin
  32. pluginDeclaration, err := helper.CombinedGetPluginDeclaration(
  33. pluginUniqueIdentifier,
  34. plugin_entities.PluginRuntimeType(installation.RuntimeType),
  35. )
  36. if err != nil {
  37. return exception.ErrPluginNotFound().ToResponse()
  38. }
  39. if !pluginDeclaration.Resource.Permission.AllowRegisterEndpoint() {
  40. return exception.PermissionDeniedError("permission denied, you need to enable endpoint access in plugin manifest").ToResponse()
  41. }
  42. if pluginDeclaration.Endpoint == nil {
  43. return exception.BadRequestError(errors.New("plugin does not have an endpoint")).ToResponse()
  44. }
  45. // check settings
  46. if err := plugin_entities.ValidateProviderConfigs(settings, pluginDeclaration.Endpoint.Settings); err != nil {
  47. return exception.BadRequestError(fmt.Errorf("failed to validate settings: %v", err)).ToResponse()
  48. }
  49. endpoint, err := install_service.InstallEndpoint(
  50. pluginUniqueIdentifier,
  51. installation.ID,
  52. tenant_id,
  53. user_id,
  54. name,
  55. map[string]any{},
  56. )
  57. if err != nil {
  58. return exception.InternalServerError(fmt.Errorf("failed to setup endpoint: %v", err)).ToResponse()
  59. }
  60. manager := plugin_manager.Manager()
  61. if manager == nil {
  62. return exception.InternalServerError(errors.New("failed to get plugin manager")).ToResponse()
  63. }
  64. // encrypt settings
  65. encryptedSettings, err := manager.BackwardsInvocation().InvokeEncrypt(
  66. &dify_invocation.InvokeEncryptRequest{
  67. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  68. TenantId: tenant_id,
  69. UserId: user_id,
  70. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  71. },
  72. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  73. Opt: dify_invocation.ENCRYPT_OPT_ENCRYPT,
  74. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  75. Identity: endpoint.ID,
  76. Data: settings,
  77. Config: pluginDeclaration.Endpoint.Settings,
  78. },
  79. },
  80. )
  81. if err != nil {
  82. return exception.InternalServerError(fmt.Errorf("failed to encrypt settings: %v", err)).ToResponse()
  83. }
  84. if err := install_service.UpdateEndpoint(endpoint, name, encryptedSettings); err != nil {
  85. return exception.InternalServerError(fmt.Errorf("failed to update endpoint: %v", err)).ToResponse()
  86. }
  87. return entities.NewSuccessResponse(true)
  88. }
  89. func RemoveEndpoint(endpoint_id string, tenant_id string) *entities.Response {
  90. endpoint, err := db.GetOne[models.Endpoint](
  91. db.Equal("id", endpoint_id),
  92. db.Equal("tenant_id", tenant_id),
  93. )
  94. if err != nil {
  95. return exception.NotFoundError(fmt.Errorf("failed to find endpoint: %v", err)).ToResponse()
  96. }
  97. err = install_service.UninstallEndpoint(&endpoint)
  98. if err != nil {
  99. return exception.InternalServerError(fmt.Errorf("failed to remove endpoint: %v", err)).ToResponse()
  100. }
  101. manager := plugin_manager.Manager()
  102. if manager == nil {
  103. return exception.InternalServerError(errors.New("failed to get plugin manager")).ToResponse()
  104. }
  105. // clear credentials cache
  106. if _, err := manager.BackwardsInvocation().InvokeEncrypt(&dify_invocation.InvokeEncryptRequest{
  107. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  108. TenantId: tenant_id,
  109. UserId: "",
  110. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  111. },
  112. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  113. Opt: dify_invocation.ENCRYPT_OPT_CLEAR,
  114. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  115. Identity: endpoint.ID,
  116. },
  117. }); err != nil {
  118. return exception.InternalServerError(fmt.Errorf("failed to clear credentials cache: %v", err)).ToResponse()
  119. }
  120. return entities.NewSuccessResponse(true)
  121. }
  122. func UpdateEndpoint(endpoint_id string, tenant_id string, user_id string, name string, settings map[string]any) *entities.Response {
  123. // get endpoint
  124. endpoint, err := db.GetOne[models.Endpoint](
  125. db.Equal("id", endpoint_id),
  126. db.Equal("tenant_id", tenant_id),
  127. )
  128. if err != nil {
  129. return exception.NotFoundError(fmt.Errorf("failed to find endpoint: %v", err)).ToResponse()
  130. }
  131. // get plugin installation
  132. installation, err := db.GetOne[models.PluginInstallation](
  133. db.Equal("plugin_id", endpoint.PluginID),
  134. db.Equal("tenant_id", tenant_id),
  135. )
  136. if err != nil {
  137. return exception.NotFoundError(fmt.Errorf("failed to find plugin installation: %v", err)).ToResponse()
  138. }
  139. pluginUniqueIdentifier, err := plugin_entities.NewPluginUniqueIdentifier(
  140. installation.PluginUniqueIdentifier,
  141. )
  142. if err != nil {
  143. return exception.UniqueIdentifierError(fmt.Errorf("failed to parse plugin unique identifier: %v", err)).ToResponse()
  144. }
  145. // get plugin
  146. pluginDeclaration, err := helper.CombinedGetPluginDeclaration(
  147. pluginUniqueIdentifier,
  148. plugin_entities.PluginRuntimeType(installation.RuntimeType),
  149. )
  150. if err != nil {
  151. return exception.ErrPluginNotFound().ToResponse()
  152. }
  153. if pluginDeclaration.Endpoint == nil {
  154. return exception.BadRequestError(errors.New("plugin does not have an endpoint")).ToResponse()
  155. }
  156. // decrypt original settings
  157. manager := plugin_manager.Manager()
  158. if manager == nil {
  159. return exception.InternalServerError(errors.New("failed to get plugin manager")).ToResponse()
  160. }
  161. originalSettings, err := manager.BackwardsInvocation().InvokeEncrypt(
  162. &dify_invocation.InvokeEncryptRequest{
  163. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  164. TenantId: tenant_id,
  165. UserId: user_id,
  166. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  167. },
  168. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  169. Opt: dify_invocation.ENCRYPT_OPT_DECRYPT,
  170. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  171. Identity: endpoint.ID,
  172. Data: endpoint.Settings,
  173. Config: pluginDeclaration.Endpoint.Settings,
  174. },
  175. },
  176. )
  177. if err != nil {
  178. return exception.InternalServerError(fmt.Errorf("failed to decrypt settings: %v", err)).ToResponse()
  179. }
  180. maskedSettings := encryption.MaskConfigCredentials(originalSettings, pluginDeclaration.Endpoint.Settings)
  181. // check if settings is changed, replace the value is the same as masked_settings
  182. for settingName, value := range settings {
  183. // skip it if the value is not secret-input
  184. found := false
  185. for _, config := range pluginDeclaration.Endpoint.Settings {
  186. if config.Name == settingName && config.Type == plugin_entities.CONFIG_TYPE_SECRET_INPUT {
  187. found = true
  188. break
  189. }
  190. }
  191. if !found {
  192. continue
  193. }
  194. if maskedSettings[settingName] == value {
  195. settings[settingName] = originalSettings[settingName]
  196. }
  197. }
  198. // check settings
  199. if err := plugin_entities.ValidateProviderConfigs(settings, pluginDeclaration.Endpoint.Settings); err != nil {
  200. return exception.BadRequestError(fmt.Errorf("failed to validate settings: %v", err)).ToResponse()
  201. }
  202. // encrypt settings
  203. encryptedSettings, err := manager.BackwardsInvocation().InvokeEncrypt(
  204. &dify_invocation.InvokeEncryptRequest{
  205. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  206. TenantId: tenant_id,
  207. UserId: user_id,
  208. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  209. },
  210. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  211. Opt: dify_invocation.ENCRYPT_OPT_ENCRYPT,
  212. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  213. Identity: endpoint.ID,
  214. Data: settings,
  215. Config: pluginDeclaration.Endpoint.Settings,
  216. },
  217. },
  218. )
  219. if err != nil {
  220. return exception.InternalServerError(fmt.Errorf("failed to encrypt settings: %v", err)).ToResponse()
  221. }
  222. // update endpoint
  223. if err := install_service.UpdateEndpoint(&endpoint, name, encryptedSettings); err != nil {
  224. return exception.InternalServerError(fmt.Errorf("failed to update endpoint: %v", err)).ToResponse()
  225. }
  226. // clear credentials cache
  227. if _, err := manager.BackwardsInvocation().InvokeEncrypt(&dify_invocation.InvokeEncryptRequest{
  228. BaseInvokeDifyRequest: dify_invocation.BaseInvokeDifyRequest{
  229. TenantId: tenant_id,
  230. UserId: user_id,
  231. Type: dify_invocation.INVOKE_TYPE_ENCRYPT,
  232. },
  233. InvokeEncryptSchema: dify_invocation.InvokeEncryptSchema{
  234. Opt: dify_invocation.ENCRYPT_OPT_CLEAR,
  235. Namespace: dify_invocation.ENCRYPT_NAMESPACE_ENDPOINT,
  236. Identity: endpoint.ID,
  237. Data: settings,
  238. Config: pluginDeclaration.Endpoint.Settings,
  239. },
  240. }); err != nil {
  241. return exception.InternalServerError(fmt.Errorf("failed to clear credentials cache: %v", err)).ToResponse()
  242. }
  243. return entities.NewSuccessResponse(true)
  244. }