mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
🐛 Fix some issues with uncaught errors #1906
This commit is contained in:
parent
9118e090e7
commit
3aec53e2cc
|
@ -927,32 +927,37 @@ class App {
|
||||||
|
|
||||||
// Returns the node icon
|
// Returns the node icon
|
||||||
this.app.get([`/${this.restEndpoint}/node-icon/:nodeType`, `/${this.restEndpoint}/node-icon/:scope/:nodeType`], async (req: express.Request, res: express.Response): Promise<void> => {
|
this.app.get([`/${this.restEndpoint}/node-icon/:nodeType`, `/${this.restEndpoint}/node-icon/:scope/:nodeType`], async (req: express.Request, res: express.Response): Promise<void> => {
|
||||||
const nodeTypeName = `${req.params.scope ? `${req.params.scope}/` : ''}${req.params.nodeType}`;
|
try {
|
||||||
|
const nodeTypeName = `${req.params.scope ? `${req.params.scope}/` : ''}${req.params.nodeType}`;
|
||||||
|
|
||||||
const nodeTypes = NodeTypes();
|
const nodeTypes = NodeTypes();
|
||||||
const nodeType = nodeTypes.getByName(nodeTypeName);
|
const nodeType = nodeTypes.getByName(nodeTypeName);
|
||||||
|
|
||||||
if (nodeType === undefined) {
|
if (nodeType === undefined) {
|
||||||
res.status(404).send('The nodeType is not known.');
|
res.status(404).send('The nodeType is not known.');
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeType.description.icon === undefined) {
|
||||||
|
res.status(404).send('No icon found for node.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nodeType.description.icon.startsWith('file:')) {
|
||||||
|
res.status(404).send('Node does not have a file icon.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filepath = nodeType.description.icon.substr(5);
|
||||||
|
|
||||||
|
const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days
|
||||||
|
res.setHeader('Cache-control', `private max-age=${maxAge}`);
|
||||||
|
|
||||||
|
res.sendFile(filepath);
|
||||||
|
} catch (error) {
|
||||||
|
// Error response
|
||||||
|
return ResponseHelper.sendErrorResponse(res, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeType.description.icon === undefined) {
|
|
||||||
res.status(404).send('No icon found for node.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nodeType.description.icon.startsWith('file:')) {
|
|
||||||
res.status(404).send('Node does not have a file icon.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filepath = nodeType.description.icon.substr(5);
|
|
||||||
|
|
||||||
const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
||||||
res.setHeader('Cache-control', `private max-age=${maxAge}`);
|
|
||||||
|
|
||||||
res.sendFile(filepath);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1316,70 +1321,75 @@ class App {
|
||||||
|
|
||||||
// Verify and store app code. Generate access tokens and store for respective credential.
|
// Verify and store app code. Generate access tokens and store for respective credential.
|
||||||
this.app.get(`/${this.restEndpoint}/oauth1-credential/callback`, async (req: express.Request, res: express.Response) => {
|
this.app.get(`/${this.restEndpoint}/oauth1-credential/callback`, async (req: express.Request, res: express.Response) => {
|
||||||
const { oauth_verifier, oauth_token, cid } = req.query;
|
|
||||||
|
|
||||||
if (oauth_verifier === undefined || oauth_token === undefined) {
|
|
||||||
const errorResponse = new ResponseHelper.ResponseError('Insufficient parameters for OAuth1 callback. Received following query parameters: ' + JSON.stringify(req.query), undefined, 503);
|
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await Db.collections.Credentials!.findOne(cid as any); // tslint:disable-line:no-any
|
|
||||||
if (result === undefined) {
|
|
||||||
const errorResponse = new ResponseHelper.ResponseError('The credential is not known.', undefined, 404);
|
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
let encryptionKey = undefined;
|
|
||||||
encryptionKey = await UserSettings.getEncryptionKey();
|
|
||||||
if (encryptionKey === undefined) {
|
|
||||||
const errorResponse = new ResponseHelper.ResponseError('No encryption key got found to decrypt the credentials!', undefined, 503);
|
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt the currently saved credentials
|
|
||||||
const workflowCredentials: IWorkflowCredentials = {
|
|
||||||
[result.type as string]: {
|
|
||||||
[result.name as string]: result as ICredentialsEncrypted,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const mode: WorkflowExecuteMode = 'internal';
|
|
||||||
const credentialsHelper = new CredentialsHelper(workflowCredentials, encryptionKey);
|
|
||||||
const decryptedDataOriginal = credentialsHelper.getDecrypted(result.name, result.type, mode, true);
|
|
||||||
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, result.type, mode);
|
|
||||||
|
|
||||||
const options: OptionsWithUrl = {
|
|
||||||
method: 'POST',
|
|
||||||
url: _.get(oauthCredentials, 'accessTokenUrl') as string,
|
|
||||||
qs: {
|
|
||||||
oauth_token,
|
|
||||||
oauth_verifier,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let oauthToken;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
oauthToken = await requestPromise(options);
|
const { oauth_verifier, oauth_token, cid } = req.query;
|
||||||
|
|
||||||
|
if (oauth_verifier === undefined || oauth_token === undefined) {
|
||||||
|
const errorResponse = new ResponseHelper.ResponseError('Insufficient parameters for OAuth1 callback. Received following query parameters: ' + JSON.stringify(req.query), undefined, 503);
|
||||||
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await Db.collections.Credentials!.findOne(cid as any); // tslint:disable-line:no-any
|
||||||
|
if (result === undefined) {
|
||||||
|
const errorResponse = new ResponseHelper.ResponseError('The credential is not known.', undefined, 404);
|
||||||
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
let encryptionKey = undefined;
|
||||||
|
encryptionKey = await UserSettings.getEncryptionKey();
|
||||||
|
if (encryptionKey === undefined) {
|
||||||
|
const errorResponse = new ResponseHelper.ResponseError('No encryption key got found to decrypt the credentials!', undefined, 503);
|
||||||
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the currently saved credentials
|
||||||
|
const workflowCredentials: IWorkflowCredentials = {
|
||||||
|
[result.type as string]: {
|
||||||
|
[result.name as string]: result as ICredentialsEncrypted,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mode: WorkflowExecuteMode = 'internal';
|
||||||
|
const credentialsHelper = new CredentialsHelper(workflowCredentials, encryptionKey);
|
||||||
|
const decryptedDataOriginal = credentialsHelper.getDecrypted(result.name, result.type, mode, true);
|
||||||
|
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, result.type, mode);
|
||||||
|
|
||||||
|
const options: OptionsWithUrl = {
|
||||||
|
method: 'POST',
|
||||||
|
url: _.get(oauthCredentials, 'accessTokenUrl') as string,
|
||||||
|
qs: {
|
||||||
|
oauth_token,
|
||||||
|
oauth_verifier,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let oauthToken;
|
||||||
|
|
||||||
|
try {
|
||||||
|
oauthToken = await requestPromise(options);
|
||||||
|
} catch (error) {
|
||||||
|
const errorResponse = new ResponseHelper.ResponseError('Unable to get access tokens!', undefined, 404);
|
||||||
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response comes as x-www-form-urlencoded string so convert it to JSON
|
||||||
|
|
||||||
|
const oauthTokenJson = querystring.parse(oauthToken);
|
||||||
|
|
||||||
|
decryptedDataOriginal.oauthTokenData = oauthTokenJson;
|
||||||
|
|
||||||
|
const credentials = new Credentials(result.name, result.type, result.nodesAccess);
|
||||||
|
credentials.setData(decryptedDataOriginal, encryptionKey);
|
||||||
|
const newCredentialsData = credentials.getDataToSave() as unknown as ICredentialsDb;
|
||||||
|
// Add special database related data
|
||||||
|
newCredentialsData.updatedAt = this.getCurrentDate();
|
||||||
|
// Save the credentials in DB
|
||||||
|
await Db.collections.Credentials!.update(cid as any, newCredentialsData); // tslint:disable-line:no-any
|
||||||
|
|
||||||
|
res.sendFile(pathResolve(__dirname, '../../templates/oauth-callback.html'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorResponse = new ResponseHelper.ResponseError('Unable to get access tokens!', undefined, 404);
|
// Error response
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
return ResponseHelper.sendErrorResponse(res, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response comes as x-www-form-urlencoded string so convert it to JSON
|
|
||||||
|
|
||||||
const oauthTokenJson = querystring.parse(oauthToken);
|
|
||||||
|
|
||||||
decryptedDataOriginal.oauthTokenData = oauthTokenJson;
|
|
||||||
|
|
||||||
const credentials = new Credentials(result.name, result.type, result.nodesAccess);
|
|
||||||
credentials.setData(decryptedDataOriginal, encryptionKey);
|
|
||||||
const newCredentialsData = credentials.getDataToSave() as unknown as ICredentialsDb;
|
|
||||||
// Add special database related data
|
|
||||||
newCredentialsData.updatedAt = this.getCurrentDate();
|
|
||||||
// Save the credentials in DB
|
|
||||||
await Db.collections.Credentials!.update(cid as any, newCredentialsData); // tslint:disable-line:no-any
|
|
||||||
|
|
||||||
res.sendFile(pathResolve(__dirname, '../../templates/oauth-callback.html'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -1478,111 +1488,116 @@ class App {
|
||||||
|
|
||||||
// Verify and store app code. Generate access tokens and store for respective credential.
|
// Verify and store app code. Generate access tokens and store for respective credential.
|
||||||
this.app.get(`/${this.restEndpoint}/oauth2-credential/callback`, async (req: express.Request, res: express.Response) => {
|
this.app.get(`/${this.restEndpoint}/oauth2-credential/callback`, async (req: express.Request, res: express.Response) => {
|
||||||
|
|
||||||
// realmId it's currently just use for the quickbook OAuth2 flow
|
|
||||||
const { code, state: stateEncoded } = req.query;
|
|
||||||
|
|
||||||
if (code === undefined || stateEncoded === undefined) {
|
|
||||||
const errorResponse = new ResponseHelper.ResponseError('Insufficient parameters for OAuth2 callback. Received following query parameters: ' + JSON.stringify(req.query), undefined, 503);
|
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
let state;
|
|
||||||
try {
|
try {
|
||||||
state = JSON.parse(Buffer.from(stateEncoded as string, 'base64').toString());
|
|
||||||
} catch (error) {
|
|
||||||
const errorResponse = new ResponseHelper.ResponseError('Invalid state format returned', undefined, 503);
|
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await Db.collections.Credentials!.findOne(state.cid);
|
// realmId it's currently just use for the quickbook OAuth2 flow
|
||||||
if (result === undefined) {
|
const { code, state: stateEncoded } = req.query;
|
||||||
const errorResponse = new ResponseHelper.ResponseError('The credential is not known.', undefined, 404);
|
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
let encryptionKey = undefined;
|
if (code === undefined || stateEncoded === undefined) {
|
||||||
encryptionKey = await UserSettings.getEncryptionKey();
|
const errorResponse = new ResponseHelper.ResponseError('Insufficient parameters for OAuth2 callback. Received following query parameters: ' + JSON.stringify(req.query), undefined, 503);
|
||||||
if (encryptionKey === undefined) {
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
const errorResponse = new ResponseHelper.ResponseError('No encryption key got found to decrypt the credentials!', undefined, 503);
|
}
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrypt the currently saved credentials
|
let state;
|
||||||
const workflowCredentials: IWorkflowCredentials = {
|
try {
|
||||||
[result.type as string]: {
|
state = JSON.parse(Buffer.from(stateEncoded as string, 'base64').toString());
|
||||||
[result.name as string]: result as ICredentialsEncrypted,
|
} catch (error) {
|
||||||
},
|
const errorResponse = new ResponseHelper.ResponseError('Invalid state format returned', undefined, 503);
|
||||||
};
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
const mode: WorkflowExecuteMode = 'internal';
|
}
|
||||||
const credentialsHelper = new CredentialsHelper(workflowCredentials, encryptionKey);
|
|
||||||
const decryptedDataOriginal = credentialsHelper.getDecrypted(result.name, result.type, mode, true);
|
|
||||||
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, result.type, mode);
|
|
||||||
|
|
||||||
const token = new csrf();
|
const result = await Db.collections.Credentials!.findOne(state.cid);
|
||||||
if (decryptedDataOriginal.csrfSecret === undefined || !token.verify(decryptedDataOriginal.csrfSecret as string, state.token)) {
|
if (result === undefined) {
|
||||||
const errorResponse = new ResponseHelper.ResponseError('The OAuth2 callback state is invalid!', undefined, 404);
|
const errorResponse = new ResponseHelper.ResponseError('The credential is not known.', undefined, 404);
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
let options = {};
|
let encryptionKey = undefined;
|
||||||
|
encryptionKey = await UserSettings.getEncryptionKey();
|
||||||
|
if (encryptionKey === undefined) {
|
||||||
|
const errorResponse = new ResponseHelper.ResponseError('No encryption key got found to decrypt the credentials!', undefined, 503);
|
||||||
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
const oAuth2Parameters = {
|
// Decrypt the currently saved credentials
|
||||||
clientId: _.get(oauthCredentials, 'clientId') as string,
|
const workflowCredentials: IWorkflowCredentials = {
|
||||||
clientSecret: _.get(oauthCredentials, 'clientSecret', '') as string | undefined,
|
[result.type as string]: {
|
||||||
accessTokenUri: _.get(oauthCredentials, 'accessTokenUrl', '') as string,
|
[result.name as string]: result as ICredentialsEncrypted,
|
||||||
authorizationUri: _.get(oauthCredentials, 'authUrl', '') as string,
|
|
||||||
redirectUri: `${WebhookHelpers.getWebhookBaseUrl()}${this.restEndpoint}/oauth2-credential/callback`,
|
|
||||||
scopes: _.split(_.get(oauthCredentials, 'scope', 'openid,') as string, ','),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_.get(oauthCredentials, 'authentication', 'header') as string === 'body') {
|
|
||||||
options = {
|
|
||||||
body: {
|
|
||||||
client_id: _.get(oauthCredentials, 'clientId') as string,
|
|
||||||
client_secret: _.get(oauthCredentials, 'clientSecret', '') as string,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
delete oAuth2Parameters.clientSecret;
|
const mode: WorkflowExecuteMode = 'internal';
|
||||||
|
const credentialsHelper = new CredentialsHelper(workflowCredentials, encryptionKey);
|
||||||
|
const decryptedDataOriginal = credentialsHelper.getDecrypted(result.name, result.type, mode, true);
|
||||||
|
const oauthCredentials = credentialsHelper.applyDefaultsAndOverwrites(decryptedDataOriginal, result.type, mode);
|
||||||
|
|
||||||
|
const token = new csrf();
|
||||||
|
if (decryptedDataOriginal.csrfSecret === undefined || !token.verify(decryptedDataOriginal.csrfSecret as string, state.token)) {
|
||||||
|
const errorResponse = new ResponseHelper.ResponseError('The OAuth2 callback state is invalid!', undefined, 404);
|
||||||
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
let options = {};
|
||||||
|
|
||||||
|
const oAuth2Parameters = {
|
||||||
|
clientId: _.get(oauthCredentials, 'clientId') as string,
|
||||||
|
clientSecret: _.get(oauthCredentials, 'clientSecret', '') as string | undefined,
|
||||||
|
accessTokenUri: _.get(oauthCredentials, 'accessTokenUrl', '') as string,
|
||||||
|
authorizationUri: _.get(oauthCredentials, 'authUrl', '') as string,
|
||||||
|
redirectUri: `${WebhookHelpers.getWebhookBaseUrl()}${this.restEndpoint}/oauth2-credential/callback`,
|
||||||
|
scopes: _.split(_.get(oauthCredentials, 'scope', 'openid,') as string, ','),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_.get(oauthCredentials, 'authentication', 'header') as string === 'body') {
|
||||||
|
options = {
|
||||||
|
body: {
|
||||||
|
client_id: _.get(oauthCredentials, 'clientId') as string,
|
||||||
|
client_secret: _.get(oauthCredentials, 'clientSecret', '') as string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
delete oAuth2Parameters.clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.externalHooks.run('oauth2.callback', [oAuth2Parameters]);
|
||||||
|
|
||||||
|
const oAuthObj = new clientOAuth2(oAuth2Parameters);
|
||||||
|
|
||||||
|
const queryParameters = req.originalUrl.split('?').splice(1, 1).join('');
|
||||||
|
|
||||||
|
const oauthToken = await oAuthObj.code.getToken(`${oAuth2Parameters.redirectUri}?${queryParameters}`, options);
|
||||||
|
|
||||||
|
if (Object.keys(req.query).length > 2) {
|
||||||
|
_.set(oauthToken.data, 'callbackQueryString', _.omit(req.query, 'state', 'code'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oauthToken === undefined) {
|
||||||
|
const errorResponse = new ResponseHelper.ResponseError('Unable to get access tokens!', undefined, 404);
|
||||||
|
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decryptedDataOriginal.oauthTokenData) {
|
||||||
|
// Only overwrite supplied data as some providers do for example just return the
|
||||||
|
// refresh_token on the very first request and not on subsequent ones.
|
||||||
|
Object.assign(decryptedDataOriginal.oauthTokenData, oauthToken.data);
|
||||||
|
} else {
|
||||||
|
// No data exists so simply set
|
||||||
|
decryptedDataOriginal.oauthTokenData = oauthToken.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_.unset(decryptedDataOriginal, 'csrfSecret');
|
||||||
|
|
||||||
|
const credentials = new Credentials(result.name, result.type, result.nodesAccess);
|
||||||
|
credentials.setData(decryptedDataOriginal, encryptionKey);
|
||||||
|
const newCredentialsData = credentials.getDataToSave() as unknown as ICredentialsDb;
|
||||||
|
// Add special database related data
|
||||||
|
newCredentialsData.updatedAt = this.getCurrentDate();
|
||||||
|
// Save the credentials in DB
|
||||||
|
await Db.collections.Credentials!.update(state.cid, newCredentialsData);
|
||||||
|
|
||||||
|
res.sendFile(pathResolve(__dirname, '../../templates/oauth-callback.html'));
|
||||||
|
} catch (error) {
|
||||||
|
// Error response
|
||||||
|
return ResponseHelper.sendErrorResponse(res, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.externalHooks.run('oauth2.callback', [oAuth2Parameters]);
|
|
||||||
|
|
||||||
const oAuthObj = new clientOAuth2(oAuth2Parameters);
|
|
||||||
|
|
||||||
const queryParameters = req.originalUrl.split('?').splice(1, 1).join('');
|
|
||||||
|
|
||||||
const oauthToken = await oAuthObj.code.getToken(`${oAuth2Parameters.redirectUri}?${queryParameters}`, options);
|
|
||||||
|
|
||||||
if (Object.keys(req.query).length > 2) {
|
|
||||||
_.set(oauthToken.data, 'callbackQueryString', _.omit(req.query, 'state', 'code'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oauthToken === undefined) {
|
|
||||||
const errorResponse = new ResponseHelper.ResponseError('Unable to get access tokens!', undefined, 404);
|
|
||||||
return ResponseHelper.sendErrorResponse(res, errorResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decryptedDataOriginal.oauthTokenData) {
|
|
||||||
// Only overwrite supplied data as some providers do for example just return the
|
|
||||||
// refresh_token on the very first request and not on subsequent ones.
|
|
||||||
Object.assign(decryptedDataOriginal.oauthTokenData, oauthToken.data);
|
|
||||||
} else {
|
|
||||||
// No data exists so simply set
|
|
||||||
decryptedDataOriginal.oauthTokenData = oauthToken.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
_.unset(decryptedDataOriginal, 'csrfSecret');
|
|
||||||
|
|
||||||
const credentials = new Credentials(result.name, result.type, result.nodesAccess);
|
|
||||||
credentials.setData(decryptedDataOriginal, encryptionKey);
|
|
||||||
const newCredentialsData = credentials.getDataToSave() as unknown as ICredentialsDb;
|
|
||||||
// Add special database related data
|
|
||||||
newCredentialsData.updatedAt = this.getCurrentDate();
|
|
||||||
// Save the credentials in DB
|
|
||||||
await Db.collections.Credentials!.update(state.cid, newCredentialsData);
|
|
||||||
|
|
||||||
res.sendFile(pathResolve(__dirname, '../../templates/oauth-callback.html'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue