@hostwebhook/platform-node 0.1.0 → 0.2.0
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/dist/busqueda-literal.d.ts +52 -0
- package/dist/busqueda-literal.js +61 -0
- package/dist/escapar-regex.d.ts +28 -0
- package/dist/escapar-regex.js +33 -0
- package/dist/escape-html.d.ts +15 -0
- package/dist/escape-html.js +25 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +19 -0
- package/dist/mongo-databases.d.ts +26 -0
- package/dist/mongo-databases.js +45 -0
- package/dist/postgres-databases.d.ts +30 -0
- package/dist/postgres-databases.js +38 -0
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lo que se teclea en un buscador es TEXTO, no una expresión regular.
|
|
3
|
+
*
|
|
4
|
+
* ## El fallo que cierra
|
|
5
|
+
*
|
|
6
|
+
* `GET /api/credentials?search=` y `GET /api/signing-secrets?search=` metían la
|
|
7
|
+
* cadena de la query directamente en un `$regex` de MongoDB. O sea que quien
|
|
8
|
+
* llamaba elegía la expresión regular que ejecuta el motor de la base.
|
|
9
|
+
*
|
|
10
|
+
* Y el motor de Mongo resuelve por retroceso, igual que el de JavaScript:
|
|
11
|
+
*
|
|
12
|
+
* 1. se crea una credencial con `name` = 100 000 letras 'a'
|
|
13
|
+
* (ni el DTO ni el esquema ponían tope a la longitud);
|
|
14
|
+
* 2. `GET /api/credentials?search=(a%2B)%2Bb`
|
|
15
|
+
*
|
|
16
|
+
* y `(a+)+b` contra esa cadena es exponencial. Una petición barata deja un
|
|
17
|
+
* worker de mongod girando, y la base es la MISMA para todos los inquilinos del
|
|
18
|
+
* clúster. Repitiendo hasta el tope de peticiones —que además se esquiva
|
|
19
|
+
* variando `X-Forwarded-For`, cosa que el propio `client-ip.ts` avisa de que es
|
|
20
|
+
* falsificable— la CPU no baja.
|
|
21
|
+
*
|
|
22
|
+
* Lo más llamativo es que el escape correcto ya estaba escrito noventa líneas
|
|
23
|
+
* más abajo en el mismo fichero, para el buscador de etiquetas. Estaba resuelto
|
|
24
|
+
* y copiado a medias.
|
|
25
|
+
*
|
|
26
|
+
* ## Lo que hace
|
|
27
|
+
*
|
|
28
|
+
* Escapa los metacaracteres —para que el patrón case LITERALMENTE lo que se
|
|
29
|
+
* escribió— y acota la longitud. Lo segundo importa aparte: el coste de una
|
|
30
|
+
* búsqueda crece con el patrón además de con el texto, y un buscador no
|
|
31
|
+
* necesita mil caracteres.
|
|
32
|
+
*
|
|
33
|
+
* ⚠️ El escape en sí NO vive aquí: es `escaparRegex`, en el módulo de al
|
|
34
|
+
* lado. Esta función es «escapar Y acotar»; hay un puñado de sitios que
|
|
35
|
+
* incrustan un valor interno en un patrón y no pueden recortarlo sin cambiar
|
|
36
|
+
* lo que significa, y ésos usan el primitivo pelado. Una sola expresión de
|
|
37
|
+
* escape en todo el repositorio, y dos maneras de pedirla.
|
|
38
|
+
*
|
|
39
|
+
* No se usa `$text`: exigiría un índice de texto por colección y cambiaría la
|
|
40
|
+
* semántica de «contiene» a «palabras completas», que no es lo que el panel
|
|
41
|
+
* ofrece hoy.
|
|
42
|
+
*/
|
|
43
|
+
/** Un buscador no necesita más. Por encima, se recorta. */
|
|
44
|
+
export declare const MAX_BUSQUEDA = 200;
|
|
45
|
+
/**
|
|
46
|
+
* Devuelve la cadena lista para meter en un `$regex`, casando literalmente.
|
|
47
|
+
*
|
|
48
|
+
* Se exporta también `MAX_BUSQUEDA` para que quien quiera pueda rechazar en vez
|
|
49
|
+
* de recortar; aquí se recorta porque un buscador que devuelve un error por
|
|
50
|
+
* escribir de más es peor que uno que busca por los primeros 200 caracteres.
|
|
51
|
+
*/
|
|
52
|
+
export declare function busquedaLiteral(bruto: unknown): string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Lo que se teclea en un buscador es TEXTO, no una expresión regular.
|
|
4
|
+
*
|
|
5
|
+
* ## El fallo que cierra
|
|
6
|
+
*
|
|
7
|
+
* `GET /api/credentials?search=` y `GET /api/signing-secrets?search=` metían la
|
|
8
|
+
* cadena de la query directamente en un `$regex` de MongoDB. O sea que quien
|
|
9
|
+
* llamaba elegía la expresión regular que ejecuta el motor de la base.
|
|
10
|
+
*
|
|
11
|
+
* Y el motor de Mongo resuelve por retroceso, igual que el de JavaScript:
|
|
12
|
+
*
|
|
13
|
+
* 1. se crea una credencial con `name` = 100 000 letras 'a'
|
|
14
|
+
* (ni el DTO ni el esquema ponían tope a la longitud);
|
|
15
|
+
* 2. `GET /api/credentials?search=(a%2B)%2Bb`
|
|
16
|
+
*
|
|
17
|
+
* y `(a+)+b` contra esa cadena es exponencial. Una petición barata deja un
|
|
18
|
+
* worker de mongod girando, y la base es la MISMA para todos los inquilinos del
|
|
19
|
+
* clúster. Repitiendo hasta el tope de peticiones —que además se esquiva
|
|
20
|
+
* variando `X-Forwarded-For`, cosa que el propio `client-ip.ts` avisa de que es
|
|
21
|
+
* falsificable— la CPU no baja.
|
|
22
|
+
*
|
|
23
|
+
* Lo más llamativo es que el escape correcto ya estaba escrito noventa líneas
|
|
24
|
+
* más abajo en el mismo fichero, para el buscador de etiquetas. Estaba resuelto
|
|
25
|
+
* y copiado a medias.
|
|
26
|
+
*
|
|
27
|
+
* ## Lo que hace
|
|
28
|
+
*
|
|
29
|
+
* Escapa los metacaracteres —para que el patrón case LITERALMENTE lo que se
|
|
30
|
+
* escribió— y acota la longitud. Lo segundo importa aparte: el coste de una
|
|
31
|
+
* búsqueda crece con el patrón además de con el texto, y un buscador no
|
|
32
|
+
* necesita mil caracteres.
|
|
33
|
+
*
|
|
34
|
+
* ⚠️ El escape en sí NO vive aquí: es `escaparRegex`, en el módulo de al
|
|
35
|
+
* lado. Esta función es «escapar Y acotar»; hay un puñado de sitios que
|
|
36
|
+
* incrustan un valor interno en un patrón y no pueden recortarlo sin cambiar
|
|
37
|
+
* lo que significa, y ésos usan el primitivo pelado. Una sola expresión de
|
|
38
|
+
* escape en todo el repositorio, y dos maneras de pedirla.
|
|
39
|
+
*
|
|
40
|
+
* No se usa `$text`: exigiría un índice de texto por colección y cambiaría la
|
|
41
|
+
* semántica de «contiene» a «palabras completas», que no es lo que el panel
|
|
42
|
+
* ofrece hoy.
|
|
43
|
+
*/
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.MAX_BUSQUEDA = void 0;
|
|
46
|
+
exports.busquedaLiteral = busquedaLiteral;
|
|
47
|
+
const escapar_regex_1 = require("./escapar-regex");
|
|
48
|
+
/** Un buscador no necesita más. Por encima, se recorta. */
|
|
49
|
+
exports.MAX_BUSQUEDA = 200;
|
|
50
|
+
/**
|
|
51
|
+
* Devuelve la cadena lista para meter en un `$regex`, casando literalmente.
|
|
52
|
+
*
|
|
53
|
+
* Se exporta también `MAX_BUSQUEDA` para que quien quiera pueda rechazar en vez
|
|
54
|
+
* de recortar; aquí se recorta porque un buscador que devuelve un error por
|
|
55
|
+
* escribir de más es peor que uno que busca por los primeros 200 caracteres.
|
|
56
|
+
*/
|
|
57
|
+
function busquedaLiteral(bruto) {
|
|
58
|
+
if (typeof bruto !== 'string' || bruto.length === 0)
|
|
59
|
+
return '';
|
|
60
|
+
return (0, escapar_regex_1.escaparRegex)(bruto.slice(0, exports.MAX_BUSQUEDA));
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lo que escribe el usuario es TEXTO, no un patrón.
|
|
3
|
+
*
|
|
4
|
+
* Sin escapar pasan dos cosas, y ninguna es «no encuentra nada»: un
|
|
5
|
+
* paréntesis suelto hace que Mongo rechace la consulta entera con un error
|
|
6
|
+
* de sintaxis, y un patrón anidado del tipo «grupo repetido dentro de grupo
|
|
7
|
+
* repetido» se convierte en un ReDoS — el regex lo evalúa el servidor de
|
|
8
|
+
* base de datos, así que quien se queda colgado es él, no el proceso que
|
|
9
|
+
* recibió la petición.
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ **Ésta es la única expresión regular de escape del repositorio.** No
|
|
12
|
+
* escribas otra: `busquedaLiteral` la usa, y todo lo demás usa una de las
|
|
13
|
+
* dos. Cuál de las dos:
|
|
14
|
+
*
|
|
15
|
+
* - `busquedaLiteral` — texto que teclea alguien en un buscador. Escapa
|
|
16
|
+
* **y acota** la longitud, porque el coste de la búsqueda crece con el
|
|
17
|
+
* patrón además de con el texto. Es la que quieres casi siempre.
|
|
18
|
+
* - `escaparRegex` (ésta) — un valor interno que se incrusta en un patrón
|
|
19
|
+
* y que NO puede recortarse sin cambiar lo que significa.
|
|
20
|
+
*
|
|
21
|
+
* El 2026-08-27 este módulo decía que quedaban «tres copias literales» por
|
|
22
|
+
* migrar. Eran DOCE: se habían contado buscando los nombres `escapeRegex` y
|
|
23
|
+
* `escaparRegex`, y la mitad estaban escritas a pelo dentro de la consulta,
|
|
24
|
+
* sin función que buscar. Contar por el nombre no es inventariar — hay que
|
|
25
|
+
* contar por la clase de caracteres. `una-sola-copia-del-escape.spec.ts` lo
|
|
26
|
+
* cuenta ahora por ti y no deja aparecer la trece.
|
|
27
|
+
*/
|
|
28
|
+
export declare function escaparRegex(s: string): string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.escaparRegex = escaparRegex;
|
|
4
|
+
/**
|
|
5
|
+
* Lo que escribe el usuario es TEXTO, no un patrón.
|
|
6
|
+
*
|
|
7
|
+
* Sin escapar pasan dos cosas, y ninguna es «no encuentra nada»: un
|
|
8
|
+
* paréntesis suelto hace que Mongo rechace la consulta entera con un error
|
|
9
|
+
* de sintaxis, y un patrón anidado del tipo «grupo repetido dentro de grupo
|
|
10
|
+
* repetido» se convierte en un ReDoS — el regex lo evalúa el servidor de
|
|
11
|
+
* base de datos, así que quien se queda colgado es él, no el proceso que
|
|
12
|
+
* recibió la petición.
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ **Ésta es la única expresión regular de escape del repositorio.** No
|
|
15
|
+
* escribas otra: `busquedaLiteral` la usa, y todo lo demás usa una de las
|
|
16
|
+
* dos. Cuál de las dos:
|
|
17
|
+
*
|
|
18
|
+
* - `busquedaLiteral` — texto que teclea alguien en un buscador. Escapa
|
|
19
|
+
* **y acota** la longitud, porque el coste de la búsqueda crece con el
|
|
20
|
+
* patrón además de con el texto. Es la que quieres casi siempre.
|
|
21
|
+
* - `escaparRegex` (ésta) — un valor interno que se incrusta en un patrón
|
|
22
|
+
* y que NO puede recortarse sin cambiar lo que significa.
|
|
23
|
+
*
|
|
24
|
+
* El 2026-08-27 este módulo decía que quedaban «tres copias literales» por
|
|
25
|
+
* migrar. Eran DOCE: se habían contado buscando los nombres `escapeRegex` y
|
|
26
|
+
* `escaparRegex`, y la mitad estaban escritas a pelo dentro de la consulta,
|
|
27
|
+
* sin función que buscar. Contar por el nombre no es inventariar — hay que
|
|
28
|
+
* contar por la clase de caracteres. `una-sola-copia-del-escape.spec.ts` lo
|
|
29
|
+
* cuenta ahora por ti y no deja aparecer la trece.
|
|
30
|
+
*/
|
|
31
|
+
function escaparRegex(s) {
|
|
32
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escapar HTML, una sola vez y en un solo sitio.
|
|
3
|
+
*
|
|
4
|
+
* Había TRES copias de esta función en el repo —en `credentials.controller`,
|
|
5
|
+
* en `approval-nodes.controller` y en `send-and-wait.controller`— idénticas
|
|
6
|
+
* carácter por carácter. Que hoy coincidan no es garantía de nada: son tres
|
|
7
|
+
* sitios donde alguien puede añadir un caso, olvidarse de los otros dos, y
|
|
8
|
+
* dejar dos escapes peores que el tercero sin que nada lo señale.
|
|
9
|
+
*
|
|
10
|
+
* Y estaba a punto de haber una cuarta, para el email de invitación.
|
|
11
|
+
*
|
|
12
|
+
* Los cinco caracteres son los de siempre, y el orden importa: `&` va primero
|
|
13
|
+
* o acabaría escapando los `&` que introducen los demás reemplazos.
|
|
14
|
+
*/
|
|
15
|
+
export declare function escapeHtml(valor: unknown): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.escapeHtml = escapeHtml;
|
|
4
|
+
/**
|
|
5
|
+
* Escapar HTML, una sola vez y en un solo sitio.
|
|
6
|
+
*
|
|
7
|
+
* Había TRES copias de esta función en el repo —en `credentials.controller`,
|
|
8
|
+
* en `approval-nodes.controller` y en `send-and-wait.controller`— idénticas
|
|
9
|
+
* carácter por carácter. Que hoy coincidan no es garantía de nada: son tres
|
|
10
|
+
* sitios donde alguien puede añadir un caso, olvidarse de los otros dos, y
|
|
11
|
+
* dejar dos escapes peores que el tercero sin que nada lo señale.
|
|
12
|
+
*
|
|
13
|
+
* Y estaba a punto de haber una cuarta, para el email de invitación.
|
|
14
|
+
*
|
|
15
|
+
* Los cinco caracteres son los de siempre, y el orden importa: `&` va primero
|
|
16
|
+
* o acabaría escapando los `&` que introducen los demás reemplazos.
|
|
17
|
+
*/
|
|
18
|
+
function escapeHtml(valor) {
|
|
19
|
+
return String(valor)
|
|
20
|
+
.replace(/&/g, '&')
|
|
21
|
+
.replace(/</g, '<')
|
|
22
|
+
.replace(/>/g, '>')
|
|
23
|
+
.replace(/"/g, '"')
|
|
24
|
+
.replace(/'/g, ''');
|
|
25
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
17
|
exports.decrypt = exports.encrypt = void 0;
|
|
4
18
|
var crypto_1 = require("./crypto");
|
|
5
19
|
Object.defineProperty(exports, "encrypt", { enumerable: true, get: function () { return crypto_1.encrypt; } });
|
|
6
20
|
Object.defineProperty(exports, "decrypt", { enumerable: true, get: function () { return crypto_1.decrypt; } });
|
|
21
|
+
__exportStar(require("./escape-html"), exports);
|
|
22
|
+
__exportStar(require("./mongo-databases"), exports);
|
|
23
|
+
__exportStar(require("./postgres-databases"), exports);
|
|
24
|
+
__exportStar(require("./busqueda-literal"), exports);
|
|
25
|
+
__exportStar(require("./escapar-regex"), exports);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Las bases que MongoDB trae siempre y que nadie elige como destino.
|
|
3
|
+
*
|
|
4
|
+
* Vive en `common` y no junto al nodo porque la usan los dos lados y en
|
|
5
|
+
* direcciones opuestas: el nodo de Mongo al listar las bases del servidor, y
|
|
6
|
+
* `CredentialsService` al comprobar que la base tecleada en el formulario
|
|
7
|
+
* existe. Importarla desde `nodes/` en `credentials/` invertiría la
|
|
8
|
+
* dependencia (los nodos importan credenciales, no al revés).
|
|
9
|
+
*/
|
|
10
|
+
export declare const BASES_INTERNAS: ReadonlySet<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Por qué rechazar la base que declara una credencial de Mongo, o `null` si
|
|
13
|
+
* no hay motivo.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ La distinción que lo es todo: `disponibles === undefined` significa **no
|
|
16
|
+
* se pudo mirar** (credencial acotada a una base, servidor caído), y eso
|
|
17
|
+
* **nunca** bloquea. Una lista vacía sí es una respuesta. Tratar los dos
|
|
18
|
+
* casos igual impediría guardar credenciales perfectamente buenas.
|
|
19
|
+
*
|
|
20
|
+
* Existe porque `client.db("no_existe")` no falla en Mongo —las bases se
|
|
21
|
+
* crean al escribir— así que un nombre mal tecleado se guarda tan campante y
|
|
22
|
+
* después toda lectura devuelve cero, sin error. Medido el 2026-08-12: una
|
|
23
|
+
* credencial decía `my_hostwebhook_testing_database` y el servidor sólo tenía
|
|
24
|
+
* `test`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function motivoDeBaseInvalida(pedida: string | null | undefined, disponibles: string[] | undefined): string | null;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BASES_INTERNAS = void 0;
|
|
4
|
+
exports.motivoDeBaseInvalida = motivoDeBaseInvalida;
|
|
5
|
+
/**
|
|
6
|
+
* Las bases que MongoDB trae siempre y que nadie elige como destino.
|
|
7
|
+
*
|
|
8
|
+
* Vive en `common` y no junto al nodo porque la usan los dos lados y en
|
|
9
|
+
* direcciones opuestas: el nodo de Mongo al listar las bases del servidor, y
|
|
10
|
+
* `CredentialsService` al comprobar que la base tecleada en el formulario
|
|
11
|
+
* existe. Importarla desde `nodes/` en `credentials/` invertiría la
|
|
12
|
+
* dependencia (los nodos importan credenciales, no al revés).
|
|
13
|
+
*/
|
|
14
|
+
exports.BASES_INTERNAS = new Set([
|
|
15
|
+
'admin',
|
|
16
|
+
'local',
|
|
17
|
+
'config',
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Por qué rechazar la base que declara una credencial de Mongo, o `null` si
|
|
21
|
+
* no hay motivo.
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ La distinción que lo es todo: `disponibles === undefined` significa **no
|
|
24
|
+
* se pudo mirar** (credencial acotada a una base, servidor caído), y eso
|
|
25
|
+
* **nunca** bloquea. Una lista vacía sí es una respuesta. Tratar los dos
|
|
26
|
+
* casos igual impediría guardar credenciales perfectamente buenas.
|
|
27
|
+
*
|
|
28
|
+
* Existe porque `client.db("no_existe")` no falla en Mongo —las bases se
|
|
29
|
+
* crean al escribir— así que un nombre mal tecleado se guarda tan campante y
|
|
30
|
+
* después toda lectura devuelve cero, sin error. Medido el 2026-08-12: una
|
|
31
|
+
* credencial decía `my_hostwebhook_testing_database` y el servidor sólo tenía
|
|
32
|
+
* `test`.
|
|
33
|
+
*/
|
|
34
|
+
function motivoDeBaseInvalida(pedida, disponibles) {
|
|
35
|
+
const nombre = (pedida ?? '').trim();
|
|
36
|
+
if (!nombre)
|
|
37
|
+
return null;
|
|
38
|
+
if (!disponibles)
|
|
39
|
+
return null;
|
|
40
|
+
if (disponibles.includes(nombre))
|
|
41
|
+
return null;
|
|
42
|
+
return disponibles.length > 0
|
|
43
|
+
? `Database "${nombre}" doesn't exist on this server. Available: ${disponibles.join(', ')}`
|
|
44
|
+
: `Database "${nombre}" doesn't exist on this server, and the server has no databases yet`;
|
|
45
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qué bases ofrece el selector del formulario de una credencial de Postgres.
|
|
3
|
+
*
|
|
4
|
+
* Aparte del servicio, como `mongo-databases.ts`, para que la consulta y el
|
|
5
|
+
* filtrado se puedan probar sin levantar un Postgres.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Las bases a las que un cliente se puede conectar de verdad.
|
|
9
|
+
*
|
|
10
|
+
* Los dos filtros están por un motivo concreto, y quitarlos no rompe nada
|
|
11
|
+
* hasta que alguien elige la opción equivocada:
|
|
12
|
+
*
|
|
13
|
+
* - `datistemplate = false` deja fuera `template0` y `template1`, que son
|
|
14
|
+
* plantillas y no destinos.
|
|
15
|
+
* - `datallowconn = true` es el que de verdad importa: **`template0` rechaza
|
|
16
|
+
* conexiones por diseño**. Ofrecerla es ofrecer una opción que sólo puede
|
|
17
|
+
* fallar, y el error (`FATAL: database "template0" is not currently
|
|
18
|
+
* accepting connections`) no se parece en nada a «esa no la elijas».
|
|
19
|
+
*/
|
|
20
|
+
export declare const SQL_BASES_DE_POSTGRES = "SELECT datname FROM pg_database\n WHERE datistemplate = false AND datallowconn = true\n ORDER BY datname";
|
|
21
|
+
/**
|
|
22
|
+
* Los nombres, de lo que devuelva el driver.
|
|
23
|
+
*
|
|
24
|
+
* Se valida el tipo en vez de castear: `pg` tipa las filas por lo que le
|
|
25
|
+
* digas, no por lo que llegue, así que una fila rara entraría como `undefined`
|
|
26
|
+
* y pintaría una opción vacía en el desplegable.
|
|
27
|
+
*/
|
|
28
|
+
export declare function nombresDeBases(filas: ReadonlyArray<{
|
|
29
|
+
datname?: unknown;
|
|
30
|
+
}>): string[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Qué bases ofrece el selector del formulario de una credencial de Postgres.
|
|
4
|
+
*
|
|
5
|
+
* Aparte del servicio, como `mongo-databases.ts`, para que la consulta y el
|
|
6
|
+
* filtrado se puedan probar sin levantar un Postgres.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SQL_BASES_DE_POSTGRES = void 0;
|
|
10
|
+
exports.nombresDeBases = nombresDeBases;
|
|
11
|
+
/**
|
|
12
|
+
* Las bases a las que un cliente se puede conectar de verdad.
|
|
13
|
+
*
|
|
14
|
+
* Los dos filtros están por un motivo concreto, y quitarlos no rompe nada
|
|
15
|
+
* hasta que alguien elige la opción equivocada:
|
|
16
|
+
*
|
|
17
|
+
* - `datistemplate = false` deja fuera `template0` y `template1`, que son
|
|
18
|
+
* plantillas y no destinos.
|
|
19
|
+
* - `datallowconn = true` es el que de verdad importa: **`template0` rechaza
|
|
20
|
+
* conexiones por diseño**. Ofrecerla es ofrecer una opción que sólo puede
|
|
21
|
+
* fallar, y el error (`FATAL: database "template0" is not currently
|
|
22
|
+
* accepting connections`) no se parece en nada a «esa no la elijas».
|
|
23
|
+
*/
|
|
24
|
+
exports.SQL_BASES_DE_POSTGRES = `SELECT datname FROM pg_database
|
|
25
|
+
WHERE datistemplate = false AND datallowconn = true
|
|
26
|
+
ORDER BY datname`;
|
|
27
|
+
/**
|
|
28
|
+
* Los nombres, de lo que devuelva el driver.
|
|
29
|
+
*
|
|
30
|
+
* Se valida el tipo en vez de castear: `pg` tipa las filas por lo que le
|
|
31
|
+
* digas, no por lo que llegue, así que una fila rara entraría como `undefined`
|
|
32
|
+
* y pintaría una opción vacía en el desplegable.
|
|
33
|
+
*/
|
|
34
|
+
function nombresDeBases(filas) {
|
|
35
|
+
return filas
|
|
36
|
+
.map((f) => f.datname)
|
|
37
|
+
.filter((n) => typeof n === 'string' && n.trim() !== '');
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hostwebhook/platform-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Lo que los servicios de HostWebhook comparten del lado de NODE: cifrado y utilidades que no pueden estar escritas dos veces",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|