@smythos/sre 1.6.1 → 1.6.8

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 (234) hide show
  1. package/CHANGELOG +111 -111
  2. package/LICENSE +18 -18
  3. package/README.md +135 -135
  4. package/dist/index.js +2 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/types/subsystems/LLMManager/ModelsProvider.service/connectors/SmythModelsProvider.class.d.ts +39 -0
  7. package/package.json +1 -1
  8. package/src/Components/APICall/APICall.class.ts +161 -161
  9. package/src/Components/APICall/AccessTokenManager.ts +166 -166
  10. package/src/Components/APICall/ArrayBufferResponse.helper.ts +58 -58
  11. package/src/Components/APICall/OAuth.helper.ts +447 -447
  12. package/src/Components/APICall/mimeTypeCategories.ts +46 -46
  13. package/src/Components/APICall/parseData.ts +167 -167
  14. package/src/Components/APICall/parseHeaders.ts +41 -41
  15. package/src/Components/APICall/parseProxy.ts +68 -68
  16. package/src/Components/APICall/parseUrl.ts +91 -91
  17. package/src/Components/APIEndpoint.class.ts +234 -234
  18. package/src/Components/APIOutput.class.ts +58 -58
  19. package/src/Components/AgentPlugin.class.ts +102 -102
  20. package/src/Components/Async.class.ts +155 -155
  21. package/src/Components/Await.class.ts +90 -90
  22. package/src/Components/Classifier.class.ts +158 -158
  23. package/src/Components/Component.class.ts +147 -147
  24. package/src/Components/ComponentHost.class.ts +38 -38
  25. package/src/Components/DataSourceCleaner.class.ts +92 -92
  26. package/src/Components/DataSourceIndexer.class.ts +181 -181
  27. package/src/Components/DataSourceLookup.class.ts +161 -161
  28. package/src/Components/ECMASandbox.class.ts +72 -72
  29. package/src/Components/FEncDec.class.ts +29 -29
  30. package/src/Components/FHash.class.ts +33 -33
  31. package/src/Components/FSign.class.ts +80 -80
  32. package/src/Components/FSleep.class.ts +25 -25
  33. package/src/Components/FTimestamp.class.ts +66 -66
  34. package/src/Components/FileStore.class.ts +78 -78
  35. package/src/Components/ForEach.class.ts +97 -97
  36. package/src/Components/GPTPlugin.class.ts +70 -70
  37. package/src/Components/GenAILLM.class.ts +586 -586
  38. package/src/Components/HuggingFace.class.ts +313 -313
  39. package/src/Components/Image/imageSettings.config.ts +70 -70
  40. package/src/Components/ImageGenerator.class.ts +483 -483
  41. package/src/Components/JSONFilter.class.ts +54 -54
  42. package/src/Components/LLMAssistant.class.ts +213 -213
  43. package/src/Components/LogicAND.class.ts +28 -28
  44. package/src/Components/LogicAtLeast.class.ts +85 -85
  45. package/src/Components/LogicAtMost.class.ts +86 -86
  46. package/src/Components/LogicOR.class.ts +29 -29
  47. package/src/Components/LogicXOR.class.ts +34 -34
  48. package/src/Components/MCPClient.class.ts +137 -137
  49. package/src/Components/MemoryDeleteKeyVal.class.ts +70 -70
  50. package/src/Components/MemoryReadKeyVal.class.ts +67 -67
  51. package/src/Components/MemoryWriteKeyVal.class.ts +62 -62
  52. package/src/Components/MemoryWriteObject.class.ts +97 -97
  53. package/src/Components/MultimodalLLM.class.ts +128 -128
  54. package/src/Components/OpenAPI.class.ts +72 -72
  55. package/src/Components/PromptGenerator.class.ts +122 -122
  56. package/src/Components/ScrapflyWebScrape.class.ts +183 -183
  57. package/src/Components/ServerlessCode.class.ts +123 -123
  58. package/src/Components/TavilyWebSearch.class.ts +103 -103
  59. package/src/Components/VisionLLM.class.ts +104 -104
  60. package/src/Components/ZapierAction.class.ts +127 -127
  61. package/src/Components/index.ts +97 -97
  62. package/src/Core/AgentProcess.helper.ts +240 -240
  63. package/src/Core/Connector.class.ts +123 -123
  64. package/src/Core/ConnectorsService.ts +197 -197
  65. package/src/Core/DummyConnector.ts +49 -49
  66. package/src/Core/HookService.ts +105 -105
  67. package/src/Core/SmythRuntime.class.ts +241 -241
  68. package/src/Core/SystemEvents.ts +16 -16
  69. package/src/Core/boot.ts +56 -56
  70. package/src/config.ts +15 -15
  71. package/src/constants.ts +126 -126
  72. package/src/data/hugging-face.params.json +579 -579
  73. package/src/helpers/AWSLambdaCode.helper.ts +624 -599
  74. package/src/helpers/BinaryInput.helper.ts +331 -331
  75. package/src/helpers/Conversation.helper.ts +1157 -1157
  76. package/src/helpers/ECMASandbox.helper.ts +64 -64
  77. package/src/helpers/JsonContent.helper.ts +97 -97
  78. package/src/helpers/LocalCache.helper.ts +97 -97
  79. package/src/helpers/Log.helper.ts +274 -274
  80. package/src/helpers/OpenApiParser.helper.ts +150 -150
  81. package/src/helpers/S3Cache.helper.ts +147 -147
  82. package/src/helpers/SmythURI.helper.ts +5 -5
  83. package/src/helpers/Sysconfig.helper.ts +95 -95
  84. package/src/helpers/TemplateString.helper.ts +243 -243
  85. package/src/helpers/TypeChecker.helper.ts +329 -329
  86. package/src/index.ts +198 -198
  87. package/src/index.ts.bak +198 -198
  88. package/src/subsystems/AgentManager/Agent.class.ts +1114 -1114
  89. package/src/subsystems/AgentManager/Agent.helper.ts +3 -3
  90. package/src/subsystems/AgentManager/AgentData.service/AgentDataConnector.ts +230 -230
  91. package/src/subsystems/AgentManager/AgentData.service/connectors/CLIAgentDataConnector.class.ts +66 -66
  92. package/src/subsystems/AgentManager/AgentData.service/connectors/LocalAgentDataConnector.class.ts +145 -145
  93. package/src/subsystems/AgentManager/AgentData.service/connectors/NullAgentData.class.ts +39 -39
  94. package/src/subsystems/AgentManager/AgentData.service/index.ts +18 -18
  95. package/src/subsystems/AgentManager/AgentLogger.class.ts +301 -301
  96. package/src/subsystems/AgentManager/AgentRequest.class.ts +51 -51
  97. package/src/subsystems/AgentManager/AgentRuntime.class.ts +557 -557
  98. package/src/subsystems/AgentManager/AgentSSE.class.ts +101 -101
  99. package/src/subsystems/AgentManager/AgentSettings.class.ts +52 -52
  100. package/src/subsystems/AgentManager/Component.service/ComponentConnector.ts +32 -32
  101. package/src/subsystems/AgentManager/Component.service/connectors/LocalComponentConnector.class.ts +60 -60
  102. package/src/subsystems/AgentManager/Component.service/index.ts +11 -11
  103. package/src/subsystems/AgentManager/EmbodimentSettings.class.ts +47 -47
  104. package/src/subsystems/AgentManager/ForkedAgent.class.ts +154 -154
  105. package/src/subsystems/AgentManager/OSResourceMonitor.ts +77 -77
  106. package/src/subsystems/ComputeManager/Code.service/CodeConnector.ts +98 -98
  107. package/src/subsystems/ComputeManager/Code.service/connectors/AWSLambdaCode.class.ts +171 -172
  108. package/src/subsystems/ComputeManager/Code.service/connectors/ECMASandbox.class.ts +131 -131
  109. package/src/subsystems/ComputeManager/Code.service/index.ts +13 -13
  110. package/src/subsystems/IO/CLI.service/CLIConnector.ts +47 -47
  111. package/src/subsystems/IO/CLI.service/index.ts +9 -9
  112. package/src/subsystems/IO/Log.service/LogConnector.ts +32 -32
  113. package/src/subsystems/IO/Log.service/connectors/ConsoleLog.class.ts +28 -28
  114. package/src/subsystems/IO/Log.service/index.ts +13 -13
  115. package/src/subsystems/IO/NKV.service/NKVConnector.ts +43 -43
  116. package/src/subsystems/IO/NKV.service/connectors/NKVLocalStorage.class.ts +234 -234
  117. package/src/subsystems/IO/NKV.service/connectors/NKVRAM.class.ts +204 -204
  118. package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +182 -182
  119. package/src/subsystems/IO/NKV.service/index.ts +14 -14
  120. package/src/subsystems/IO/Router.service/RouterConnector.ts +21 -21
  121. package/src/subsystems/IO/Router.service/connectors/ExpressRouter.class.ts +48 -48
  122. package/src/subsystems/IO/Router.service/connectors/NullRouter.class.ts +40 -40
  123. package/src/subsystems/IO/Router.service/index.ts +11 -11
  124. package/src/subsystems/IO/Storage.service/SmythFS.class.ts +488 -488
  125. package/src/subsystems/IO/Storage.service/StorageConnector.ts +66 -66
  126. package/src/subsystems/IO/Storage.service/connectors/LocalStorage.class.ts +327 -327
  127. package/src/subsystems/IO/Storage.service/connectors/S3Storage.class.ts +482 -482
  128. package/src/subsystems/IO/Storage.service/index.ts +13 -13
  129. package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +108 -108
  130. package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +465 -465
  131. package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +387 -387
  132. package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +408 -408
  133. package/src/subsystems/IO/VectorDB.service/embed/BaseEmbedding.ts +107 -107
  134. package/src/subsystems/IO/VectorDB.service/embed/GoogleEmbedding.ts +118 -118
  135. package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +109 -109
  136. package/src/subsystems/IO/VectorDB.service/embed/index.ts +26 -26
  137. package/src/subsystems/IO/VectorDB.service/index.ts +14 -14
  138. package/src/subsystems/LLMManager/LLM.helper.ts +251 -251
  139. package/src/subsystems/LLMManager/LLM.inference.ts +345 -345
  140. package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +492 -492
  141. package/src/subsystems/LLMManager/LLM.service/LLMCredentials.helper.ts +171 -171
  142. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +666 -666
  143. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +407 -407
  144. package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +92 -92
  145. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +983 -983
  146. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +319 -319
  147. package/src/subsystems/LLMManager/LLM.service/connectors/Ollama.class.ts +361 -361
  148. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +257 -257
  149. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +430 -430
  150. package/src/subsystems/LLMManager/LLM.service/connectors/openai/OpenAIConnector.class.ts +503 -503
  151. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ChatCompletionsApiInterface.ts +524 -524
  152. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterface.ts +100 -100
  153. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/OpenAIApiInterfaceFactory.ts +81 -81
  154. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/ResponsesApiInterface.ts +1145 -1145
  155. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/constants.ts +13 -13
  156. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/index.ts +4 -4
  157. package/src/subsystems/LLMManager/LLM.service/connectors/openai/apiInterfaces/utils.ts +11 -11
  158. package/src/subsystems/LLMManager/LLM.service/connectors/openai/types.ts +32 -32
  159. package/src/subsystems/LLMManager/LLM.service/connectors/xAI.class.ts +478 -478
  160. package/src/subsystems/LLMManager/LLM.service/index.ts +47 -47
  161. package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +303 -303
  162. package/src/subsystems/LLMManager/ModelsProvider.service/connectors/JSONModelsProvider.class.ts +271 -271
  163. package/src/subsystems/LLMManager/ModelsProvider.service/index.ts +11 -11
  164. package/src/subsystems/LLMManager/custom-models.ts +854 -854
  165. package/src/subsystems/LLMManager/models.ts +2540 -2540
  166. package/src/subsystems/LLMManager/paramMappings.ts +69 -69
  167. package/src/subsystems/MemoryManager/Cache.service/CacheConnector.ts +86 -86
  168. package/src/subsystems/MemoryManager/Cache.service/connectors/LocalStorageCache.class.ts +297 -297
  169. package/src/subsystems/MemoryManager/Cache.service/connectors/RAMCache.class.ts +214 -214
  170. package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +252 -252
  171. package/src/subsystems/MemoryManager/Cache.service/connectors/S3Cache.class.ts +373 -373
  172. package/src/subsystems/MemoryManager/Cache.service/index.ts +15 -15
  173. package/src/subsystems/MemoryManager/LLMCache.ts +72 -72
  174. package/src/subsystems/MemoryManager/LLMContext.ts +124 -124
  175. package/src/subsystems/MemoryManager/LLMMemory.service/LLMMemoryConnector.ts +26 -26
  176. package/src/subsystems/MemoryManager/RuntimeContext.ts +277 -277
  177. package/src/subsystems/Security/AccessControl/ACL.class.ts +208 -208
  178. package/src/subsystems/Security/AccessControl/AccessCandidate.class.ts +82 -82
  179. package/src/subsystems/Security/AccessControl/AccessRequest.class.ts +52 -52
  180. package/src/subsystems/Security/Account.service/AccountConnector.ts +44 -44
  181. package/src/subsystems/Security/Account.service/connectors/DummyAccount.class.ts +130 -130
  182. package/src/subsystems/Security/Account.service/connectors/JSONFileAccount.class.ts +170 -170
  183. package/src/subsystems/Security/Account.service/connectors/MySQLAccount.class.ts +76 -76
  184. package/src/subsystems/Security/Account.service/index.ts +14 -14
  185. package/src/subsystems/Security/Credentials.helper.ts +62 -62
  186. package/src/subsystems/Security/ManagedVault.service/ManagedVaultConnector.ts +38 -38
  187. package/src/subsystems/Security/ManagedVault.service/connectors/NullManagedVault.class.ts +53 -53
  188. package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +154 -154
  189. package/src/subsystems/Security/ManagedVault.service/index.ts +12 -12
  190. package/src/subsystems/Security/SecureConnector.class.ts +110 -110
  191. package/src/subsystems/Security/Vault.service/Vault.helper.ts +30 -30
  192. package/src/subsystems/Security/Vault.service/VaultConnector.ts +29 -29
  193. package/src/subsystems/Security/Vault.service/connectors/HashicorpVault.class.ts +46 -46
  194. package/src/subsystems/Security/Vault.service/connectors/JSONFileVault.class.ts +221 -221
  195. package/src/subsystems/Security/Vault.service/connectors/NullVault.class.ts +54 -54
  196. package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +140 -140
  197. package/src/subsystems/Security/Vault.service/index.ts +12 -12
  198. package/src/types/ACL.types.ts +104 -104
  199. package/src/types/AWS.types.ts +10 -10
  200. package/src/types/Agent.types.ts +61 -61
  201. package/src/types/AgentLogger.types.ts +17 -17
  202. package/src/types/Cache.types.ts +1 -1
  203. package/src/types/Common.types.ts +2 -2
  204. package/src/types/LLM.types.ts +520 -520
  205. package/src/types/Redis.types.ts +8 -8
  206. package/src/types/SRE.types.ts +64 -64
  207. package/src/types/Security.types.ts +14 -14
  208. package/src/types/Storage.types.ts +5 -5
  209. package/src/types/VectorDB.types.ts +86 -86
  210. package/src/utils/base64.utils.ts +275 -275
  211. package/src/utils/cli.utils.ts +68 -68
  212. package/src/utils/data.utils.ts +322 -322
  213. package/src/utils/date-time.utils.ts +22 -22
  214. package/src/utils/general.utils.ts +238 -238
  215. package/src/utils/index.ts +12 -12
  216. package/src/utils/lazy-client.ts +261 -261
  217. package/src/utils/numbers.utils.ts +13 -13
  218. package/src/utils/oauth.utils.ts +35 -35
  219. package/src/utils/string.utils.ts +414 -414
  220. package/src/utils/url.utils.ts +19 -19
  221. package/src/utils/validation.utils.ts +74 -74
  222. package/dist/bundle-analysis-lazy.html +0 -4949
  223. package/dist/bundle-analysis.html +0 -4949
  224. package/dist/types/Components/Triggers/GmailTrigger.class.d.ts +0 -13
  225. package/dist/types/Components/Triggers/Trigger.class.d.ts +0 -3
  226. package/dist/types/helpers/AIPerformanceAnalyzer.helper.d.ts +0 -45
  227. package/dist/types/helpers/AIPerformanceCollector.helper.d.ts +0 -111
  228. package/dist/types/subsystems/IO/Storage.service/connectors/AzureBlobStorage.class.d.ts +0 -211
  229. package/dist/types/subsystems/IO/VectorDB.service/connectors/WeaviateVectorDB.class.d.ts +0 -187
  230. package/dist/types/subsystems/PerformanceManager/Performance.service/PerformanceConnector.d.ts +0 -102
  231. package/dist/types/subsystems/PerformanceManager/Performance.service/connectors/LocalPerformanceConnector.class.d.ts +0 -100
  232. package/dist/types/subsystems/PerformanceManager/Performance.service/index.d.ts +0 -22
  233. package/dist/types/types/Performance.types.d.ts +0 -468
  234. package/dist/types/utils/package-manager.utils.d.ts +0 -26
@@ -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
+ }