Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@smythos/sre",
"version": "1.5.50",
"version": "1.5.51",
"description": "Smyth Runtime Environment",
"author": "Alaa-eddine KADDOURI",
"license": "MIT",
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/Components/APICall/APICall.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ export class APICall extends Component {
consumerSecret: Joi.string().allow('').label('Consumer Secret'),
oauth1CallbackURL: Joi.string().allow('').label('OAuth1 Callback URL'),
authenticate: Joi.string().allow('').label('Authenticate'),
oauth_con_id: Joi.string().allow('').label('OAuth Connection ID'),
});
constructor() {
super();
}

init() {}
init() { }

async process(input, config, agent: Agent) {
await super.process(input, config, agent);
Expand Down Expand Up @@ -113,10 +114,9 @@ export class APICall extends Component {
let Headers: any = {};
let _error: any = undefined;
try {
if (config?.data?.oauthService && config?.data?.oauthService !== 'None') {
const rootUrl = new URL(reqConfig.url).origin;
if (config?.data?.oauth_con_id !== '' && config?.data?.oauth_con_id !== 'None') {
const additionalParams = extractAdditionalParamsForOAuth1(reqConfig);
const oauthHeaders = await generateOAuthHeaders(agent, config, reqConfig, logger, additionalParams, rootUrl);
const oauthHeaders = await generateOAuthHeaders(agent, config, reqConfig, logger, additionalParams);
//reqConfig.headers = { ...reqConfig.headers, ...oauthHeaders };
reqConfig.headers = reqConfig.headers.concat({ ...oauthHeaders });
}
Comment on lines +117 to 122
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix OAuth gating and header merge.
Undefined oauth_con_id currently passes the condition; also avoid concat on headers.

-                if (config?.data?.oauth_con_id !== '' && config?.data?.oauth_con_id !== 'None') {
+                if (typeof config?.data?.oauth_con_id === 'string' && config.data.oauth_con_id.trim() && config.data.oauth_con_id !== 'None') {
                     const additionalParams = extractAdditionalParamsForOAuth1(reqConfig);
-                    const oauthHeaders = await generateOAuthHeaders(agent, config, reqConfig, logger, additionalParams);
-                    //reqConfig.headers = { ...reqConfig.headers, ...oauthHeaders };
-                    reqConfig.headers = reqConfig.headers.concat({ ...oauthHeaders });
+                    const oauthHeaders = await generateOAuthHeaders(agent, config, reqConfig, logger, additionalParams);
+                    reqConfig.headers = { ...(reqConfig.headers || {}), ...oauthHeaders };
                 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (config?.data?.oauth_con_id !== '' && config?.data?.oauth_con_id !== 'None') {
const additionalParams = extractAdditionalParamsForOAuth1(reqConfig);
const oauthHeaders = await generateOAuthHeaders(agent, config, reqConfig, logger, additionalParams, rootUrl);
const oauthHeaders = await generateOAuthHeaders(agent, config, reqConfig, logger, additionalParams);
//reqConfig.headers = { ...reqConfig.headers, ...oauthHeaders };
reqConfig.headers = reqConfig.headers.concat({ ...oauthHeaders });
}
if (typeof config?.data?.oauth_con_id === 'string' && config.data.oauth_con_id.trim() && config.data.oauth_con_id !== 'None') {
const additionalParams = extractAdditionalParamsForOAuth1(reqConfig);
const oauthHeaders = await generateOAuthHeaders(agent, config, reqConfig, logger, additionalParams);
reqConfig.headers = { ...(reqConfig.headers || {}), ...oauthHeaders };
}
🤖 Prompt for AI Agents
In packages/core/src/Components/APICall/APICall.class.ts around lines 117-122,
the condition allows undefined oauth_con_id to pass and headers are being
concatenated as if they were an array; update the gating to check for a truthy,
non-empty, non-'None' value (e.g. config?.data?.oauth_con_id &&
config.data.oauth_con_id !== 'None') and replace the concat with an object merge
that ensures headers is an object (e.g. reqConfig.headers = {
...(reqConfig.headers || {}), ...oauthHeaders }) so OAuth headers are only added
when present and merged correctly.

Expand Down
54 changes: 45 additions & 9 deletions packages/core/src/Components/APICall/AccessTokenManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,35 @@ class AccessTokenManager {
private secondaryToken: string; // refreshToken || tokenSecret
private tokenUrl: string; // tokenURL to refresh accessToken
private expires_in: any;
private data: any; // value of key(keyId) in teamSettings that needs to be updated if required
private keyId: any; // key of object in teamSettings
private tokensData: any; // Full tokens data object
private keyId: any; // key of object in teamSettings
private logger: any; // Use to log console in debugger
private agent: Agent;
private isNewStructure: boolean;
constructor(
clientId: string,
clientSecret: string,
secondaryToken: string,
tokenUrl: string,
expires_in: any,
primaryToken: string,
data: any,
tokensData: any,
keyId: any,
logger: any,
agent: Agent,
isNewStructure: boolean = false,
) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.primaryToken = primaryToken;
this.secondaryToken = secondaryToken;
this.tokenUrl = tokenUrl;
this.expires_in = expires_in;
this.data = data;
this.tokensData = tokensData;
this.keyId = keyId;
this.logger = logger;
this.agent = agent;
this.isNewStructure = isNewStructure;
}

async getAccessToken(): Promise<string> {
Expand Down Expand Up @@ -105,19 +108,52 @@ class AccessTokenManager {
this.logger.debug('Access token refreshed successfully.');
const expiresInMilliseconds: number = response?.data?.expires_in ? response?.data?.expires_in * 1000 : response?.data?.expires_in;
const expirationTimestamp: number = expiresInMilliseconds ? new Date().getTime() + expiresInMilliseconds : expiresInMilliseconds;
this.data.primary = newAccessToken;
this.data.expires_in = expirationTimestamp ? expirationTimestamp?.toString() : expirationTimestamp;
//const oauthTeamSettings = new OauthTeamSettings();
//const save: any = await oauthTeamSettings.update({ keyId: this.keyId, data: this.data });

const save: any = await managedVault.user(AccessCandidate.agent(this.agent.id)).set(this.keyId, JSON.stringify(this.data));
// Maintain the same structure format when saving
let updatedData;
if (this.isNewStructure) {
// Maintain new structure format
updatedData = {
...this.tokensData,
auth_data: {
...(this.tokensData?.auth_data ?? {}),
primary: newAccessToken,
// Persist rotated refresh_token when provided; fall back to existing
secondary: (response?.data?.refresh_token ?? this.secondaryToken),
// Use nullish check so 0 is preserved
expires_in: (expirationTimestamp ?? undefined) !== undefined ? String(expirationTimestamp) : undefined
}
};
} else {
// Maintain old structure format
updatedData = {
...this.tokensData,
primary: newAccessToken,
expires_in: (expirationTimestamp ?? undefined) !== undefined ? String(expirationTimestamp) : undefined
};
// Persist rotated refresh_token when provided; otherwise keep existing
updatedData.secondary = (response?.data?.refresh_token ?? this.secondaryToken);
}

const save: any = await managedVault.user(AccessCandidate.agent(this.agent.id)).set(this.keyId, JSON.stringify(updatedData));
if (save && save.status === 200) {
console.log('Access token value is updated successfully.');
this.logger.debug('Access token value is updated successfully.');
} else {
console.log('Warning: new access token value is not updated.');
this.logger.debug('Warning: new access token value is not updated.');
}

// Update internal tokensData reference
this.tokensData = updatedData;
this.primaryToken = newAccessToken;
// Update in-memory refresh token in case the provider rotated it
this.secondaryToken = (response?.data?.refresh_token ?? this.secondaryToken);
// Preserve 0 and avoid dropping undefined
this.expires_in =
(expirationTimestamp ?? undefined) !== undefined
? String(expirationTimestamp)
: undefined;
return newAccessToken;
} catch (error) {
console.error('Failed to refresh access token:', error);
Expand Down
Loading