@purecore/one-server-4-all 0.1.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/COMPARACAO_LIVE_SERVER.md +37 -35
- package/README.md +44 -26
- package/dist/cert-generator.js +62 -44
- package/dist/deployer.js +10 -11
- package/dist/index.js +1 -1
- package/dist/server.js +8 -8
- package/hot-server.deps.graflow +1 -1
- package/package.json +3 -2
- package/reports/21-12-2025_04-21.md +25 -4
- package/reports/31-12-2025_21-15.md +2 -2
- package/reports/31-12-2025_21-45.md +1 -1
- package/reports/31-12-2025_22-00.md +1 -1
- package/src/cert-generator.ts +196 -158
- package/src/deployer.ts +11 -12
- package/src/index.ts +1 -1
- package/src/server.ts +8 -8
package/dist/server.js
CHANGED
|
@@ -12,22 +12,22 @@ const INJECTED_SCRIPT = `
|
|
|
12
12
|
<!-- Code injected by auto-server -->
|
|
13
13
|
<script>
|
|
14
14
|
(function() {
|
|
15
|
-
console.log('[
|
|
15
|
+
console.log('[one-server-4-all] Connected to hot reload');
|
|
16
16
|
const evtSource = new EventSource('/_hot_server_sse');
|
|
17
17
|
evtSource.onmessage = function(event) {
|
|
18
18
|
try {
|
|
19
19
|
const data = JSON.parse(event.data);
|
|
20
20
|
if (data.type === 'css') {
|
|
21
|
-
console.log('[
|
|
21
|
+
console.log('[one-server-4-all] CSS changed, injecting...');
|
|
22
22
|
injectCSS(data.file);
|
|
23
23
|
} else {
|
|
24
|
-
console.log('[
|
|
24
|
+
console.log('[one-server-4-all] Reloading...');
|
|
25
25
|
window.location.reload();
|
|
26
26
|
}
|
|
27
27
|
} catch (e) {
|
|
28
28
|
// Fallback para compatibilidade
|
|
29
29
|
if (event.data === 'reload') {
|
|
30
|
-
console.log('[
|
|
30
|
+
console.log('[one-server-4-all] Reloading...');
|
|
31
31
|
window.location.reload();
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -44,13 +44,13 @@ const INJECTED_SCRIPT = `
|
|
|
44
44
|
// Força reload do CSS adicionando/removendo timestamp
|
|
45
45
|
const newHref = href.split('?')[0] + '?v=' + timestamp;
|
|
46
46
|
link.setAttribute('href', newHref);
|
|
47
|
-
console.log('[
|
|
47
|
+
console.log('[one-server-4-all] CSS injected:', filePath);
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
evtSource.onerror = function() {
|
|
53
|
-
console.log('[
|
|
53
|
+
console.log('[one-server-4-all] Disconnected. Retrying...');
|
|
54
54
|
};
|
|
55
55
|
})();
|
|
56
56
|
</script>
|
|
@@ -325,7 +325,7 @@ export class HotServer {
|
|
|
325
325
|
const green = (text) => `\x1b[32m${text}\x1b[0m`;
|
|
326
326
|
const bold = (text) => `\x1b[1m${text}\x1b[0m`;
|
|
327
327
|
const gray = (text) => `\x1b[90m${text}\x1b[0m`;
|
|
328
|
-
console.log(`\n ${bold(cyan("
|
|
328
|
+
console.log(`\n ${bold(cyan("one-server-4-all"))} ${cyan("v" + version)} ${gray("ready in")} ${bold(green(readyTime + " ms"))}\n`);
|
|
329
329
|
console.log(` ${green("➜")} ${bold("Local")}: ${cyan(`${protocol}://localhost:${this.config.port}/`)}`);
|
|
330
330
|
const networks = this.getNetworkIPs();
|
|
331
331
|
networks.forEach((ip) => {
|
|
@@ -551,7 +551,7 @@ export class HotServer {
|
|
|
551
551
|
</div>
|
|
552
552
|
|
|
553
553
|
<div class="back">
|
|
554
|
-
Servido por <strong>purecore-
|
|
554
|
+
Servido por <strong>purecore-one-server-4-all</strong>
|
|
555
555
|
</div>
|
|
556
556
|
</div>
|
|
557
557
|
</body>
|
package/hot-server.deps.graflow
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(
|
|
1
|
+
(one-server-4-all)->(0.1.0)
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@purecore/one-server-4-all",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Zero dependency modern hot-reload server replacement",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"one-server": "./dist/index.js",
|
|
9
|
+
"one-server-4-all": "./dist/index.js",
|
|
9
10
|
"vai-server": "./dist/index.js"
|
|
10
11
|
},
|
|
11
12
|
"scripts": {
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
"keywords": [
|
|
22
23
|
"http-server",
|
|
23
24
|
"hot-reload",
|
|
24
|
-
"
|
|
25
|
+
"one-server-4-all",
|
|
25
26
|
"live-server",
|
|
26
27
|
"zero-dependency"
|
|
27
28
|
],
|
|
@@ -9,17 +9,20 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
9
9
|
### 1. 🔒 Suporte Completo a HTTPS
|
|
10
10
|
|
|
11
11
|
**O que foi implementado:**
|
|
12
|
+
|
|
12
13
|
- Modo HTTPS opcional ativado pela flag `--https=true`
|
|
13
14
|
- Geração automática de certificados SSL auto-assinados
|
|
14
15
|
- Servidor HTTP/HTTPS dinâmico baseado na configuração
|
|
15
16
|
- Suporte completo a protocolos HTTP e HTTPS
|
|
16
17
|
|
|
17
18
|
**Arquivos modificados:**
|
|
19
|
+
|
|
18
20
|
- `src/server.ts`: Classe HotServer modificada para suportar HTTPS
|
|
19
21
|
- `src/index.ts`: Parsing da flag `--https`
|
|
20
22
|
- `src/validator.ts`: Validação da configuração HTTPS
|
|
21
23
|
|
|
22
24
|
**Técnicas utilizadas:**
|
|
25
|
+
|
|
23
26
|
- Módulo `https` do Node.js para servidor SSL
|
|
24
27
|
- Detecção automática de certificados existentes
|
|
25
28
|
- Fallback gracioso para modo HTTP quando necessário
|
|
@@ -28,15 +31,18 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
28
31
|
### 2. 🛠️ Sistema de Geração de Certificados
|
|
29
32
|
|
|
30
33
|
**O que foi implementado:**
|
|
34
|
+
|
|
31
35
|
- Classe `CertGenerator` completa para gerenciamento de certificados
|
|
32
36
|
- Geração automática de pares chave privada/certificado
|
|
33
37
|
- Comandos CLI para geração, limpeza e informações
|
|
34
|
-
- Certificados salvos em `.
|
|
38
|
+
- Certificados salvos em `.one-server-4-all-certs/` padrão
|
|
35
39
|
|
|
36
40
|
**Arquivos criados:**
|
|
41
|
+
|
|
37
42
|
- `src/cert-generator.ts`: Sistema completo de geração de certificados
|
|
38
43
|
|
|
39
44
|
**Técnicas utilizadas:**
|
|
45
|
+
|
|
40
46
|
- Crypto API nativa do Node.js para geração RSA
|
|
41
47
|
- File system operations para persistência
|
|
42
48
|
- Command-line interface com subcomandos
|
|
@@ -45,6 +51,7 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
45
51
|
### 3. 🔓🔒 Indicadores Visuais no Terminal
|
|
46
52
|
|
|
47
53
|
**O que foi implementado:**
|
|
54
|
+
|
|
48
55
|
- Emojis de cadeado no log de inicialização:
|
|
49
56
|
- 🔓 para modo HTTP (cadeado aberto)
|
|
50
57
|
- 🔒 para modo HTTPS (cadeado fechado)
|
|
@@ -52,9 +59,11 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
52
59
|
- Visual feedback imediato do modo de segurança
|
|
53
60
|
|
|
54
61
|
**Arquivos modificados:**
|
|
62
|
+
|
|
55
63
|
- `src/server.ts`: Logs de inicialização com indicadores visuais
|
|
56
64
|
|
|
57
65
|
**Técnicas utilizadas:**
|
|
66
|
+
|
|
58
67
|
- Template literals com emojis Unicode
|
|
59
68
|
- Detecção dinâmica de protocolo
|
|
60
69
|
- Console output formatting
|
|
@@ -62,6 +71,7 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
62
71
|
### 4. 📊 Sistema Avançado de Logs
|
|
63
72
|
|
|
64
73
|
**O que foi implementado:**
|
|
74
|
+
|
|
65
75
|
- Logs detalhados para cada arquivo servido
|
|
66
76
|
- Informações de tamanho e tipo MIME
|
|
67
77
|
- Parsing automático de recursos HTML
|
|
@@ -69,9 +79,11 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
69
79
|
- Logs especiais para injeção de hot-reload
|
|
70
80
|
|
|
71
81
|
**Arquivos modificados:**
|
|
82
|
+
|
|
72
83
|
- `src/server.ts`: Sistema completo de logging
|
|
73
84
|
|
|
74
85
|
**Técnicas utilizadas:**
|
|
86
|
+
|
|
75
87
|
- Regex parsing para recursos HTML
|
|
76
88
|
- File system stats para informações de tamanho
|
|
77
89
|
- Formatação human-readable de bytes
|
|
@@ -80,6 +92,7 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
80
92
|
## 🔧 Funcionalidades Técnicas
|
|
81
93
|
|
|
82
94
|
### Scripts NPM Adicionados
|
|
95
|
+
|
|
83
96
|
```json
|
|
84
97
|
{
|
|
85
98
|
"dev:https": "ts-node src/index.ts --https=true",
|
|
@@ -90,18 +103,20 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
90
103
|
```
|
|
91
104
|
|
|
92
105
|
### Estrutura de Certificados
|
|
106
|
+
|
|
93
107
|
```
|
|
94
|
-
.
|
|
108
|
+
.one-server-4-all-certs/
|
|
95
109
|
├── localhost.key # Chave privada RSA
|
|
96
110
|
└── localhost.crt # Certificado auto-assinado
|
|
97
111
|
```
|
|
98
112
|
|
|
99
113
|
### Exemplo de Logs de Saída
|
|
114
|
+
|
|
100
115
|
```
|
|
101
116
|
🔐 Gerando certificados auto-assinados...
|
|
102
117
|
✅ Certificados gerados com sucesso!
|
|
103
118
|
|
|
104
|
-
🚀
|
|
119
|
+
🚀 one-server-4-all rodando!
|
|
105
120
|
-----------------------------------
|
|
106
121
|
📂 Root: /path/to/project
|
|
107
122
|
🔒 Local: https://localhost:9999
|
|
@@ -118,6 +133,7 @@ Foram implementadas com sucesso as funcionalidades de HTTPS, geração automáti
|
|
|
118
133
|
## 🧪 Como Testar
|
|
119
134
|
|
|
120
135
|
### Modo HTTPS
|
|
136
|
+
|
|
121
137
|
```bash
|
|
122
138
|
# Ativar HTTPS
|
|
123
139
|
npm run dev:https
|
|
@@ -127,6 +143,7 @@ ts-node src/index.ts --https=true
|
|
|
127
143
|
```
|
|
128
144
|
|
|
129
145
|
### Gerenciamento de Certificados
|
|
146
|
+
|
|
130
147
|
```bash
|
|
131
148
|
# Gerar certificados
|
|
132
149
|
npm run certs:generate
|
|
@@ -139,6 +156,7 @@ npm run certs:clean
|
|
|
139
156
|
```
|
|
140
157
|
|
|
141
158
|
### Logs Detalhados
|
|
159
|
+
|
|
142
160
|
1. Inicie o servidor
|
|
143
161
|
2. Abra uma página HTML no navegador
|
|
144
162
|
3. Observe no terminal:
|
|
@@ -149,16 +167,19 @@ npm run certs:clean
|
|
|
149
167
|
## 📈 Benefícios Alcançados
|
|
150
168
|
|
|
151
169
|
### Segurança
|
|
170
|
+
|
|
152
171
|
- ✅ Desenvolvimento local com HTTPS
|
|
153
172
|
- ✅ Certificados auto-gerados automaticamente
|
|
154
173
|
- ✅ Feedback visual de segurança
|
|
155
174
|
|
|
156
175
|
### Desenvolvimento
|
|
176
|
+
|
|
157
177
|
- ✅ Logs detalhados para debugging
|
|
158
178
|
- ✅ Visibilidade de recursos HTML
|
|
159
179
|
- ✅ Protocol-aware operations
|
|
160
180
|
|
|
161
181
|
### Experiência do Desenvolvedor
|
|
182
|
+
|
|
162
183
|
- ✅ Indicadores visuais claros
|
|
163
184
|
- ✅ Automação de tarefas repetitivas
|
|
164
185
|
- ✅ CLI intuitiva e completa
|
|
@@ -181,4 +202,4 @@ O Purecore Hot Server agora oferece:
|
|
|
181
202
|
- [OpenSSL Certificate Generation](https://www.openssl.org/docs/man1.1.1/man1/req.html)
|
|
182
203
|
- [MDN Web Docs - SSL/TLS](https://developer.mozilla.org/en-US/docs/Glossary/SSL)
|
|
183
204
|
- [RFC 5280 - Certificate Standards](https://tools.ietf.org/html/rfc5280)
|
|
184
|
-
- [Unicode Emoji Reference](https://unicode.org/emoji/charts/full-emoji-list.html)
|
|
205
|
+
- [Unicode Emoji Reference](https://unicode.org/emoji/charts/full-emoji-list.html)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Relatório de Modificação - Log Estilo Vite
|
|
2
2
|
|
|
3
3
|
**Data:** 31-12-2025
|
|
4
|
-
**Tarefa:** Customizar o log de inicialização do `
|
|
4
|
+
**Tarefa:** Customizar o log de inicialização do `one-server-4-all` para ser idêntico ao do Vite.
|
|
5
5
|
|
|
6
6
|
## O que foi feito
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
- Implementada a detecção de interfaces de rede usando o módulo nativo `node:os`.
|
|
10
10
|
- Adicionada medição de tempo de inicialização (`startTime`) para exibir "ready in X ms".
|
|
11
11
|
- Estilização completa usando códigos de escape ANSI para cores e negrito, imitando perfeitamente o visual premium do Vite.
|
|
12
|
-
- Substituído o nome "VITE" por "
|
|
12
|
+
- Substituído o nome "VITE" por "one-server-4-all".
|
|
13
13
|
- Adicionado o link de ajuda "press h + enter to show help".
|
|
14
14
|
- Atualizado o feedback de porta em uso para também seguir o padrão visual.
|
|
15
15
|
- Corrigido o `.gitignore` para incluir a pasta `dist`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Relatório de Modificação - Implementação do Deployer Interativo
|
|
2
2
|
|
|
3
3
|
**Data:** 31-12-2025
|
|
4
|
-
**Tarefa:** Substituir o script `cria.sh` por um comando `deploy` interativo integrado ao CLI do `
|
|
4
|
+
**Tarefa:** Substituir o script `cria.sh` por um comando `deploy` interativo integrado ao CLI do `one-server-4-all`.
|
|
5
5
|
|
|
6
6
|
## O que foi feito
|
|
7
7
|
|
package/src/cert-generator.ts
CHANGED
|
@@ -1,173 +1,211 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import crypto from
|
|
3
|
-
import fs from
|
|
4
|
-
import path from
|
|
5
|
-
import { execFileSync } from
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { execFileSync } from "node:child_process";
|
|
6
6
|
|
|
7
7
|
export class CertGenerator {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
8
|
+
private static readonly CERT_DIR = ".one-server-4-all-certs";
|
|
9
|
+
private static readonly KEY_FILE = "localhost.key";
|
|
10
|
+
private static readonly CERT_FILE = "localhost.crt";
|
|
11
|
+
|
|
12
|
+
static async generateCerts() {
|
|
13
|
+
const certDir = path.join(process.cwd(), this.CERT_DIR);
|
|
14
|
+
const keyPath = path.join(certDir, this.KEY_FILE);
|
|
15
|
+
const certPath = path.join(certDir, this.CERT_FILE);
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
// Verificar se certificados já existem
|
|
19
|
+
try {
|
|
20
|
+
await fs.access(keyPath);
|
|
21
|
+
await fs.access(certPath);
|
|
22
|
+
console.log("📋 Certificados já existem em:", certDir);
|
|
23
|
+
return { keyPath, certPath };
|
|
24
|
+
} catch {
|
|
25
|
+
// Certificados não existem, vamos criar
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Criar diretório se não existir
|
|
29
|
+
await fs.mkdir(certDir, { recursive: true });
|
|
30
|
+
|
|
31
|
+
console.log("🔐 Gerando certificados auto-assinados...");
|
|
32
|
+
|
|
33
|
+
// Observação importante:
|
|
34
|
+
// Gerar um X509 "de verdade" apenas com node:crypto (sem libs externas) não é trivial.
|
|
35
|
+
// Como este projeto roda no WSL, utilizamos o OpenSSL (toolchain padrão do Linux)
|
|
36
|
+
// para gerar um par key/cert PEM válido e compatível com Bun/BoringSSL.
|
|
37
|
+
await this.generateWithOpenSSL({ keyPath, certPath });
|
|
38
|
+
|
|
39
|
+
// Validação do PEM (evita subir servidor com arquivo corrompido)
|
|
40
|
+
const [keyPem, certPem] = await Promise.all([
|
|
41
|
+
fs.readFile(keyPath, "utf8"),
|
|
42
|
+
fs.readFile(certPath, "utf8"),
|
|
43
|
+
]);
|
|
44
|
+
this.validatePem({ keyPem, certPem, keyPath, certPath });
|
|
45
|
+
this.validateX509(certPem, certPath);
|
|
46
|
+
this.validateWithOpenSSL(certPath);
|
|
47
|
+
|
|
48
|
+
console.log("✅ Certificados gerados com sucesso!");
|
|
49
|
+
console.log("📁 Localização:", certDir);
|
|
50
|
+
console.log("🔑 Chave privada:", keyPath);
|
|
51
|
+
console.log("📄 Certificado:", certPath);
|
|
52
|
+
console.log("");
|
|
53
|
+
console.log(
|
|
54
|
+
"⚠️ AVISO: Estes são certificados auto-assinados para desenvolvimento local."
|
|
55
|
+
);
|
|
56
|
+
console.log(" Não use em produção!");
|
|
57
|
+
|
|
58
|
+
return { keyPath, certPath };
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("❌ Erro ao gerar certificados:", error);
|
|
61
|
+
throw error;
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private static generateWithOpenSSL(params: {
|
|
66
|
+
keyPath: string;
|
|
67
|
+
certPath: string;
|
|
68
|
+
}) {
|
|
69
|
+
const { keyPath, certPath } = params;
|
|
70
|
+
const subj = "/C=BR/ST=SP/L=Sao Paulo/O=Purecore/OU=Dev/CN=localhost";
|
|
71
|
+
|
|
72
|
+
// Preferimos SAN para evitar problemas em clients modernos.
|
|
73
|
+
// Nem todo OpenSSL antigo suporta -addext, então fazemos fallback.
|
|
74
|
+
const baseArgs = [
|
|
75
|
+
"req",
|
|
76
|
+
"-x509",
|
|
77
|
+
"-newkey",
|
|
78
|
+
"rsa:2048",
|
|
79
|
+
"-keyout",
|
|
80
|
+
keyPath,
|
|
81
|
+
"-out",
|
|
82
|
+
certPath,
|
|
83
|
+
"-days",
|
|
84
|
+
"365",
|
|
85
|
+
"-nodes",
|
|
86
|
+
"-subj",
|
|
87
|
+
subj,
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
execFileSync(
|
|
92
|
+
"openssl",
|
|
93
|
+
[...baseArgs, "-addext", "subjectAltName=DNS:localhost,IP:127.0.0.1"],
|
|
94
|
+
{ stdio: "inherit" }
|
|
95
|
+
);
|
|
96
|
+
} catch {
|
|
97
|
+
execFileSync("openssl", baseArgs, { stdio: "inherit" });
|
|
77
98
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private static validatePem(params: {
|
|
102
|
+
keyPem: string;
|
|
103
|
+
certPem: string;
|
|
104
|
+
keyPath: string;
|
|
105
|
+
certPath: string;
|
|
106
|
+
}) {
|
|
107
|
+
const { keyPem, certPem, keyPath, certPath } = params;
|
|
108
|
+
const keyOk =
|
|
109
|
+
keyPem.includes("-----BEGIN PRIVATE KEY-----") ||
|
|
110
|
+
keyPem.includes("-----BEGIN RSA PRIVATE KEY-----");
|
|
111
|
+
const certOk = certPem.includes("-----BEGIN CERTIFICATE-----");
|
|
112
|
+
|
|
113
|
+
if (!keyOk || !certOk) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`PEM inválido gerado. ` +
|
|
116
|
+
`keyOk=${keyOk} certOk=${certOk}. ` +
|
|
117
|
+
`keyPath=${keyPath} certPath=${certPath}`
|
|
118
|
+
);
|
|
93
119
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private static validateX509(certPem: string, certPath: string) {
|
|
123
|
+
try {
|
|
124
|
+
// Node valida a estrutura do X509 e falha se base64/DER estiverem inválidos.
|
|
125
|
+
// Isso é um bom "gate" antes de subir o https.createServer().
|
|
126
|
+
// @ts-ignore - Bun/Node expõem X509Certificate em node:crypto
|
|
127
|
+
const x509 = new crypto.X509Certificate(certPem);
|
|
128
|
+
if (!x509.subject) {
|
|
129
|
+
throw new Error("X509 sem subject");
|
|
130
|
+
}
|
|
131
|
+
} catch (error: any) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`Certificado X509 inválido em ${certPath}: ${
|
|
134
|
+
error?.message || String(error)
|
|
135
|
+
}`
|
|
136
|
+
);
|
|
107
137
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private static validateWithOpenSSL(certPath: string) {
|
|
141
|
+
try {
|
|
142
|
+
// OpenSSL é a validação "ground truth" no WSL.
|
|
143
|
+
execFileSync("openssl", ["x509", "-in", certPath, "-noout"], {
|
|
144
|
+
stdio: "ignore",
|
|
145
|
+
});
|
|
146
|
+
} catch (error: any) {
|
|
147
|
+
throw new Error(`OpenSSL não conseguiu ler o certificado (${certPath}).`);
|
|
116
148
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static async getCertPaths(): Promise<{
|
|
152
|
+
keyPath: string;
|
|
153
|
+
certPath: string;
|
|
154
|
+
} | null> {
|
|
155
|
+
const certDir = path.join(process.cwd(), this.CERT_DIR);
|
|
156
|
+
const keyPath = path.join(certDir, this.KEY_FILE);
|
|
157
|
+
const certPath = path.join(certDir, this.CERT_FILE);
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
await fs.access(keyPath);
|
|
161
|
+
await fs.access(certPath);
|
|
162
|
+
return { keyPath, certPath };
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
130
165
|
}
|
|
166
|
+
}
|
|
131
167
|
|
|
132
|
-
|
|
133
|
-
|
|
168
|
+
static async cleanCerts() {
|
|
169
|
+
const certDir = path.join(process.cwd(), this.CERT_DIR);
|
|
134
170
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
171
|
+
try {
|
|
172
|
+
await fs.rm(certDir, { recursive: true, force: true });
|
|
173
|
+
console.log("🗑️ Certificados removidos:", certDir);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.error("❌ Erro ao remover certificados:", error);
|
|
141
176
|
}
|
|
177
|
+
}
|
|
142
178
|
}
|
|
143
179
|
|
|
144
180
|
// Executar se chamado diretamente
|
|
145
|
-
if (typeof require !==
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
181
|
+
if (typeof require !== "undefined" && require.main === module) {
|
|
182
|
+
const command = process.argv[2];
|
|
183
|
+
|
|
184
|
+
switch (command) {
|
|
185
|
+
case "generate":
|
|
186
|
+
case undefined:
|
|
187
|
+
CertGenerator.generateCerts().catch(console.error);
|
|
188
|
+
break;
|
|
189
|
+
case "clean":
|
|
190
|
+
CertGenerator.cleanCerts().catch(console.error);
|
|
191
|
+
break;
|
|
192
|
+
case "info":
|
|
193
|
+
CertGenerator.getCertPaths()
|
|
194
|
+
.then((paths) => {
|
|
195
|
+
if (paths) {
|
|
196
|
+
console.log("📋 Certificados encontrados:");
|
|
197
|
+
console.log("🔑 Chave:", paths.keyPath);
|
|
198
|
+
console.log("📄 Certificado:", paths.certPath);
|
|
199
|
+
} else {
|
|
200
|
+
console.log("❌ Nenhum certificado encontrado");
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
.catch(console.error);
|
|
204
|
+
break;
|
|
205
|
+
default:
|
|
206
|
+
console.log("Uso: cert-generator [generate|clean|info]");
|
|
207
|
+
console.log(" generate: Gera certificados auto-assinados (padrão)");
|
|
208
|
+
console.log(" clean: Remove certificados existentes");
|
|
209
|
+
console.log(" info: Mostra informações dos certificados");
|
|
210
|
+
}
|
|
211
|
+
}
|