Skip to content
Closed
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
35 changes: 28 additions & 7 deletions src/api/controllers/instance.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,36 @@ export class InstanceController {
status: instanceData.status,
});

instance.setInstance({
instanceName: instanceData.instanceName,
instanceId,
integration: instanceData.integration,
token: hash,
number: instanceData.number,
businessId: instanceData.businessId,
// Verifica se a Instance foi criada com sucesso antes de continuar
const createdInstance = await this.prismaRepository.instance.findUnique({
where: { id: instanceId },
});

if (!createdInstance) {
throw new BadRequestException('Failed to create instance in database');
}

// Para WhatsApp Business, setInstance é async e precisa ser aguardado
if (instanceData.integration === Integration.WHATSAPP_BUSINESS) {
await (instance as any).setInstance({
instanceName: instanceData.instanceName,
instanceId,
integration: instanceData.integration,
token: instanceData.token || hash, // Usa o token original completo
number: instanceData.number,
businessId: instanceData.businessId,
});
} else {
instance.setInstance({
instanceName: instanceData.instanceName,
instanceId,
integration: instanceData.integration,
token: hash,
number: instanceData.number,
businessId: instanceData.businessId,
});
}

this.waMonitor.waInstances[instance.instanceName] = instance;
this.waMonitor.delInstanceTime(instance.instanceName);

Expand Down
61 changes: 58 additions & 3 deletions src/api/guards/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { InstanceDto } from '@api/dto/instance.dto';
import { prismaRepository } from '@api/server.module';
import { cache, prismaRepository, waMonitor } from '@api/server.module';
import { Integration } from '@api/types/wa.types';
import { Auth, configService, Database } from '@config/env.config';
import { Logger } from '@config/logger.config';
import { ForbiddenException, UnauthorizedException } from '@exceptions';
Expand Down Expand Up @@ -30,15 +31,69 @@ async function apikey(req: Request, _: Response, next: NextFunction) {
const instance = await prismaRepository.instance.findUnique({
where: { name: param.instanceName },
});
if (instance.token === key) {
const keyToCompare = key.length > 255 ? key.substring(0, 255) : key;
if (instance.token === keyToCompare) {
// Se o token fornecido é maior que 255 e a instância é WhatsApp Business, salva no cache
if (key.length > 255 && instance.integration === Integration.WHATSAPP_BUSINESS) {
const cacheKey = `instance:${param.instanceName}:fullToken`;
await cache.set(cacheKey, key, 0);
logger.log({ message: 'Stored full token in cache from request', instanceName: param.instanceName });

// Atualiza a instância em memória se existir
if (waMonitor.waInstances[param.instanceName]) {
const waInstance = waMonitor.waInstances[param.instanceName];
if (waInstance && typeof (waInstance as any).setInstance === 'function') {
try {
await (waInstance as any).setInstance({
instanceName: param.instanceName,
instanceId: instance.id,
integration: instance.integration,
token: key,
number: instance.number,
businessId: instance.businessId,
});
logger.log({ message: 'Updated full token in memory', instanceName: param.instanceName });
} catch (error) {
logger.error({ message: 'Error updating token in memory', error, instanceName: param.instanceName });
}
}
}
}
return next();
}
} else {
if (req.originalUrl.includes('/instance/fetchInstances') && db.SAVE_DATA.INSTANCE) {
const keyToCompare = key.length > 255 ? key.substring(0, 255) : key;
const instanceByKey = await prismaRepository.instance.findFirst({
where: { token: key },
where: { token: keyToCompare },
});
if (instanceByKey) {
// Se o token fornecido é maior que 255 e a instância é WhatsApp Business, salva no cache
if (key.length > 255 && instanceByKey.integration === Integration.WHATSAPP_BUSINESS) {
const cacheKey = `instance:${instanceByKey.name}:fullToken`;
await cache.set(cacheKey, key, 0);
logger.log({ message: 'Stored full token in cache from request', instanceName: instanceByKey.name });

// Atualiza a instância em memória se existir
if (waMonitor.waInstances[instanceByKey.name]) {
const waInstance = waMonitor.waInstances[instanceByKey.name];
if (waInstance && typeof (waInstance as any).setInstance === 'function') {
try {
await (waInstance as any).setInstance({
instanceName: instanceByKey.name,
instanceId: instanceByKey.id,
integration: instanceByKey.integration,
token: key,
number: instanceByKey.number,
businessId: instanceByKey.businessId,
});
logger.log({ message: 'Updated full token in memory', instanceName: instanceByKey.name });
} catch (error) {
logger.error({ message: 'Error updating token in memory', error, instanceName: instanceByKey.name });
}
}
}
}
return next();
}
}
Expand Down
33 changes: 33 additions & 0 deletions src/api/integrations/channel/meta/whatsapp.business.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,44 @@ export class BusinessStartupService extends ChannelStartupService {
super(configService, eventEmitter, prismaRepository, chatwootCache);
}

private fullToken: string | null = null;

public stateConnection: wa.StateConnection = { state: 'open' };

public phoneNumber: string;
public mobile: boolean;

// Override token getter para retornar token completo se disponível
public get token(): string {
return this.fullToken || this.instance.token || '';
}

// Override setInstance para armazenar/carregar token completo
public async setInstance(instance: any) {
super.setInstance(instance);

// Se o token fornecido é maior que 255, é o token completo - armazena imediatamente
if (instance.token && instance.token.length > 255) {
this.fullToken = instance.token;
const cacheKey = `instance:${instance.instanceName}:fullToken`;
await this.cache.set(cacheKey, instance.token, 0);
this.logger.log({ message: 'Stored full token in cache', instanceName: instance.instanceName });
} else {
// Tenta carregar token completo do cache
const cacheKey = `instance:${instance.instanceName}:fullToken`;
const fullToken = await this.cache.get(cacheKey);
if (fullToken) {
this.fullToken = fullToken;
this.logger.log({ message: 'Loaded full token from cache', instanceName: instance.instanceName });
} else {
this.logger.warn({
message: 'Full token not found in cache, using truncated token',
instanceName: instance.instanceName,
});
}
}
}

public get connectionStatus() {
return this.stateConnection;
}
Expand Down
3 changes: 2 additions & 1 deletion src/api/integrations/event/websocket/websocket.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ export class WebsocketController extends EventController implements EventControl
return callback('apiKey is required', false);
}

const instance = await this.prismaRepository.instance.findFirst({ where: { token: apiKey } });
const keyToCompare = apiKey.length > 255 ? apiKey.substring(0, 255) : apiKey;
const instance = await this.prismaRepository.instance.findFirst({ where: { token: keyToCompare } });

if (!instance) {
const globalToken = configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
Expand Down
4 changes: 3 additions & 1 deletion src/api/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ export class AuthService {
return true;
}

// Compara apenas os primeiros 255 caracteres para verificar duplicatas
const tokenToCompare = token.length > 255 ? token.substring(0, 255) : token;
const instances = await this.prismaRepository.instance.findMany({
where: { token },
where: { token: tokenToCompare },
});

if (instances.length > 0) {
Expand Down
20 changes: 14 additions & 6 deletions src/api/services/channel.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,41 +157,49 @@ export class ChannelStartupService {
}

public async setSettings(data: SettingsDto) {
const truncate = (str: string | null | undefined, maxLength: number): string | null => {
if (!str) return null;
return str.length > maxLength ? str.substring(0, maxLength) : str;
};

const msgCall = truncate(data.msgCall, 100);
const wavoipToken = truncate(data.wavoipToken, 100);

await this.prismaRepository.setting.upsert({
where: {
instanceId: this.instanceId,
},
update: {
rejectCall: data.rejectCall,
msgCall: data.msgCall,
msgCall: msgCall,
groupsIgnore: data.groupsIgnore,
alwaysOnline: data.alwaysOnline,
readMessages: data.readMessages,
readStatus: data.readStatus,
syncFullHistory: data.syncFullHistory,
wavoipToken: data.wavoipToken,
wavoipToken: wavoipToken,
},
create: {
rejectCall: data.rejectCall,
msgCall: data.msgCall,
msgCall: msgCall,
groupsIgnore: data.groupsIgnore,
alwaysOnline: data.alwaysOnline,
readMessages: data.readMessages,
readStatus: data.readStatus,
syncFullHistory: data.syncFullHistory,
wavoipToken: data.wavoipToken,
wavoipToken: wavoipToken,
instanceId: this.instanceId,
},
});

this.localSettings.rejectCall = data?.rejectCall;
this.localSettings.msgCall = data?.msgCall;
this.localSettings.msgCall = msgCall;
this.localSettings.groupsIgnore = data?.groupsIgnore;
this.localSettings.alwaysOnline = data?.alwaysOnline;
this.localSettings.readMessages = data?.readMessages;
this.localSettings.readStatus = data?.readStatus;
this.localSettings.syncFullHistory = data?.syncFullHistory;
this.localSettings.wavoipToken = data?.wavoipToken;
this.localSettings.wavoipToken = wavoipToken;

if (this.localSettings.wavoipToken && this.localSettings.wavoipToken.length > 0) {
this.client.ws.close();
Expand Down
Loading
Loading