New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

imapflow

Package Overview
Dependencies
Maintainers
0
Versions
171
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

imapflow - npm Package Compare versions

Comparing version 1.0.166 to 1.0.167

7

CHANGELOG.md
# Changelog
## [1.0.167](https://github.com/postalsys/imapflow/compare/v1.0.166...v1.0.167) (2024-11-07)
### Bug Fixes
* **auth:** Prefer AUTH=LOGIN and AUTH=PLAIN to LOGIN ([3efd98a](https://github.com/postalsys/imapflow/commit/3efd98a5033db29228023302fc4663316b2b28fb))
## [1.0.166](https://github.com/postalsys/imapflow/compare/v1.0.165...v1.0.166) (2024-11-05)

@@ -4,0 +11,0 @@

195

lib/commands/authenticate.js

@@ -5,68 +5,161 @@ 'use strict';

// Authenticates user using LOGIN
module.exports = async (connection, username, accessToken) => {
if (connection.state !== connection.states.NOT_AUTHENTICATED) {
// nothing to do here
return;
async function authOauth(connection, username, accessToken) {
let oauthbearer;
let command;
let breaker;
if (connection.capabilities.has('AUTH=OAUTHBEARER')) {
oauthbearer = [`n,a=${username},`, `host=${connection.servername}`, `port=993`, `auth=Bearer ${accessToken}`, '', ''].join('\x01');
command = 'OAUTHBEARER';
breaker = 'AQ==';
} else if (connection.capabilities.has('AUTH=XOAUTH') || connection.capabilities.has('AUTH=XOAUTH2')) {
oauthbearer = [`user=${username}`, `auth=Bearer ${accessToken}`, '', ''].join('\x01');
command = 'XOAUTH2';
breaker = '';
}
// AUTH=OAUTHBEARER and AUTH=XOAUTH in the context of OAuth2 or very similar so we can handle these together
if (connection.capabilities.has('AUTH=OAUTHBEARER') || connection.capabilities.has('AUTH=XOAUTH') || connection.capabilities.has('AUTH=XOAUTH2')) {
let oauthbearer;
let command;
let breaker;
let errorResponse = false;
try {
let response = await connection.exec(
'AUTHENTICATE',
[
{ type: 'ATOM', value: command },
{ type: 'ATOM', value: Buffer.from(oauthbearer).toString('base64'), sensitive: true }
],
{
onPlusTag: async resp => {
if (resp.attributes && resp.attributes[0] && resp.attributes[0].type === 'TEXT') {
try {
errorResponse = JSON.parse(Buffer.from(resp.attributes[0].value, 'base64').toString());
} catch (err) {
connection.log.debug({ errorResponse: resp.attributes[0].value, err });
}
}
if (connection.capabilities.has('AUTH=OAUTHBEARER')) {
oauthbearer = [`n,a=${username},`, `host=${connection.servername}`, `port=993`, `auth=Bearer ${accessToken}`, '', ''].join('\x01');
command = 'OAUTHBEARER';
breaker = 'AQ==';
} else if (connection.capabilities.has('AUTH=XOAUTH') || connection.capabilities.has('AUTH=XOAUTH2')) {
oauthbearer = [`user=${username}`, `auth=Bearer ${accessToken}`, '', ''].join('\x01');
command = 'XOAUTH2';
breaker = '';
connection.log.debug({ src: 'c', msg: breaker, comment: `Error response for ${command}` });
connection.write(breaker);
}
}
);
response.next();
connection.authCapabilities.set(`AUTH=${command}`, true);
return username;
} catch (err) {
let errorCode = getStatusCode(err.response);
if (errorCode) {
err.serverResponseCode = errorCode;
}
err.authenticationFailed = true;
err.response = await getErrorText(err.response);
if (errorResponse) {
err.oauthError = errorResponse;
}
throw err;
}
}
let errorResponse = false;
try {
let response = await connection.exec(
'AUTHENTICATE',
[
{ type: 'ATOM', value: command },
{ type: 'ATOM', value: Buffer.from(oauthbearer).toString('base64'), sensitive: true }
],
{
onPlusTag: async resp => {
if (resp.attributes && resp.attributes[0] && resp.attributes[0].type === 'TEXT') {
try {
errorResponse = JSON.parse(Buffer.from(resp.attributes[0].value, 'base64').toString());
} catch (err) {
connection.log.debug({ errorResponse: resp.attributes[0].value, err });
}
async function authLogin(connection, username, password) {
let errorResponse = false;
try {
let response = await connection.exec('AUTHENTICATE', [{ type: 'ATOM', value: 'LOGIN' }], {
onPlusTag: async resp => {
if (resp.attributes && resp.attributes[0] && resp.attributes[0].type === 'TEXT') {
let question = Buffer.from(resp.attributes[0].value, 'base64').toString();
switch (question.toLowerCase().replace(/:$/, '')) {
case 'username': {
let encodedUsername = Buffer.from(username).toString('base64');
connection.log.debug({ src: 'c', msg: encodedUsername, comment: `Encoded username for AUTH=LOGIN` });
connection.write(encodedUsername);
break;
}
connection.log.debug({ src: 'c', msg: breaker, comment: `Error response for ${command}` });
connection.write(breaker);
case 'password':
connection.log.debug({ src: 'c', msg: '(* value hidden *)', comment: `Encoded password for AUTH=LOGIN` });
connection.write(Buffer.from(password).toString('base64'));
break;
default: {
let error = new Error(`Unknown LOGIN question "${question}"`);
throw error;
}
}
}
);
response.next();
}
});
connection.authCapabilities.set(`AUTH=${command}`, true);
response.next();
return username;
} catch (err) {
let errorCode = getStatusCode(err.response);
if (errorCode) {
err.serverResponseCode = errorCode;
connection.authCapabilities.set(`AUTH=LOGIN`, true);
return username;
} catch (err) {
let errorCode = getStatusCode(err.response);
if (errorCode) {
err.serverResponseCode = errorCode;
}
err.authenticationFailed = true;
err.response = await getErrorText(err.response);
if (errorResponse) {
err.oauthError = errorResponse;
}
throw err;
}
}
async function authPlain(connection, username, password) {
let errorResponse = false;
try {
let response = await connection.exec('AUTHENTICATE', [{ type: 'ATOM', value: 'PLAIN' }], {
onPlusTag: async () => {
let encodedResponse = Buffer.from(['', username, password].join('\x00')).toString('base64');
let loggedResponse = Buffer.from(['', username, '(* value hidden *)'].join('\x00')).toString('base64');
connection.log.debug({ src: 'c', msg: loggedResponse, comment: `Encoded response for AUTH=PLAIN` });
connection.write(encodedResponse);
}
err.authenticationFailed = true;
err.response = await getErrorText(err.response);
if (errorResponse) {
err.oauthError = errorResponse;
}
throw err;
});
response.next();
connection.authCapabilities.set(`AUTH=PLAIN`, true);
return username;
} catch (err) {
let errorCode = getStatusCode(err.response);
if (errorCode) {
err.serverResponseCode = errorCode;
}
err.authenticationFailed = true;
err.response = await getErrorText(err.response);
if (errorResponse) {
err.oauthError = errorResponse;
}
throw err;
}
}
// Authenticates user using LOGIN
module.exports = async (connection, username, { accessToken, password }) => {
if (connection.state !== connection.states.NOT_AUTHENTICATED) {
// nothing to do here
return;
}
if (accessToken) {
// AUTH=OAUTHBEARER and AUTH=XOAUTH in the context of OAuth2 or very similar so we can handle these together
if (connection.capabilities.has('AUTH=OAUTHBEARER') || connection.capabilities.has('AUTH=XOAUTH') || connection.capabilities.has('AUTH=XOAUTH2')) {
return await authOauth(connection, username, accessToken);
}
}
if (password) {
if (connection.capabilities.has('AUTH=LOGIN')) {
return await authLogin(connection, username, password);
}
if (connection.capabilities.has('AUTH=PLAIN')) {
return await authPlain(connection, username, password);
}
}
throw new Error('Unsupported authentication mechanism');
};
{
"name": "imapflow",
"version": "1.0.166",
"version": "1.0.167",
"description": "IMAP Client for Node",

@@ -5,0 +5,0 @@ "main": "./lib/imap-flow.js",

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc