PERF: Criado script para manter a porta 3001 sempre disponível
All checks were successful
Deploy Dev / deploy (push) Successful in 45s
All checks were successful
Deploy Dev / deploy (push) Successful in 45s
This commit is contained in:
parent
21a81282d5
commit
8790ce70d0
@ -5,6 +5,7 @@
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"start": "cross-env NODE_ENV=production node dist/main.js",
|
||||
"predev": "node scripts/ensure-port-free.js",
|
||||
"dev": "cross-env NODE_ENV=development nest start --watch",
|
||||
"start:dev": "npm run dev"
|
||||
},
|
||||
|
||||
89
scripts/ensure-port-free.js
Normal file
89
scripts/ensure-port-free.js
Normal file
@ -0,0 +1,89 @@
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function loadEnvFile(filePath) {
|
||||
if (!fs.existsSync(filePath)) return {};
|
||||
|
||||
return fs
|
||||
.readFileSync(filePath, 'utf8')
|
||||
.split(/\r?\n/)
|
||||
.reduce((acc, line) => {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) return acc;
|
||||
const separatorIndex = trimmed.indexOf('=');
|
||||
if (separatorIndex === -1) return acc;
|
||||
const key = trimmed.slice(0, separatorIndex).trim();
|
||||
const value = trimmed.slice(separatorIndex + 1).trim();
|
||||
acc[key] = value;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function getConfiguredPort() {
|
||||
const env = {
|
||||
...loadEnvFile(path.resolve(process.cwd(), '.env.development')),
|
||||
...process.env,
|
||||
};
|
||||
|
||||
return Number(env.PORT || env.BACKEND_PORT || 3001);
|
||||
}
|
||||
|
||||
function getWindowsPids(port) {
|
||||
const output = execSync(`netstat -ano -p tcp | findstr :${port}`, {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
});
|
||||
|
||||
return Array.from(
|
||||
new Set(
|
||||
output
|
||||
.split(/\r?\n/)
|
||||
.filter((line) => line.includes('LISTENING'))
|
||||
.map((line) => line.trim().split(/\s+/).at(-1))
|
||||
.filter(Boolean)
|
||||
.filter((pid) => pid !== String(process.pid)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function getUnixPids(port) {
|
||||
const output = execSync(`lsof -ti tcp:${port} -sTCP:LISTEN`, {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
});
|
||||
|
||||
return Array.from(
|
||||
new Set(
|
||||
output
|
||||
.split(/\r?\n/)
|
||||
.map((pid) => pid.trim())
|
||||
.filter(Boolean)
|
||||
.filter((pid) => pid !== String(process.pid)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function killPid(pid) {
|
||||
if (process.platform === 'win32') {
|
||||
execSync(`taskkill /PID ${pid} /F /T`, { stdio: 'ignore' });
|
||||
return;
|
||||
}
|
||||
|
||||
execSync(`kill -TERM ${pid}`, { stdio: 'ignore' });
|
||||
}
|
||||
|
||||
const port = getConfiguredPort();
|
||||
|
||||
try {
|
||||
const pids = process.platform === 'win32' ? getWindowsPids(port) : getUnixPids(port);
|
||||
|
||||
if (!pids.length) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
pids.forEach(killPid);
|
||||
console.log(`Porta ${port} liberada. Processo(s) encerrado(s): ${pids.join(', ')}`);
|
||||
} catch {
|
||||
process.exit(0);
|
||||
}
|
||||
16
src/main.ts
16
src/main.ts
@ -9,10 +9,24 @@ async function bootstrap() {
|
||||
|
||||
const app = await NestFactory.create(AppModule);
|
||||
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
|
||||
const allowedOrigins = new Set(
|
||||
frontendUrl
|
||||
.split(',')
|
||||
.map((origin) => origin.trim())
|
||||
.filter(Boolean),
|
||||
);
|
||||
allowedOrigins.add('http://localhost:3000');
|
||||
allowedOrigins.add('http://localhost:5173');
|
||||
const port = Number(process.env.PORT || process.env.BACKEND_PORT || 3001);
|
||||
|
||||
app.enableCors({
|
||||
origin: frontendUrl,
|
||||
origin(origin, callback) {
|
||||
if (!origin || allowedOrigins.has(origin)) {
|
||||
callback(null, true);
|
||||
return;
|
||||
}
|
||||
callback(new Error(`Origem CORS nao permitida: ${origin}`));
|
||||
},
|
||||
credentials: true,
|
||||
});
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ export class LdapAuthProvider {
|
||||
|
||||
async authenticate({ username, password }: LoginData): Promise<AuthResult> {
|
||||
const config = this.authConfig.getConfig();
|
||||
const normalizedUsername = this.normalizeUsername(username);
|
||||
|
||||
if (!config.ldap.enabled) {
|
||||
throw new ForbiddenException('Login AD/LDAP desabilitado');
|
||||
@ -24,7 +25,7 @@ export class LdapAuthProvider {
|
||||
throw new Error('LDAP_URL nao configurado');
|
||||
}
|
||||
|
||||
if (!username || !password) {
|
||||
if (!normalizedUsername || !password) {
|
||||
throw new UnauthorizedException('Usuario e senha sao obrigatorios');
|
||||
}
|
||||
|
||||
@ -39,17 +40,19 @@ export class LdapAuthProvider {
|
||||
await client.bind(config.ldap.bindDn, config.ldap.bindPassword);
|
||||
}
|
||||
|
||||
const userPrincipal = this.buildUserPrincipal(username);
|
||||
const userPrincipal = this.buildUserPrincipal(normalizedUsername);
|
||||
await client.bind(userPrincipal, password);
|
||||
|
||||
const directoryUser = await this.searchUser(client, username);
|
||||
const directoryUser = await this.searchUser(client, this.getSearchUsername(normalizedUsername));
|
||||
const providerUser = {
|
||||
id: directoryUser?.email || userPrincipal,
|
||||
name: directoryUser?.name || username,
|
||||
name: directoryUser?.name || normalizedUsername,
|
||||
email:
|
||||
directoryUser?.email ||
|
||||
(config.ldap.domain ? `${username}@${config.ldap.domain}` : null),
|
||||
username: directoryUser?.username || username,
|
||||
(config.ldap.domain && !normalizedUsername.includes('@')
|
||||
? `${normalizedUsername}@${config.ldap.domain}`
|
||||
: normalizedUsername),
|
||||
username: directoryUser?.username || normalizedUsername,
|
||||
provider: 'ldap' as const,
|
||||
};
|
||||
const user = await this.userAccess.syncAuthenticatedUser(providerUser);
|
||||
@ -59,7 +62,7 @@ export class LdapAuthProvider {
|
||||
user,
|
||||
};
|
||||
} catch (_error) {
|
||||
throw new UnauthorizedException('Autenticacao AD/LDAP falhou');
|
||||
throw new UnauthorizedException('Autenticação falhou');
|
||||
} finally {
|
||||
await client.unbind().catch(() => undefined);
|
||||
}
|
||||
@ -72,6 +75,10 @@ export class LdapAuthProvider {
|
||||
return config.ldap.userDnTemplate.replaceAll('{{username}}', username);
|
||||
}
|
||||
|
||||
if (username.includes('@')) {
|
||||
return username;
|
||||
}
|
||||
|
||||
if (config.ldap.domain) {
|
||||
return `${username}@${config.ldap.domain}`;
|
||||
}
|
||||
@ -79,6 +86,14 @@ export class LdapAuthProvider {
|
||||
return username;
|
||||
}
|
||||
|
||||
private normalizeUsername(username: string) {
|
||||
return String(username || '').trim();
|
||||
}
|
||||
|
||||
private getSearchUsername(username: string) {
|
||||
return username.includes('@') ? username.split('@')[0] : username;
|
||||
}
|
||||
|
||||
private async searchUser(client: Client, username: string) {
|
||||
const config = this.authConfig.getConfig();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user