@smythos/sre 1.6.8 → 1.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/CHANGELOG +111 -111
  2. package/LICENSE +18 -18
  3. package/README.md +135 -135
  4. package/dist/bundle-analysis-lazy.html +4949 -0
  5. package/dist/bundle-analysis.html +4949 -0
  6. package/dist/index.js +2 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/types/Components/Triggers/Gmail.trigger.d.ts +58 -0
  9. package/dist/types/Components/Triggers/GmailTrigger.class.d.ts +44 -0
  10. package/dist/types/Components/Triggers/Trigger.class.d.ts +21 -0
  11. package/dist/types/Components/Triggers/WhatsApp.trigger.d.ts +22 -0
  12. package/dist/types/helpers/AIPerformanceAnalyzer.helper.d.ts +45 -0
  13. package/dist/types/helpers/AIPerformanceCollector.helper.d.ts +111 -0
  14. package/dist/types/subsystems/IO/Storage.service/connectors/AzureBlobStorage.class.d.ts +211 -0
  15. package/dist/types/subsystems/IO/VectorDB.service/connectors/WeaviateVectorDB.class.d.ts +187 -0
  16. package/dist/types/subsystems/PerformanceManager/Performance.service/PerformanceConnector.d.ts +102 -0
  17. package/dist/types/subsystems/PerformanceManager/Performance.service/connectors/LocalPerformanceConnector.class.d.ts +100 -0
  18. package/dist/types/subsystems/PerformanceManager/Performance.service/index.d.ts +22 -0
  19. package/dist/types/subsystems/Security/Credentials/Credentials.class.d.ts +2 -0
  20. package/dist/types/subsystems/Security/Credentials/ManagedOAuth2Credentials.class.d.ts +18 -0
  21. package/dist/types/subsystems/Security/Credentials/OAuth2Credentials.class.d.ts +14 -0
  22. package/dist/types/types/Performance.types.d.ts +468 -0
  23. package/dist/types/utils/package-manager.utils.d.ts +26 -0
  24. package/package.json +1 -1
  25. package/src/Components/APICall/APICall.class.ts +161 -161
  26. package/src/Components/APICall/AccessTokenManager.ts +166 -166
  27. package/src/Components/APICall/ArrayBufferResponse.helper.ts +58 -58
  28. package/src/Components/APICall/OAuth.helper.ts +447 -447
  29. package/src/Components/APICall/mimeTypeCategories.ts +46 -46
  30. package/src/Components/APICall/parseData.ts +167 -167
  31. package/src/Components/APICall/parseHeaders.ts +41 -41
  32. package/src/Components/APICall/parseProxy.ts +68 -68
  33. package/src/Components/APICall/parseUrl.ts +91 -91
  34. package/src/Components/APIEndpoint.class.ts +234 -234
  35. package/src/Components/APIOutput.class.ts +58 -58
  36. package/src/Components/AgentPlugin.class.ts +102 -102
  37. package/src/Components/Async.class.ts +155 -155
  38. package/src/Components/Await.class.ts +90 -90
  39. package/src/Components/Classifier.class.ts +158 -158
  40. package/src/Components/Component.class.ts +147 -147
  41. package/src/Components/ComponentHost.class.ts +38 -38
  42. package/src/Components/DataSourceCleaner.class.ts +92 -92
  43. package/src/Components/DataSourceIndexer.class.ts +181 -181
  44. package/src/Components/DataSourceLookup.class.ts +161 -161
  45. package/src/Components/ECMASandbox.class.ts +72 -72
  46. package/src/Components/FEncDec.class.ts +29 -29
  47. package/src/Components/FHash.class.ts +33 -33
  48. package/src/Components/FSign.class.ts +80 -80
  49. package/src/Components/FSleep.class.ts +25 -25
  50. package/src/Components/FTimestamp.class.ts +66 -66
  51. package/src/Components/FileStore.class.ts +78 -78
  52. package/src/Components/ForEach.class.ts +97 -97
  53. package/src/Components/GPTPlugin.class.ts +70 -70
  54. package/src/Components/GenAILLM.class.ts +586 -586
  55. package/src/Components/HuggingFace.class.ts +313 -313
  56. package/src/Components/Image/imageSettings.config.ts +70 -70
  57. package/src/Components/ImageGenerator.class.ts +483 -483
  58. package/src/Components/JSONFilter.class.ts +54 -54
  59. package/src/Components/LLMAssistant.class.ts +213 -213
  60. package/src/Components/LogicAND.class.ts +28 -28
  61. package/src/Components/LogicAtLeast.class.ts +85 -85
  62. package/src/Components/LogicAtMost.class.ts +86 -86
  63. package/src/Components/LogicOR.class.ts +29 -29
  64. package/src/Components/LogicXOR.class.ts +34 -34
  65. package/src/Components/MCPClient.class.ts +137 -137
  66. package/src/Components/MemoryDeleteKeyVal.class.ts +70 -70
  67. package/src/Components/MemoryReadKeyVal.class.ts +67 -67
  68. package/src/Components/MemoryWriteKeyVal.class.ts +62 -62
  69. package/src/Components/MemoryWriteObject.class.ts +97 -97
  70. package/src/Components/MultimodalLLM.class.ts +128 -128
  71. package/src/Components/OpenAPI.class.ts +72 -72
  72. package/src/Components/PromptGenerator.class.ts +122 -122
  73. package/src/Components/ScrapflyWebScrape.class.ts +183 -183
  74. package/src/Components/ServerlessCode.class.ts +123 -123
  75. package/src/Components/TavilyWebSearch.class.ts +103 -103
  76. package/src/Components/VisionLLM.class.ts +104 -104
  77. package/src/Components/ZapierAction.class.ts +127 -127
  78. package/src/Components/index.ts +97 -97
  79. package/src/Core/AgentProcess.helper.ts +240 -240
  80. package/src/Core/Connector.class.ts +123 -123
  81. package/src/Core/ConnectorsService.ts +197 -197
  82. package/src/Core/DummyConnector.ts +49 -49
  83. package/src/Core/HookService.ts +105 -105
  84. package/src/Core/SmythRuntime.class.ts +241 -241
  85. package/src/Core/SystemEvents.ts +16 -16
  86. package/src/Core/boot.ts +56 -56
  87. package/src/config.ts +15 -15
  88. package/src/constants.ts +126 -126
  89. package/src/data/hugging-face.params.json +579 -579
  90. package/src/helpers/AWSLambdaCode.helper.ts +624 -624
  91. package/src/helpers/BinaryInput.helper.ts +331 -331
  92. package/src/helpers/Conversation.helper.ts +1157 -1157
  93. package/src/helpers/ECMASandbox.helper.ts +64 -64
  94. package/src/helpers/JsonContent.helper.ts +97 -97
  95. package/src/helpers/LocalCache.helper.ts +97 -97
  96. package/src/helpers/Log.helper.ts +274 -274
  97. package/src/helpers/OpenApiParser.helper.ts +150 -150
  98. package/src/helpers/S3Cache.helper.ts +147 -147
  99. package/src/helpers/SmythURI.helper.ts +5 -5
  100. package/src/helpers/Sysconfig.helper.ts +95 -95
  101. package/src/helpers/TemplateString.helper.ts +243 -243
  102. package/src/helpers/TypeChecker.helper.ts +329 -329
  103. package/src/index.ts +3 -3
  104. package/src/index.ts.bak +3 -3
  105. package/src/subsystems/AgentManager/Agent.class.ts +1114 -1114
  106. package/src/subsystems/AgentManager/Agent.helper.ts +3 -3
  107. package/src/subsystems/AgentManager/AgentData.service/AgentDataConnector.ts +230 -230
  108. package/src/subsystems/AgentManager/AgentData.service/connectors/CLIAgentDataConnector.class.ts +66 -66
  109. package/src/subsystems/AgentManager/AgentData.service/connectors/LocalAgentDataConnector.class.ts +145 -145
  110. package/src/subsystems/AgentManager/AgentData.service/connectors/NullAgentData.class.ts +39 -39
  111. package/src/subsystems/AgentManager/AgentData.service/index.ts +18 -18
  112. package/src/subsystems/AgentManager/AgentLogger.class.ts +301 -301
  113. package/src/subsystems/AgentManager/AgentRequest.class.ts +51 -51
  114. package/src/subsystems/AgentManager/AgentRuntime.class.ts +557 -557
  115. package/src/subsystems/AgentManager/AgentSSE.class.ts +101 -101
  116. package/src/subsystems/AgentManager/AgentSettings.class.ts +52 -52
  117. package/src/subsystems/AgentManager/Component.service/ComponentConnector.ts +32 -32
  118. package/src/subsystems/AgentManager/Component.service/connectors/LocalComponentConnector.class.ts +60 -60
  119. package/src/subsystems/AgentManager/Component.service/index.ts +11 -11
  120. package/src/subsystems/AgentManager/EmbodimentSettings.class.ts +47 -47
  121. package/src/subsystems/AgentManager/ForkedAgent.class.ts +154 -154
  122. package/src/subsystems/AgentManager/OSResourceMonitor.ts +77 -77
  123. package/src/subsystems/ComputeManager/Code.service/CodeConnector.ts +98 -98
  124. package/src/subsystems/ComputeManager/Code.service/connectors/AWSLambdaCode.class.ts +171 -171
  125. package/src/subsystems/ComputeManager/Code.service/connectors/ECMASandbox.class.ts +131 -131
  126. package/src/subsystems/ComputeManager/Code.service/index.ts +13 -13
  127. package/src/subsystems/IO/CLI.service/CLIConnector.ts +47 -47
  128. package/src/subsystems/IO/CLI.service/index.ts +9 -9
  129. package/src/subsystems/IO/Log.service/LogConnector.ts +32 -32
  130. package/src/subsystems/IO/Log.service/connectors/ConsoleLog.class.ts +28 -28
  131. package/src/subsystems/IO/Log.service/index.ts +13 -13
  132. package/src/subsystems/IO/NKV.service/NKVConnector.ts +43 -43
  133. package/src/subsystems/IO/NKV.service/connectors/NKVLocalStorage.class.ts +234 -234
  134. package/src/subsystems/IO/NKV.service/connectors/NKVRAM.class.ts +204 -204
  135. package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +182 -182
  136. package/src/subsystems/IO/NKV.service/index.ts +14 -14
  137. package/src/subsystems/IO/Router.service/RouterConnector.ts +21 -21
  138. package/src/subsystems/IO/Router.service/connectors/ExpressRouter.class.ts +48 -48
  139. package/src/subsystems/IO/Router.service/connectors/NullRouter.class.ts +40 -40
  140. package/src/subsystems/IO/Router.service/index.ts +11 -11
  141. package/src/subsystems/IO/Storage.service/SmythFS.class.ts +488 -488
  142. package/src/subsystems/IO/Storage.service/StorageConnector.ts +66 -66
  143. package/src/subsystems/IO/Storage.service/connectors/LocalStorage.class.ts +327 -327
  144. package/src/subsystems/IO/Storage.service/connectors/S3Storage.class.ts +482 -482
  145. package/src/subsystems/IO/Storage.service/index.ts +13 -13
  146. package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +108 -108
  147. package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +465 -465
  148. package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +387 -387
  149. package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +408 -408
  150. package/src/subsystems/IO/VectorDB.service/embed/BaseEmbedding.ts +107 -107
  151. package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +118 -118
  152. package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +109 -109
  153. package/src/subsystems/IO/VectorDB.service/embed/index.ts +26 -26
  154. package/src/subsystems/IO/VectorDB.service/index.ts +14 -14
  155. package/src/subsystems/LLMManager/LLM.helper.ts +251 -251
  156. package/src/subsystems/LLMManager/LLM.inference.ts +345 -345
  157. package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +492 -492
  158. package/src/subsystems/LLMManager/LLM.service/LLMCredentials.helper.ts +171 -171
  159. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +666 -666
  160. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +407 -407
  161. package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +92 -92
  162. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +983 -983
  163. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +319 -319
  164. package/src/subsystems/LLMManager/LLM.service/connectors/Ollama.class.ts +361 -361
  165. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +257 -257
  166. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +430 -430
  167. package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +503 -503
  168. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +524 -524
  169. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.ts +100 -100
  170. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterfaceFactory.ts +81 -81
  171. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +1145 -1145
  172. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.ts +13 -13
  173. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/index.ts +4 -4
  174. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/utils.ts +11 -11
  175. package/src/subsystems/LLMManager/LLM.service/connectors/openai/types.ts +32 -32
  176. package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +478 -478
  177. package/src/subsystems/LLMManager/LLM.service/index.ts +47 -47
  178. package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +303 -303
  179. package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +280 -271
  180. package/src/subsystems/LLMManager/ModelsProvider.service/index.ts +11 -11
  181. package/src/subsystems/LLMManager/custom-models.ts +854 -854
  182. package/src/subsystems/LLMManager/models.ts +2540 -2540
  183. package/src/subsystems/LLMManager/paramMappings.ts +69 -69
  184. package/src/subsystems/MemoryManager/Cache.service/CacheConnector.ts +86 -86
  185. package/src/subsystems/MemoryManager/Cache.service/connectors/LocalStorageCache.class.ts +297 -297
  186. package/src/subsystems/MemoryManager/Cache.service/connectors/RAMCache.class.ts +214 -214
  187. package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +252 -252
  188. package/src/subsystems/MemoryManager/Cache.service/connectors/S3Cache.class.ts +373 -373
  189. package/src/subsystems/MemoryManager/Cache.service/index.ts +15 -15
  190. package/src/subsystems/MemoryManager/LLMCache.ts +72 -72
  191. package/src/subsystems/MemoryManager/LLMContext.ts +124 -124
  192. package/src/subsystems/MemoryManager/LLMMemory.service/LLMMemoryConnector.ts +26 -26
  193. package/src/subsystems/MemoryManager/RuntimeContext.ts +277 -277
  194. package/src/subsystems/Security/AccessControl/ACL.class.ts +208 -208
  195. package/src/subsystems/Security/AccessControl/AccessCandidate.class.ts +82 -82
  196. package/src/subsystems/Security/AccessControl/AccessRequest.class.ts +52 -52
  197. package/src/subsystems/Security/Account.service/AccountConnector.ts +44 -44
  198. package/src/subsystems/Security/Account.service/connectors/DummyAccount.class.ts +130 -130
  199. package/src/subsystems/Security/Account.service/connectors/JSONFileAccount.class.ts +170 -170
  200. package/src/subsystems/Security/Account.service/connectors/MySQLAccount.class.ts +76 -76
  201. package/src/subsystems/Security/Account.service/index.ts +14 -14
  202. package/src/subsystems/Security/Credentials.helper.ts +62 -62
  203. package/src/subsystems/Security/ManagedVault.service/ManagedVaultConnector.ts +38 -38
  204. package/src/subsystems/Security/ManagedVault.service/connectors/NullManagedVault.class.ts +53 -53
  205. package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +154 -154
  206. package/src/subsystems/Security/ManagedVault.service/index.ts +12 -12
  207. package/src/subsystems/Security/SecureConnector.class.ts +110 -110
  208. package/src/subsystems/Security/Vault.service/Vault.helper.ts +30 -30
  209. package/src/subsystems/Security/Vault.service/VaultConnector.ts +29 -29
  210. package/src/subsystems/Security/Vault.service/connectors/HashicorpVault.class.ts +46 -46
  211. package/src/subsystems/Security/Vault.service/connectors/JSONFileVault.class.ts +221 -221
  212. package/src/subsystems/Security/Vault.service/connectors/NullVault.class.ts +54 -54
  213. package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +140 -140
  214. package/src/subsystems/Security/Vault.service/index.ts +12 -12
  215. package/src/types/ACL.types.ts +104 -104
  216. package/src/types/AWS.types.ts +10 -10
  217. package/src/types/Agent.types.ts +61 -61
  218. package/src/types/AgentLogger.types.ts +17 -17
  219. package/src/types/Cache.types.ts +1 -1
  220. package/src/types/Common.types.ts +2 -2
  221. package/src/types/LLM.types.ts +520 -520
  222. package/src/types/Redis.types.ts +8 -8
  223. package/src/types/SRE.types.ts +64 -64
  224. package/src/types/Security.types.ts +14 -14
  225. package/src/types/Storage.types.ts +5 -5
  226. package/src/types/VectorDB.types.ts +86 -86
  227. package/src/utils/base64.utils.ts +275 -275
  228. package/src/utils/cli.utils.ts +68 -68
  229. package/src/utils/data.utils.ts +322 -322
  230. package/src/utils/date-time.utils.ts +22 -22
  231. package/src/utils/general.utils.ts +238 -238
  232. package/src/utils/index.ts +12 -12
  233. package/src/utils/lazy-client.ts +261 -261
  234. package/src/utils/numbers.utils.ts +13 -13
  235. package/src/utils/oauth.utils.ts +35 -35
  236. package/src/utils/string.utils.ts +414 -414
  237. package/src/utils/url.utils.ts +19 -19
  238. package/src/utils/validation.utils.ts +74 -74
  239. package/dist/types/subsystems/LLMManager/ModelsProvider.service/connectors/SmythModelsProvider.class.d.ts +0 -39
@@ -1,447 +1,447 @@
1
- // helper.ts
2
- import crypto from 'crypto';
3
- import OAuth from 'oauth-1.0a';
4
- import AccessTokenManager from './AccessTokenManager';
5
- import { REQUEST_CONTENT_TYPES } from '@sre/constants';
6
- import axios, { AxiosRequestConfig } from 'axios';
7
- import { Logger } from '@sre/helpers/Log.helper';
8
- import { ConnectorService } from '@sre/Core/ConnectorsService';
9
- import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
10
- import { TemplateString } from '@sre/helpers/TemplateString.helper';
11
- import { SystemEvents } from '@sre/Core/SystemEvents';
12
-
13
- const console = Logger('OAuth.helper');
14
- let managedVault: any;
15
-
16
- SystemEvents.on('SRE:Booted', () => {
17
- try {
18
- managedVault = ConnectorService.getManagedVaultConnector();
19
- } catch (error) {
20
- console.warn('Could not find a compatible ManagedVault connector, OAuth APICalls will not work');
21
- }
22
- });
23
-
24
- export function extractAdditionalParamsForOAuth1(reqConfig: AxiosRequestConfig = {}) {
25
- let additionalParams = {};
26
-
27
- // Validate URL doesn't contain unresolved template variables
28
- if (reqConfig.url && (reqConfig.url.includes('{{') || reqConfig.url.includes('${{'))) {
29
- console.warn('Warning: URL contains unresolved template variables for OAuth1 signature:', reqConfig.url);
30
- }
31
-
32
- // Parse URL parameters
33
- try {
34
- const url = new URL(reqConfig.url);
35
- const searchParams = url.searchParams;
36
- additionalParams = Object.fromEntries(searchParams.entries());
37
-
38
- // Log if we have query parameters for debugging
39
- if (searchParams.toString()) {
40
- console.debug('OAuth1: Found query parameters:', Object.keys(additionalParams));
41
- }
42
- } catch (error) {
43
- console.warn('Failed to parse URL for OAuth1 parameters:', error);
44
- }
45
-
46
- // Get the content type, handling different header formats
47
- const headers = reqConfig.headers || {};
48
- let contentType = '';
49
-
50
- // Headers might be an object or array of objects
51
- if (Array.isArray(headers)) {
52
- const contentTypeHeader = headers.find(h =>
53
- Object.keys(h).some(k => k.toLowerCase() === 'content-type')
54
- );
55
- if (contentTypeHeader) {
56
- const key = Object.keys(contentTypeHeader).find(k => k.toLowerCase() === 'content-type');
57
- contentType = contentTypeHeader[key];
58
- }
59
- } else {
60
- contentType = headers['Content-Type'] || headers['content-type'] || '';
61
- }
62
-
63
- // Extract body parameters based on content type
64
- const method = (reqConfig.method || 'GET').toUpperCase();
65
-
66
- if (contentType.includes(REQUEST_CONTENT_TYPES.urlEncodedFormData)) {
67
- // For form data, include the form parameters in the signature
68
- if (reqConfig.data) {
69
- let formParams = {};
70
- if (typeof reqConfig.data === 'string') {
71
- // Check for unresolved template variables in form data
72
- if (reqConfig.data.includes('{{') || reqConfig.data.includes('${{')) {
73
- console.warn('Warning: Form data contains unresolved template variables for OAuth1 signature');
74
- }
75
- const formData = new URLSearchParams(reqConfig.data);
76
- formParams = Object.fromEntries(formData.entries());
77
- } else if (reqConfig.data instanceof URLSearchParams) {
78
- formParams = Object.fromEntries(reqConfig.data.entries());
79
- } else if (typeof reqConfig.data === 'object') {
80
- // Handle plain object
81
- formParams = reqConfig.data;
82
- }
83
- console.debug('OAuth1: Including form parameters in signature:', Object.keys(formParams));
84
- additionalParams = { ...additionalParams, ...formParams };
85
- }
86
- } else if (contentType.includes(REQUEST_CONTENT_TYPES.json) ||
87
- contentType.includes('application/') ||
88
- contentType.includes('text/')) {
89
- // For JSON and other non-form data, use oauth_body_hash
90
- if (reqConfig.data && method !== 'GET' && method !== 'HEAD') {
91
- let bodyString = '';
92
- if (typeof reqConfig.data === 'string') {
93
- bodyString = reqConfig.data;
94
- } else {
95
- bodyString = JSON.stringify(reqConfig.data);
96
- }
97
- // Check for unresolved template variables
98
- if (bodyString.includes('{{') || bodyString.includes('${{')) {
99
- console.warn('Warning: Request body contains unresolved template variables for OAuth1 signature');
100
- }
101
- const hash = crypto.createHash('sha1').update(bodyString).digest('base64');
102
- additionalParams['oauth_body_hash'] = hash;
103
- console.debug('OAuth1: Added oauth_body_hash for', contentType);
104
- }
105
- } else if (contentType.includes(REQUEST_CONTENT_TYPES.multipartFormData)) {
106
- // For multipart form data, only include text fields
107
- if (reqConfig.data && typeof reqConfig.data === 'object' && 'entries' in reqConfig.data) {
108
- const formData = reqConfig.data as FormData;
109
- for (const [key, value] of formData.entries()) {
110
- // Only include string values, exclude Files/Blobs
111
- if (typeof value === 'string') {
112
- additionalParams[key] = value;
113
- } else if (typeof value === 'object' && value !== null &&
114
- ('size' in value || 'type' in value)) {
115
- // Skip binary data (Files, Blobs, etc.)
116
- continue;
117
- } else {
118
- // Include other simple values
119
- additionalParams[key] = String(value);
120
- }
121
- }
122
- }
123
- } else if (!contentType && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
124
- // No content type specified but has data
125
- if (reqConfig.data) {
126
- const bodyString = typeof reqConfig.data === 'string' ?
127
- reqConfig.data : JSON.stringify(reqConfig.data);
128
- const hash = crypto.createHash('sha1').update(bodyString).digest('base64');
129
- additionalParams['oauth_body_hash'] = hash;
130
- }
131
- }
132
-
133
- console.debug('OAuth1: Total parameters for signature:', Object.keys(additionalParams).length);
134
- return additionalParams;
135
- }
136
-
137
- export const buildOAuth1Header = (url, method, oauth1Credentials, additionalParams = {}) => {
138
- const oauth = new OAuth({
139
- consumer: {
140
- key: oauth1Credentials.consumerKey,
141
- secret: oauth1Credentials.consumerSecret,
142
- },
143
- signature_method: 'HMAC-SHA1',
144
- hash_function(base_string, key) {
145
- return crypto.createHmac('sha1', key).update(base_string).digest('base64');
146
- },
147
- });
148
-
149
- // OAuth1 requires the base URL without query parameters for signature
150
- // The query parameters should be included separately in additionalParams
151
- let baseUrl = url;
152
- try {
153
- const urlObj = new URL(url);
154
- // Remove query parameters from URL for signature base
155
- baseUrl = `${urlObj.protocol}//${urlObj.host}${urlObj.pathname}`;
156
- console.debug('OAuth1: Base URL for signature:', baseUrl);
157
- } catch (error) {
158
- console.warn('Failed to parse URL for OAuth1 signature:', error);
159
- }
160
-
161
- // Include additional parameters in the request data
162
- const requestData = {
163
- url: baseUrl,
164
- method: method.toUpperCase(),
165
- data: additionalParams, // Parameters should be in data field for oauth-1.0a library
166
- };
167
-
168
- const token = oauth1Credentials.token && oauth1Credentials.token !== '' ?
169
- { key: oauth1Credentials.token, secret: oauth1Credentials.tokenSecret || '' } :
170
- null;
171
-
172
- const signedRequest = oauth.authorize(requestData, token);
173
- return oauth.toHeader(signedRequest);
174
- };
175
-
176
- export const retrieveOAuthTokens = async (agent, config) => {
177
- let tokenKey: any = null;
178
- try {
179
- // To support both old and new OAuth configuration, we check for both oauth_con_id and config.id (component id)
180
- tokenKey = config?.data?.oauth_con_id || `OAUTH_${config?.id}_TOKENS`;
181
-
182
- try {
183
- const result: any = await managedVault.user(AccessCandidate.agent(agent.id)).get(tokenKey);
184
- const tokensData = typeof result === 'object' ? result : JSON.parse(result || '{}');
185
-
186
- if (!tokensData) {
187
- throw new Error('Failed to retrieve OAuth tokens from vault. Please authenticate ...');
188
- }
189
-
190
- // Check if it's new structure (has auth_data and auth_settings) or old structure
191
- const isNewStructure = tokensData.auth_data !== undefined && tokensData.auth_settings !== undefined;
192
-
193
- // Extract tokens based on structure
194
- const primaryToken = isNewStructure
195
- ? tokensData.auth_data?.primary
196
- : tokensData.primary;
197
- const secondaryToken = isNewStructure
198
- ? tokensData.auth_data?.secondary
199
- : tokensData.secondary;
200
- const expiresIn = isNewStructure
201
- ? tokensData.auth_data?.expires_in
202
- : tokensData.expires_in;
203
-
204
- // Extract settings based on structure
205
- const type = isNewStructure
206
- ? tokensData.auth_settings?.type
207
- : (tokensData.type || tokensData.oauth_info?.type);
208
- const service = isNewStructure
209
- ? tokensData.auth_settings?.service
210
- : tokensData.oauth_info?.service;
211
-
212
- // Add warning logs for OAuth2
213
- if (type === 'oauth2' && service !== 'oauth2_client_credentials') {
214
- if (!secondaryToken) {
215
- console.warn('Warning: refresh_token is missing for OAuth2');
216
- }
217
- if (!expiresIn) {
218
- console.warn('Warning: expires_in is missing for OAuth2.');
219
- }
220
- }
221
-
222
- // sometimes refreshToken is not available . e.g in case of linkedIn. so only add check for primary token
223
- if (service !== 'oauth2_client_credentials') {
224
- if (!primaryToken) {
225
- throw new Error('Retrieved OAuth tokens do not exist, invalid OR incomplete. Please authenticate ...');
226
- }
227
- }
228
-
229
- const responseData: any = {
230
- primaryToken,
231
- secondaryToken,
232
- type,
233
- service,
234
- };
235
-
236
- if (type === 'oauth') {
237
- // Extract OAuth1 credentials based on structure
238
- if (isNewStructure) {
239
- responseData.consumerKey = tokensData.auth_settings?.consumerKey;
240
- responseData.consumerSecret = tokensData.auth_settings?.consumerSecret;
241
- responseData.tokenURL = tokensData.auth_settings?.tokenURL;
242
- } else {
243
- responseData.consumerKey = tokensData.consumerKey || tokensData.oauth_info?.consumerKey;
244
- responseData.consumerSecret = tokensData.consumerSecret || tokensData.oauth_info?.consumerSecret;
245
- responseData.tokenURL = tokensData.tokenURL || tokensData.oauth_info?.tokenURL;
246
- }
247
- responseData.team = tokensData.team || agent.teamId;
248
- } else if (type === 'oauth2') {
249
- // Extract OAuth2 credentials based on structure
250
- if (isNewStructure) {
251
- responseData.tokenURL = tokensData.auth_settings?.tokenURL;
252
- responseData.clientID = tokensData.auth_settings?.clientID;
253
- responseData.clientSecret = tokensData.auth_settings?.clientSecret;
254
- } else {
255
- responseData.tokenURL = tokensData.tokenURL || tokensData.oauth_info?.tokenURL;
256
- responseData.clientID = tokensData.clientID || tokensData.oauth_info?.clientID;
257
- responseData.clientSecret = tokensData.clientSecret || tokensData.oauth_info?.clientSecret;
258
- }
259
- responseData.expiresIn = expiresIn ?? 0; // Optional property, default to 0 if not present
260
- responseData.team = tokensData.team || agent.teamId;
261
- }
262
-
263
- return { responseData, tokensData, keyId: tokenKey, isNewStructure };
264
- } catch (error) {
265
- throw new Error(`Failed to parse retrieved tokens: ${error}`);
266
- }
267
- } catch (error) {
268
- console.error('Error retrieving OAuth tokens:', error);
269
- throw error; // rethrow for potential handling by the calling code
270
- }
271
- };
272
-
273
- export const handleOAuthHeaders = async (agent, config, reqConfig, logger, additionalParams = {}) => {
274
- let headers = {}; // Initialize headers as an empty object
275
- const { responseData: oauthTokens, tokensData, keyId, isNewStructure } = await retrieveOAuthTokens(agent, config);
276
-
277
- try {
278
- // Build OAuth config string with template support
279
- let oAuthConfigString = JSON.stringify({
280
- consumerKey: oauthTokens.consumerKey || '',
281
- consumerSecret: oauthTokens.consumerSecret || '',
282
- clientID: oauthTokens.clientID || '',
283
- clientSecret: oauthTokens.clientSecret || '',
284
- tokenURL: oauthTokens.tokenURL || '',
285
- });
286
-
287
- oAuthConfigString = await TemplateString(oAuthConfigString).parseTeamKeysAsync(oauthTokens.team || agent.teamId).asyncResult;
288
-
289
- const oAuthConfig = JSON.parse(oAuthConfigString);
290
- // Avoid logging sensitive OAuth config in plaintext
291
- // console.log('oAuthConfig', { ...oAuthConfig, clientSecret: '***' });
292
- if (oauthTokens.service === 'oauth2_client_credentials') {
293
- const accessToken = await getClientCredentialToken(tokensData, logger, keyId, oauthTokens, config, agent, isNewStructure);
294
- headers['Authorization'] = `Bearer ${accessToken}`;
295
- } else {
296
- if (oauthTokens.type === 'oauth') {
297
- // For OAuth1, generate and replace the signature in headers
298
- // Use the full URL (with path but without query params) for OAuth1
299
- const oauthHeader = buildOAuth1Header(
300
- reqConfig.url,
301
- reqConfig.method,
302
- {
303
- consumerKey: oAuthConfig.consumerKey,
304
- consumerSecret: oAuthConfig.consumerSecret,
305
- token: oauthTokens.primaryToken,
306
- tokenSecret: oauthTokens.secondaryToken,
307
- },
308
- additionalParams
309
- );
310
-
311
- headers = { ...reqConfig.headers, ...oauthHeader };
312
- logger.debug('OAuth1 access token check success.');
313
- } else if (oauthTokens.type === 'oauth2') {
314
- // For OAuth2, add the 'Authorization' header with the bearer token
315
- const accessTokenManager = new AccessTokenManager(
316
- oAuthConfig.clientID,
317
- oAuthConfig.clientSecret,
318
- oauthTokens.secondaryToken,
319
- oAuthConfig.tokenURL,
320
- oauthTokens.expiresIn,
321
- oauthTokens.primaryToken,
322
- tokensData,
323
- keyId,
324
- logger,
325
- agent,
326
- isNewStructure
327
- );
328
-
329
- const accessToken = await accessTokenManager.getAccessToken();
330
- headers['Authorization'] = `Bearer ${accessToken}`;
331
- }
332
- }
333
- return headers;
334
- } catch (error) {
335
- logger.error(`Access token check failed: ${error}`);
336
- throw error;
337
- }
338
- };
339
-
340
- const getKeyIdsFromTemplateVars = (str: string): string[] => {
341
- if (!str) return [];
342
-
343
- const pattern = /{{KEY\((.*?)\)}}/g;
344
- const keyIds: any = [];
345
- let match: any = [];
346
-
347
- while ((match = pattern.exec(str)) !== null) {
348
- if (match?.length < 2) continue;
349
- keyIds.push(match[1]);
350
- }
351
-
352
- return keyIds;
353
- };
354
-
355
- async function getClientCredentialToken(tokensData, logger, keyId, oauthTokens, config, agent, isNewStructure = false) {
356
-
357
-
358
- const logAndThrowError = (message) => {
359
- logger.debug(message);
360
- throw new Error(message);
361
- };
362
-
363
- try {
364
- const { clientID, clientSecret, tokenURL } = oauthTokens;
365
- const currentTime = new Date().getTime();
366
- // Check for token expiration
367
- if (!oauthTokens.expiresIn || currentTime >= Number(oauthTokens.expiresIn)) {
368
- // Verify required parameters
369
- if (!clientID || !clientSecret || !tokenURL) {
370
- logAndThrowError('Missing client_id, client_secret OR token_url');
371
- }
372
-
373
- const params = new URLSearchParams({
374
- grant_type: 'client_credentials',
375
- client_id: clientID,
376
- client_secret: clientSecret,
377
- });
378
-
379
- const response = await axios.post(tokenURL, params.toString(), {
380
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
381
- });
382
-
383
- console.log('Access token refreshed successfully.');
384
- logger.debug('Access token refreshed successfully.');
385
-
386
- const newAccessToken = response.data.access_token;
387
- const expiresInMilliseconds = response.data.expires_in * 1000;
388
- const expirationTimestamp = currentTime + expiresInMilliseconds;
389
-
390
- // Maintain the same structure format when saving
391
- let updatedData;
392
- if (isNewStructure) {
393
- // Maintain new structure format; preserve existing fields
394
- const parts = String(config?.data?.oauth_con_id ?? '').split('_');
395
- const prefixSuffix = parts.length > 1 ? parts[1] : parts[0];
396
- const oauthKeysPrefix = prefixSuffix ? `OAUTH_${prefixSuffix}` : undefined;
397
- updatedData = {
398
- ...(tokensData || {}),
399
- auth_data: {
400
- ...(tokensData?.auth_data || {}),
401
- primary: newAccessToken,
402
- expires_in: expirationTimestamp.toString()
403
- },
404
- auth_settings: {
405
- ...(tokensData?.auth_settings || {}),
406
- type: 'oauth2',
407
- tokenURL,
408
- clientID,
409
- clientSecret,
410
- ...(oauthKeysPrefix ? { oauth_keys_prefix: oauthKeysPrefix } : {}),
411
- service: 'oauth2_client_credentials',
412
- },
413
- };
414
- } else {
415
- // Maintain old structure format
416
- updatedData = {
417
- ...tokensData,
418
- primary: newAccessToken,
419
- expires_in: expirationTimestamp.toString()
420
- };
421
- // Ensure required fields are present for old structure
422
- if (!updatedData.type) updatedData.type = 'oauth2';
423
- if (!updatedData.tokenURL) updatedData.tokenURL = tokenURL;
424
- if (!updatedData.team) updatedData.team = agent.teamId;
425
- if (!updatedData.oauth_info) {
426
- updatedData.oauth_info = {
427
- oauth_keys_prefix: `OAUTH_${config?.data?.oauth_con_id?.split('_')[1] || config?.id}`,
428
- service: 'oauth2_client_credentials',
429
- tokenURL,
430
- clientID,
431
- clientSecret
432
- };
433
- }
434
- }
435
-
436
- await managedVault.user(AccessCandidate.agent(agent.id)).set(keyId, JSON.stringify(updatedData));
437
-
438
- return newAccessToken;
439
- } else {
440
- console.log('Access token value is still valid.');
441
- logger.debug('Access token value is still valid.');
442
- return oauthTokens.primaryToken;
443
- }
444
- } catch (error) {
445
- logAndThrowError(`Failed to refresh access token: ${error}`);
446
- }
447
- }
1
+ // helper.ts
2
+ import crypto from 'crypto';
3
+ import OAuth from 'oauth-1.0a';
4
+ import AccessTokenManager from './AccessTokenManager';
5
+ import { REQUEST_CONTENT_TYPES } from '@sre/constants';
6
+ import axios, { AxiosRequestConfig } from 'axios';
7
+ import { Logger } from '@sre/helpers/Log.helper';
8
+ import { ConnectorService } from '@sre/Core/ConnectorsService';
9
+ import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
10
+ import { TemplateString } from '@sre/helpers/TemplateString.helper';
11
+ import { SystemEvents } from '@sre/Core/SystemEvents';
12
+
13
+ const console = Logger('OAuth.helper');
14
+ let managedVault: any;
15
+
16
+ SystemEvents.on('SRE:Booted', () => {
17
+ try {
18
+ managedVault = ConnectorService.getManagedVaultConnector();
19
+ } catch (error) {
20
+ console.warn('Could not find a compatible ManagedVault connector, OAuth APICalls will not work');
21
+ }
22
+ });
23
+
24
+ export function extractAdditionalParamsForOAuth1(reqConfig: AxiosRequestConfig = {}) {
25
+ let additionalParams = {};
26
+
27
+ // Validate URL doesn't contain unresolved template variables
28
+ if (reqConfig.url && (reqConfig.url.includes('{{') || reqConfig.url.includes('${{'))) {
29
+ console.warn('Warning: URL contains unresolved template variables for OAuth1 signature:', reqConfig.url);
30
+ }
31
+
32
+ // Parse URL parameters
33
+ try {
34
+ const url = new URL(reqConfig.url);
35
+ const searchParams = url.searchParams;
36
+ additionalParams = Object.fromEntries(searchParams.entries());
37
+
38
+ // Log if we have query parameters for debugging
39
+ if (searchParams.toString()) {
40
+ console.debug('OAuth1: Found query parameters:', Object.keys(additionalParams));
41
+ }
42
+ } catch (error) {
43
+ console.warn('Failed to parse URL for OAuth1 parameters:', error);
44
+ }
45
+
46
+ // Get the content type, handling different header formats
47
+ const headers = reqConfig.headers || {};
48
+ let contentType = '';
49
+
50
+ // Headers might be an object or array of objects
51
+ if (Array.isArray(headers)) {
52
+ const contentTypeHeader = headers.find(h =>
53
+ Object.keys(h).some(k => k.toLowerCase() === 'content-type')
54
+ );
55
+ if (contentTypeHeader) {
56
+ const key = Object.keys(contentTypeHeader).find(k => k.toLowerCase() === 'content-type');
57
+ contentType = contentTypeHeader[key];
58
+ }
59
+ } else {
60
+ contentType = headers['Content-Type'] || headers['content-type'] || '';
61
+ }
62
+
63
+ // Extract body parameters based on content type
64
+ const method = (reqConfig.method || 'GET').toUpperCase();
65
+
66
+ if (contentType.includes(REQUEST_CONTENT_TYPES.urlEncodedFormData)) {
67
+ // For form data, include the form parameters in the signature
68
+ if (reqConfig.data) {
69
+ let formParams = {};
70
+ if (typeof reqConfig.data === 'string') {
71
+ // Check for unresolved template variables in form data
72
+ if (reqConfig.data.includes('{{') || reqConfig.data.includes('${{')) {
73
+ console.warn('Warning: Form data contains unresolved template variables for OAuth1 signature');
74
+ }
75
+ const formData = new URLSearchParams(reqConfig.data);
76
+ formParams = Object.fromEntries(formData.entries());
77
+ } else if (reqConfig.data instanceof URLSearchParams) {
78
+ formParams = Object.fromEntries(reqConfig.data.entries());
79
+ } else if (typeof reqConfig.data === 'object') {
80
+ // Handle plain object
81
+ formParams = reqConfig.data;
82
+ }
83
+ console.debug('OAuth1: Including form parameters in signature:', Object.keys(formParams));
84
+ additionalParams = { ...additionalParams, ...formParams };
85
+ }
86
+ } else if (contentType.includes(REQUEST_CONTENT_TYPES.json) ||
87
+ contentType.includes('application/') ||
88
+ contentType.includes('text/')) {
89
+ // For JSON and other non-form data, use oauth_body_hash
90
+ if (reqConfig.data && method !== 'GET' && method !== 'HEAD') {
91
+ let bodyString = '';
92
+ if (typeof reqConfig.data === 'string') {
93
+ bodyString = reqConfig.data;
94
+ } else {
95
+ bodyString = JSON.stringify(reqConfig.data);
96
+ }
97
+ // Check for unresolved template variables
98
+ if (bodyString.includes('{{') || bodyString.includes('${{')) {
99
+ console.warn('Warning: Request body contains unresolved template variables for OAuth1 signature');
100
+ }
101
+ const hash = crypto.createHash('sha1').update(bodyString).digest('base64');
102
+ additionalParams['oauth_body_hash'] = hash;
103
+ console.debug('OAuth1: Added oauth_body_hash for', contentType);
104
+ }
105
+ } else if (contentType.includes(REQUEST_CONTENT_TYPES.multipartFormData)) {
106
+ // For multipart form data, only include text fields
107
+ if (reqConfig.data && typeof reqConfig.data === 'object' && 'entries' in reqConfig.data) {
108
+ const formData = reqConfig.data as FormData;
109
+ for (const [key, value] of formData.entries()) {
110
+ // Only include string values, exclude Files/Blobs
111
+ if (typeof value === 'string') {
112
+ additionalParams[key] = value;
113
+ } else if (typeof value === 'object' && value !== null &&
114
+ ('size' in value || 'type' in value)) {
115
+ // Skip binary data (Files, Blobs, etc.)
116
+ continue;
117
+ } else {
118
+ // Include other simple values
119
+ additionalParams[key] = String(value);
120
+ }
121
+ }
122
+ }
123
+ } else if (!contentType && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
124
+ // No content type specified but has data
125
+ if (reqConfig.data) {
126
+ const bodyString = typeof reqConfig.data === 'string' ?
127
+ reqConfig.data : JSON.stringify(reqConfig.data);
128
+ const hash = crypto.createHash('sha1').update(bodyString).digest('base64');
129
+ additionalParams['oauth_body_hash'] = hash;
130
+ }
131
+ }
132
+
133
+ console.debug('OAuth1: Total parameters for signature:', Object.keys(additionalParams).length);
134
+ return additionalParams;
135
+ }
136
+
137
+ export const buildOAuth1Header = (url, method, oauth1Credentials, additionalParams = {}) => {
138
+ const oauth = new OAuth({
139
+ consumer: {
140
+ key: oauth1Credentials.consumerKey,
141
+ secret: oauth1Credentials.consumerSecret,
142
+ },
143
+ signature_method: 'HMAC-SHA1',
144
+ hash_function(base_string, key) {
145
+ return crypto.createHmac('sha1', key).update(base_string).digest('base64');
146
+ },
147
+ });
148
+
149
+ // OAuth1 requires the base URL without query parameters for signature
150
+ // The query parameters should be included separately in additionalParams
151
+ let baseUrl = url;
152
+ try {
153
+ const urlObj = new URL(url);
154
+ // Remove query parameters from URL for signature base
155
+ baseUrl = `${urlObj.protocol}//${urlObj.host}${urlObj.pathname}`;
156
+ console.debug('OAuth1: Base URL for signature:', baseUrl);
157
+ } catch (error) {
158
+ console.warn('Failed to parse URL for OAuth1 signature:', error);
159
+ }
160
+
161
+ // Include additional parameters in the request data
162
+ const requestData = {
163
+ url: baseUrl,
164
+ method: method.toUpperCase(),
165
+ data: additionalParams, // Parameters should be in data field for oauth-1.0a library
166
+ };
167
+
168
+ const token = oauth1Credentials.token && oauth1Credentials.token !== '' ?
169
+ { key: oauth1Credentials.token, secret: oauth1Credentials.tokenSecret || '' } :
170
+ null;
171
+
172
+ const signedRequest = oauth.authorize(requestData, token);
173
+ return oauth.toHeader(signedRequest);
174
+ };
175
+
176
+ export const retrieveOAuthTokens = async (agent, config) => {
177
+ let tokenKey: any = null;
178
+ try {
179
+ // To support both old and new OAuth configuration, we check for both oauth_con_id and config.id (component id)
180
+ tokenKey = config?.data?.oauth_con_id || `OAUTH_${config?.id}_TOKENS`;
181
+
182
+ try {
183
+ const result: any = await managedVault.user(AccessCandidate.agent(agent.id)).get(tokenKey);
184
+ const tokensData = typeof result === 'object' ? result : JSON.parse(result || '{}');
185
+
186
+ if (!tokensData) {
187
+ throw new Error('Failed to retrieve OAuth tokens from vault. Please authenticate ...');
188
+ }
189
+
190
+ // Check if it's new structure (has auth_data and auth_settings) or old structure
191
+ const isNewStructure = tokensData.auth_data !== undefined && tokensData.auth_settings !== undefined;
192
+
193
+ // Extract tokens based on structure
194
+ const primaryToken = isNewStructure
195
+ ? tokensData.auth_data?.primary
196
+ : tokensData.primary;
197
+ const secondaryToken = isNewStructure
198
+ ? tokensData.auth_data?.secondary
199
+ : tokensData.secondary;
200
+ const expiresIn = isNewStructure
201
+ ? tokensData.auth_data?.expires_in
202
+ : tokensData.expires_in;
203
+
204
+ // Extract settings based on structure
205
+ const type = isNewStructure
206
+ ? tokensData.auth_settings?.type
207
+ : (tokensData.type || tokensData.oauth_info?.type);
208
+ const service = isNewStructure
209
+ ? tokensData.auth_settings?.service
210
+ : tokensData.oauth_info?.service;
211
+
212
+ // Add warning logs for OAuth2
213
+ if (type === 'oauth2' && service !== 'oauth2_client_credentials') {
214
+ if (!secondaryToken) {
215
+ console.warn('Warning: refresh_token is missing for OAuth2');
216
+ }
217
+ if (!expiresIn) {
218
+ console.warn('Warning: expires_in is missing for OAuth2.');
219
+ }
220
+ }
221
+
222
+ // sometimes refreshToken is not available . e.g in case of linkedIn. so only add check for primary token
223
+ if (service !== 'oauth2_client_credentials') {
224
+ if (!primaryToken) {
225
+ throw new Error('Retrieved OAuth tokens do not exist, invalid OR incomplete. Please authenticate ...');
226
+ }
227
+ }
228
+
229
+ const responseData: any = {
230
+ primaryToken,
231
+ secondaryToken,
232
+ type,
233
+ service,
234
+ };
235
+
236
+ if (type === 'oauth') {
237
+ // Extract OAuth1 credentials based on structure
238
+ if (isNewStructure) {
239
+ responseData.consumerKey = tokensData.auth_settings?.consumerKey;
240
+ responseData.consumerSecret = tokensData.auth_settings?.consumerSecret;
241
+ responseData.tokenURL = tokensData.auth_settings?.tokenURL;
242
+ } else {
243
+ responseData.consumerKey = tokensData.consumerKey || tokensData.oauth_info?.consumerKey;
244
+ responseData.consumerSecret = tokensData.consumerSecret || tokensData.oauth_info?.consumerSecret;
245
+ responseData.tokenURL = tokensData.tokenURL || tokensData.oauth_info?.tokenURL;
246
+ }
247
+ responseData.team = tokensData.team || agent.teamId;
248
+ } else if (type === 'oauth2') {
249
+ // Extract OAuth2 credentials based on structure
250
+ if (isNewStructure) {
251
+ responseData.tokenURL = tokensData.auth_settings?.tokenURL;
252
+ responseData.clientID = tokensData.auth_settings?.clientID;
253
+ responseData.clientSecret = tokensData.auth_settings?.clientSecret;
254
+ } else {
255
+ responseData.tokenURL = tokensData.tokenURL || tokensData.oauth_info?.tokenURL;
256
+ responseData.clientID = tokensData.clientID || tokensData.oauth_info?.clientID;
257
+ responseData.clientSecret = tokensData.clientSecret || tokensData.oauth_info?.clientSecret;
258
+ }
259
+ responseData.expiresIn = expiresIn ?? 0; // Optional property, default to 0 if not present
260
+ responseData.team = tokensData.team || agent.teamId;
261
+ }
262
+
263
+ return { responseData, tokensData, keyId: tokenKey, isNewStructure };
264
+ } catch (error) {
265
+ throw new Error(`Failed to parse retrieved tokens: ${error}`);
266
+ }
267
+ } catch (error) {
268
+ console.error('Error retrieving OAuth tokens:', error);
269
+ throw error; // rethrow for potential handling by the calling code
270
+ }
271
+ };
272
+
273
+ export const handleOAuthHeaders = async (agent, config, reqConfig, logger, additionalParams = {}) => {
274
+ let headers = {}; // Initialize headers as an empty object
275
+ const { responseData: oauthTokens, tokensData, keyId, isNewStructure } = await retrieveOAuthTokens(agent, config);
276
+
277
+ try {
278
+ // Build OAuth config string with template support
279
+ let oAuthConfigString = JSON.stringify({
280
+ consumerKey: oauthTokens.consumerKey || '',
281
+ consumerSecret: oauthTokens.consumerSecret || '',
282
+ clientID: oauthTokens.clientID || '',
283
+ clientSecret: oauthTokens.clientSecret || '',
284
+ tokenURL: oauthTokens.tokenURL || '',
285
+ });
286
+
287
+ oAuthConfigString = await TemplateString(oAuthConfigString).parseTeamKeysAsync(oauthTokens.team || agent.teamId).asyncResult;
288
+
289
+ const oAuthConfig = JSON.parse(oAuthConfigString);
290
+ // Avoid logging sensitive OAuth config in plaintext
291
+ // console.log('oAuthConfig', { ...oAuthConfig, clientSecret: '***' });
292
+ if (oauthTokens.service === 'oauth2_client_credentials') {
293
+ const accessToken = await getClientCredentialToken(tokensData, logger, keyId, oauthTokens, config, agent, isNewStructure);
294
+ headers['Authorization'] = `Bearer ${accessToken}`;
295
+ } else {
296
+ if (oauthTokens.type === 'oauth') {
297
+ // For OAuth1, generate and replace the signature in headers
298
+ // Use the full URL (with path but without query params) for OAuth1
299
+ const oauthHeader = buildOAuth1Header(
300
+ reqConfig.url,
301
+ reqConfig.method,
302
+ {
303
+ consumerKey: oAuthConfig.consumerKey,
304
+ consumerSecret: oAuthConfig.consumerSecret,
305
+ token: oauthTokens.primaryToken,
306
+ tokenSecret: oauthTokens.secondaryToken,
307
+ },
308
+ additionalParams
309
+ );
310
+
311
+ headers = { ...reqConfig.headers, ...oauthHeader };
312
+ logger.debug('OAuth1 access token check success.');
313
+ } else if (oauthTokens.type === 'oauth2') {
314
+ // For OAuth2, add the 'Authorization' header with the bearer token
315
+ const accessTokenManager = new AccessTokenManager(
316
+ oAuthConfig.clientID,
317
+ oAuthConfig.clientSecret,
318
+ oauthTokens.secondaryToken,
319
+ oAuthConfig.tokenURL,
320
+ oauthTokens.expiresIn,
321
+ oauthTokens.primaryToken,
322
+ tokensData,
323
+ keyId,
324
+ logger,
325
+ agent,
326
+ isNewStructure
327
+ );
328
+
329
+ const accessToken = await accessTokenManager.getAccessToken();
330
+ headers['Authorization'] = `Bearer ${accessToken}`;
331
+ }
332
+ }
333
+ return headers;
334
+ } catch (error) {
335
+ logger.error(`Access token check failed: ${error}`);
336
+ throw error;
337
+ }
338
+ };
339
+
340
+ const getKeyIdsFromTemplateVars = (str: string): string[] => {
341
+ if (!str) return [];
342
+
343
+ const pattern = /{{KEY\((.*?)\)}}/g;
344
+ const keyIds: any = [];
345
+ let match: any = [];
346
+
347
+ while ((match = pattern.exec(str)) !== null) {
348
+ if (match?.length < 2) continue;
349
+ keyIds.push(match[1]);
350
+ }
351
+
352
+ return keyIds;
353
+ };
354
+
355
+ async function getClientCredentialToken(tokensData, logger, keyId, oauthTokens, config, agent, isNewStructure = false) {
356
+
357
+
358
+ const logAndThrowError = (message) => {
359
+ logger.debug(message);
360
+ throw new Error(message);
361
+ };
362
+
363
+ try {
364
+ const { clientID, clientSecret, tokenURL } = oauthTokens;
365
+ const currentTime = new Date().getTime();
366
+ // Check for token expiration
367
+ if (!oauthTokens.expiresIn || currentTime >= Number(oauthTokens.expiresIn)) {
368
+ // Verify required parameters
369
+ if (!clientID || !clientSecret || !tokenURL) {
370
+ logAndThrowError('Missing client_id, client_secret OR token_url');
371
+ }
372
+
373
+ const params = new URLSearchParams({
374
+ grant_type: 'client_credentials',
375
+ client_id: clientID,
376
+ client_secret: clientSecret,
377
+ });
378
+
379
+ const response = await axios.post(tokenURL, params.toString(), {
380
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
381
+ });
382
+
383
+ console.log('Access token refreshed successfully.');
384
+ logger.debug('Access token refreshed successfully.');
385
+
386
+ const newAccessToken = response.data.access_token;
387
+ const expiresInMilliseconds = response.data.expires_in * 1000;
388
+ const expirationTimestamp = currentTime + expiresInMilliseconds;
389
+
390
+ // Maintain the same structure format when saving
391
+ let updatedData;
392
+ if (isNewStructure) {
393
+ // Maintain new structure format; preserve existing fields
394
+ const parts = String(config?.data?.oauth_con_id ?? '').split('_');
395
+ const prefixSuffix = parts.length > 1 ? parts[1] : parts[0];
396
+ const oauthKeysPrefix = prefixSuffix ? `OAUTH_${prefixSuffix}` : undefined;
397
+ updatedData = {
398
+ ...(tokensData || {}),
399
+ auth_data: {
400
+ ...(tokensData?.auth_data || {}),
401
+ primary: newAccessToken,
402
+ expires_in: expirationTimestamp.toString()
403
+ },
404
+ auth_settings: {
405
+ ...(tokensData?.auth_settings || {}),
406
+ type: 'oauth2',
407
+ tokenURL,
408
+ clientID,
409
+ clientSecret,
410
+ ...(oauthKeysPrefix ? { oauth_keys_prefix: oauthKeysPrefix } : {}),
411
+ service: 'oauth2_client_credentials',
412
+ },
413
+ };
414
+ } else {
415
+ // Maintain old structure format
416
+ updatedData = {
417
+ ...tokensData,
418
+ primary: newAccessToken,
419
+ expires_in: expirationTimestamp.toString()
420
+ };
421
+ // Ensure required fields are present for old structure
422
+ if (!updatedData.type) updatedData.type = 'oauth2';
423
+ if (!updatedData.tokenURL) updatedData.tokenURL = tokenURL;
424
+ if (!updatedData.team) updatedData.team = agent.teamId;
425
+ if (!updatedData.oauth_info) {
426
+ updatedData.oauth_info = {
427
+ oauth_keys_prefix: `OAUTH_${config?.data?.oauth_con_id?.split('_')[1] || config?.id}`,
428
+ service: 'oauth2_client_credentials',
429
+ tokenURL,
430
+ clientID,
431
+ clientSecret
432
+ };
433
+ }
434
+ }
435
+
436
+ await managedVault.user(AccessCandidate.agent(agent.id)).set(keyId, JSON.stringify(updatedData));
437
+
438
+ return newAccessToken;
439
+ } else {
440
+ console.log('Access token value is still valid.');
441
+ logger.debug('Access token value is still valid.');
442
+ return oauthTokens.primaryToken;
443
+ }
444
+ } catch (error) {
445
+ logAndThrowError(`Failed to refresh access token: ${error}`);
446
+ }
447
+ }