Skip to content

Conversation

@JefersonRamos
Copy link
Contributor

@JefersonRamos JefersonRamos commented Nov 5, 2025

📋 Description

Durante o processo de logout de uma instância, as chaves associadas ao estado criptográfico não estavam sendo removidas corretamente do Redis.

Dessa forma, quando uma nova conexão era estabelecida reutilizando o mesmo instanceName, o Baileys carregava chaves antigas e inválidas, incompatíveis com o novo conjunto de credenciais (creds) gerado na reconexão.

Essa inconsistência gerava o seguinte sintoma prático:

A instância autenticava com sucesso;

Contudo, ao tentar enviar mensagens, entrava em estado de bloqueio, exibindo o status “aguardando mensagem” indefinidamente.

🔗 Related Issue


Closes #(issue_number)

🧪 Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧹 Code cleanup
  • 🔒 Security fix

🧪 Testing

  • Manual testing completed
  • Functionality verified in development environment
  • No breaking changes introduced
  • Tested with different connection types (if applicable)

📸 Screenshots (if applicable)

✅ Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have manually tested my changes thoroughly
  • I have verified the changes work with different scenarios
  • Any dependent changes have been merged and published

📝 Additional Notes

Summary by Sourcery

Ensure cryptographic keys are properly cleaned up on instance logout by adding and invoking removeCreds methods across auth state providers and logging deletion actions.

Bug Fixes:

  • Delete stale authentication keys from Redis and file storage on logout to prevent session lockups.

Enhancements:

  • Add removeCreds method to Prisma, Redis, and file-based auth state providers.
  • Invoke removeCreds in BaileysStartupService during instance logout for all configured storage backends.
  • Integrate Logger to record key deletion actions and warnings.

…o estado criptográfico não estavam sendo removidas corretamente do Redis.

Dessa forma, quando uma nova conexão era estabelecida reutilizando o mesmo instanceName, o Baileys carregava chaves antigas e inválidas, incompatíveis com o novo conjunto de credenciais (creds) gerado na reconexão.

Essa inconsistência gerava o seguinte sintoma prático:

A instância autenticava com sucesso;

Contudo, ao tentar enviar mensagens, entrava em estado de bloqueio, exibindo o status “aguardando mensagem” indefinidamente.
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 5, 2025

Reviewer's Guide

Ensures proper cleanup of authentication credentials on instance logout by adding removeCreds methods to all auth state handlers and invoking them during the logout flow to prevent stale keys from persisting.

Sequence diagram for updated logout credential cleanup process

sequenceDiagram
  participant "BaileysStartupService"
  participant "AuthStateProvider"
  participant "useMultiFileAuthStateRedisDb"
  participant "useMultiFileAuthStatePrisma"
  participant "Redis/DB/Provider"

  "BaileysStartupService"->>"AuthStateProvider": Call authStateProvider(instance.id)
  "BaileysStartupService"->>"AuthStateProvider": Call removeCreds()
  "AuthStateProvider"->>"Redis/DB/Provider": Remove session keys

  "BaileysStartupService"->>"useMultiFileAuthStateRedisDb": Call useMultiFileAuthStateRedisDb(instance.id, cache)
  "BaileysStartupService"->>"useMultiFileAuthStateRedisDb": Call removeCreds()
  "useMultiFileAuthStateRedisDb"->>"Redis/DB/Provider": Delete Redis keys

  "BaileysStartupService"->>"useMultiFileAuthStatePrisma": Call useMultiFileAuthStatePrisma(instance.id, cache)
  "BaileysStartupService"->>"useMultiFileAuthStatePrisma": Call removeCreds()
  "useMultiFileAuthStatePrisma"->>"Redis/DB/Provider": Delete DB/Redis keys
Loading

ER diagram for credential removal from Redis and DB on logout

erDiagram
  INSTANCE {
    string id
    string sessionId
  }
  REDIS {
    string key
    string value
  }
  DB {
    string sessionId
    string creds
  }

  INSTANCE ||--o{ REDIS : "removes keys on logout"
  INSTANCE ||--o{ DB : "removes creds on logout"
Loading

Class diagram for updated auth state handlers with removeCreds method

classDiagram
  class AuthStateProvider {
    +providerFiles: ProviderFiles
    +authStateProvider(instance: string): AuthState
  }
  class AuthState {
    +state: AuthenticationState
    +saveCreds(): Promise<void>
    +removeCreds(): Promise<void>
  }
  class useMultiFileAuthStatePrisma {
    +state: AuthenticationState
    +saveCreds(): Promise<void>
    +removeCreds(): Promise<void>
  }
  class useMultiFileAuthStateRedisDb {
    +state: AuthenticationState
    +saveCreds(): Promise<void>
    +removeCreds(): Promise<void>
  }

  AuthStateProvider --> AuthState
  useMultiFileAuthStatePrisma --|> AuthState
  useMultiFileAuthStateRedisDb --|> AuthState
Loading

File-Level Changes

Change Details Files
Implement removeCreds method in Prisma-based auth state handler
  • Imported and initialized Logger for the module
  • Added removeCreds function to delete session keys from Redis or fall back to deleteAuthKey
  • Extended returned auth state object to include removeCreds
src/utils/use-multi-file-auth-state-prisma.ts
Expose removeCreds in file-based auth state provider
  • Updated AuthState type to include removeCreds
  • Implemented removeCreds in AuthStateProvider using providerFiles.removeSession
  • Initialized logger and added logging within removeCreds
src/utils/use-multi-file-auth-state-provider-files.ts
Implement removeCreds in Redis-based auth state handler
  • Added removeCreds function leveraging cache.delete with warning log
  • Extended returned auth state to include removeCreds
src/utils/use-multi-file-auth-state-redis-db.ts
Integrate removeCreds calls into logout flow in Baileys startup service
  • After WebSocket close, call removeCreds for provider-based auth when enabled
  • Conditionally invoke removeCreds for Redis and Prisma auth states based on configuration flags
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • There’s significant duplication in the removeCreds implementation across Prisma, Redis, and file providers—consider extracting a shared helper to DRY up the code.
  • Review the logger instantiations and naming (e.g. Redis file using the Prisma logger name) and standardize log levels for consistency.
  • In BaileysStartupService, you could consolidate the three separate removeCreds calls into a unified loop or strategy to avoid repetitive authState loading.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- There’s significant duplication in the removeCreds implementation across Prisma, Redis, and file providers—consider extracting a shared helper to DRY up the code.
- Review the logger instantiations and naming (e.g. Redis file using the Prisma logger name) and standardize log levels for consistency.
- In BaileysStartupService, you could consolidate the three separate removeCreds calls into a unified loop or strategy to avoid repetitive authState loading.

## Individual Comments

### Comment 1
<location> `src/utils/use-multi-file-auth-state-provider-files.ts:93-99` </location>
<code_context>
       return response;
     };

+    const removeCreds = async () => {
+
+      const [response, error] = await this.providerFiles.removeSession(instance);
+      if (error) {
+        // this.logger.error(['removeData', error?.message, error?.stack]);
+        return;
+      }
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** removeCreds swallows errors silently; consider logging or surfacing them.

Errors from providerFiles.removeSession are currently ignored. If downstream consumers rely on error handling, log or propagate these errors.

```suggestion
    const removeCreds = async () => {

      const [response, error] = await this.providerFiles.removeSession(instance);
      if (error) {
        if (this.logger) {
          this.logger.error(['removeCreds', error?.message, error?.stack]);
        } else {
          console.error('removeCreds error:', error);
        }
        throw error;
      }
```
</issue_to_address>

### Comment 2
<location> `src/utils/use-multi-file-auth-state-provider-files.ts:152` </location>
<code_context>
   }
 }

+const logger = new Logger('useMultiFileAuthStatePrisma');
+
 export default async function useMultiFileAuthStatePrisma(
</code_context>

<issue_to_address>
**suggestion:** Logger instance name may be misleading in this context.

Consider renaming the logger to match the provider file's purpose for improved traceability.
</issue_to_address>

### Comment 3
<location> `src/utils/use-multi-file-auth-state-redis-db.ts:41-48` </location>
<code_context>
+  async function removeCreds(): Promise<any> {
+    try {
+
+      logger.warn({ action: 'redis.delete', instanceName });
+
+      return await cache.delete(instanceName);
</code_context>

<issue_to_address>
**suggestion:** Consider using logger.info for successful deletion and logger.warn only for errors.

Use logger.info to indicate successful deletion, and reserve logger.warn or logger.error for error cases to improve log clarity.

```suggestion
    try {
      logger.info({ action: 'redis.delete', instanceName });
      await cache.delete(instanceName);
    } catch (err) {
      logger.warn({ action: 'redis.delete.failed', instanceName, error: err });
      return;
    }
```
</issue_to_address>

### Comment 4
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:273-276` </location>
<code_context>
+    const cache = this.configService.get<CacheConf>('CACHE');
+    const provider = this.configService.get<ProviderSession>('PROVIDER');
+
+    if (provider?.ENABLED) {
+      const authState = await this.authStateProvider.authStateProvider(this.instance.id);
+
+      await authState.removeCreds()
+    }
+
</code_context>

<issue_to_address>
**suggestion:** Consider handling errors from removeCreds to avoid silent failures.

Currently, errors from removeCreds are ignored. Consider logging or handling these errors to improve reliability and traceability.
</issue_to_address>

### Comment 5
<location> `src/utils/use-multi-file-auth-state-prisma.ts:149-168` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

### Comment 6
<location> `src/utils/use-multi-file-auth-state-redis-db.ts:40-49` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines 93 to 99
const removeCreds = async () => {

const [response, error] = await this.providerFiles.removeSession(instance);
if (error) {
// this.logger.error(['removeData', error?.message, error?.stack]);
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (bug_risk): removeCreds swallows errors silently; consider logging or surfacing them.

Errors from providerFiles.removeSession are currently ignored. If downstream consumers rely on error handling, log or propagate these errors.

Suggested change
const removeCreds = async () => {
const [response, error] = await this.providerFiles.removeSession(instance);
if (error) {
// this.logger.error(['removeData', error?.message, error?.stack]);
return;
}
const removeCreds = async () => {
const [response, error] = await this.providerFiles.removeSession(instance);
if (error) {
if (this.logger) {
this.logger.error(['removeCreds', error?.message, error?.stack]);
} else {
console.error('removeCreds error:', error);
}
throw error;
}

Comment on lines 41 to 48
try {

logger.warn({ action: 'redis.delete', instanceName });

return await cache.delete(instanceName);
} catch {
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider using logger.info for successful deletion and logger.warn only for errors.

Use logger.info to indicate successful deletion, and reserve logger.warn or logger.error for error cases to improve log clarity.

Suggested change
try {
logger.warn({ action: 'redis.delete', instanceName });
return await cache.delete(instanceName);
} catch {
return;
}
try {
logger.info({ action: 'redis.delete', instanceName });
await cache.delete(instanceName);
} catch (err) {
logger.warn({ action: 'redis.delete.failed', instanceName, error: err });
return;
}

Comment on lines 149 to 168
async function removeCreds(): Promise<any> {

const cacheConfig = configService.get<CacheConf>('CACHE');

// Redis
try {
if (cacheConfig.REDIS.ENABLED) {
await cache.delete(sessionId);
logger.info({ action: 'redis.delete', sessionId });

return
}
} catch (err) {
logger.warn({ action: 'redis.delete', sessionId, err });
}

logger.info({ action: 'auth.key.delete', sessionId });

await deleteAuthKey(sessionId);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Avoid function declarations, favouring function assignment expressions, inside blocks. (avoid-function-declarations-in-blocks)

ExplanationFunction declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers. Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you should use function expressions, which create functions in-scope.

Comment on lines 40 to 49
async function removeCreds(): Promise<any> {
try {

logger.warn({ action: 'redis.delete', instanceName });

return await cache.delete(instanceName);
} catch {
return;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Avoid function declarations, favouring function assignment expressions, inside blocks. (avoid-function-declarations-in-blocks)

ExplanationFunction declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers. Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you should use function expressions, which create functions in-scope.

} else {
const { host, password, port, protocol: proto, username } = proxy
protocol = (proto || 'http').replace(':', '')
const { host, password, port, protocol: proto, username } = proxy;

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
} else {
const { host, password, port, protocol: proto, username } = proxy
protocol = (proto || 'http').replace(':', '')
const { host, password, port, protocol: proto, username } = proxy;

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
} else {
const { host, password, port, protocol: proto, username } = proxy
protocol = (proto || 'http').replace(':', '')
const { host, password, port, protocol: proto, username } = proxy;

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
} else {
const { host, password, port, protocol: proto, username } = proxy
protocol = (proto || 'http').replace(':', '')
const { host, password, port, protocol: proto, username } = proxy;

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
} else {
const { host, password, port, protocol: proto, username } = proxy
protocol = (proto || 'http').replace(':', '')
const { host, password, port, protocol: proto, username } = proxy;

Check failure

Code scanning / CodeQL

Insecure randomness High

This uses a cryptographically insecure random number generated at
Math.random()
in a security context.
@DavidsonGomes DavidsonGomes changed the base branch from main to develop November 7, 2025 17:37
@DavidsonGomes DavidsonGomes merged commit fca39a2 into EvolutionAPI:develop Nov 7, 2025
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants