feat(core): Make OAuth2 error handling consistent with success handling (#5555)

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
Manish Dhanwal
2023-03-22 12:53:49 +01:00
committed by GitHub
parent 135b0d3e27
commit 40aacf9279
5 changed files with 87 additions and 35 deletions

View File

@@ -11,7 +11,6 @@ import type {
WorkflowExecuteMode,
INodeCredentialsDetails,
ICredentialsEncrypted,
IDataObject,
} from 'n8n-workflow';
import { LoggerProxy } from 'n8n-workflow';
import { resolve as pathResolve } from 'path';
@@ -112,7 +111,7 @@ oauth2CredentialController.get(
);
const token = new Csrf();
// Generate a CSRF prevention token and send it as a OAuth2 state stringma/ERR
// Generate a CSRF prevention token and send it as an OAuth2 state string
const csrfSecret = token.secretSync();
const state = {
token: token.create(csrfSecret),
@@ -174,6 +173,9 @@ oauth2CredentialController.get(
}),
);
const renderCallbackError = (res: express.Response, errorMessage: string) =>
res.render('oauth-error-callback', { error: { message: errorMessage } });
/**
* GET /oauth2-credential/callback
*
@@ -188,12 +190,12 @@ oauth2CredentialController.get(
const { code, state: stateEncoded } = req.query;
if (!code || !stateEncoded) {
const errorResponse = new ResponseHelper.ServiceUnavailableError(
return renderCallbackError(
res,
`Insufficient parameters for OAuth2 callback. Received following query parameters: ${JSON.stringify(
req.query,
)}`,
);
return ResponseHelper.sendErrorResponse(res, errorResponse);
}
let state;
@@ -203,31 +205,21 @@ oauth2CredentialController.get(
token: string;
};
} catch (error) {
const errorResponse = new ResponseHelper.ServiceUnavailableError(
'Invalid state format returned',
);
return ResponseHelper.sendErrorResponse(res, errorResponse);
return renderCallbackError(res, 'Invalid state format returned');
}
const credential = await getCredentialWithoutUser(state.cid);
if (!credential) {
LoggerProxy.error('OAuth2 callback failed because of insufficient permissions', {
const errorMessage = 'OAuth2 callback failed because of insufficient permissions';
LoggerProxy.error(errorMessage, {
userId: req.user?.id,
credentialId: state.cid,
});
const errorResponse = new ResponseHelper.NotFoundError(
RESPONSE_ERROR_MESSAGES.NO_CREDENTIAL,
);
return ResponseHelper.sendErrorResponse(res, errorResponse);
return renderCallbackError(res, errorMessage);
}
let encryptionKey: string;
try {
encryptionKey = await UserSettings.getEncryptionKey();
} catch (error) {
throw new ResponseHelper.InternalServerError((error as IDataObject).message as string);
}
const encryptionKey = await UserSettings.getEncryptionKey();
const mode: WorkflowExecuteMode = 'internal';
const timezone = config.getEnv('generic.timezone');
@@ -251,14 +243,12 @@ oauth2CredentialController.get(
decryptedDataOriginal.csrfSecret === undefined ||
!token.verify(decryptedDataOriginal.csrfSecret as string, state.token)
) {
LoggerProxy.debug('OAuth2 callback state is invalid', {
const errorMessage = 'The OAuth2 callback state is invalid!';
LoggerProxy.debug(errorMessage, {
userId: req.user?.id,
credentialId: state.cid,
});
const errorResponse = new ResponseHelper.NotFoundError(
'The OAuth2 callback state is invalid!',
);
return ResponseHelper.sendErrorResponse(res, errorResponse);
return renderCallbackError(res, errorMessage);
}
let options = {};
@@ -298,12 +288,12 @@ oauth2CredentialController.get(
}
if (oauthToken === undefined) {
LoggerProxy.error('OAuth2 callback failed: unable to get access tokens', {
const errorMessage = 'Unable to get OAuth2 access tokens!';
LoggerProxy.error(errorMessage, {
userId: req.user?.id,
credentialId: state.cid,
});
const errorResponse = new ResponseHelper.NotFoundError('Unable to get access tokens!');
return ResponseHelper.sendErrorResponse(res, errorResponse);
return renderCallbackError(res, errorMessage);
}
if (decryptedDataOriginal.oauthTokenData) {
@@ -336,9 +326,7 @@ oauth2CredentialController.get(
return res.sendFile(pathResolve(TEMPLATES_DIR, 'oauth-callback.html'));
} catch (error) {
// Error response
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
return ResponseHelper.sendErrorResponse(res, error);
return renderCallbackError(res, (error as Error).message);
}
},
);