setup_endpoint.go 9.3 KB

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