@aiconnect/confidant 1.0.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/README.md +570 -0
- package/dist/api-client.d.ts +58 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +101 -0
- package/dist/api-client.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/create.d.ts +3 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +51 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/delete.d.ts +3 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +29 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/get-request.d.ts +3 -0
- package/dist/commands/get-request.d.ts.map +1 -0
- package/dist/commands/get-request.js +89 -0
- package/dist/commands/get-request.js.map +1 -0
- package/dist/commands/get.d.ts +3 -0
- package/dist/commands/get.d.ts.map +1 -0
- package/dist/commands/get.js +29 -0
- package/dist/commands/get.js.map +1 -0
- package/dist/commands/request.d.ts +3 -0
- package/dist/commands/request.d.ts.map +1 -0
- package/dist/commands/request.js +289 -0
- package/dist/commands/request.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +40 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/crypto.d.ts +32 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +79 -0
- package/dist/crypto.js.map +1 -0
- package/dist/crypto.test.d.ts +5 -0
- package/dist/crypto.test.d.ts.map +1 -0
- package/dist/crypto.test.js +77 -0
- package/dist/crypto.test.js.map +1 -0
- package/dist/i18n.d.ts +55 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +63 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/network-detection.d.ts +11 -0
- package/dist/network-detection.d.ts.map +1 -0
- package/dist/network-detection.js +54 -0
- package/dist/network-detection.js.map +1 -0
- package/dist/network-detection.test.d.ts +2 -0
- package/dist/network-detection.test.d.ts.map +1 -0
- package/dist/network-detection.test.js +150 -0
- package/dist/network-detection.test.js.map +1 -0
- package/dist/rate-limiter.d.ts +61 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +128 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/rate-limiter.test.d.ts +5 -0
- package/dist/rate-limiter.test.d.ts.map +1 -0
- package/dist/rate-limiter.test.js +130 -0
- package/dist/rate-limiter.test.js.map +1 -0
- package/dist/registry.d.ts +136 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +182 -0
- package/dist/registry.js.map +1 -0
- package/dist/registry.test.d.ts +13 -0
- package/dist/registry.test.d.ts.map +1 -0
- package/dist/registry.test.js +308 -0
- package/dist/registry.test.js.map +1 -0
- package/dist/routes.d.ts +4 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +931 -0
- package/dist/routes.js.map +1 -0
- package/dist/server.d.ts +27 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +79 -0
- package/dist/server.js.map +1 -0
- package/dist/storage.d.ts +150 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +298 -0
- package/dist/storage.js.map +1 -0
- package/dist/storage.test.d.ts +5 -0
- package/dist/storage.test.d.ts.map +1 -0
- package/dist/storage.test.js +466 -0
- package/dist/storage.test.js.map +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +56 -0
- package/dist/types.js.map +1 -0
- package/dist/url-helper.d.ts +16 -0
- package/dist/url-helper.d.ts.map +1 -0
- package/dist/url-helper.js +27 -0
- package/dist/url-helper.js.map +1 -0
- package/dist/url-helper.test.d.ts +2 -0
- package/dist/url-helper.test.d.ts.map +1 -0
- package/dist/url-helper.test.js +70 -0
- package/dist/url-helper.test.js.map +1 -0
- package/package.json +73 -0
- package/public/index.html +352 -0
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portuguese translations for CLI messages
|
|
3
|
+
*/
|
|
4
|
+
export const translations = {
|
|
5
|
+
// Error messages
|
|
6
|
+
secretCannotBeEmpty: 'O segredo não pode estar vazio',
|
|
7
|
+
ttlMustBePositive: 'O TTL deve ser um número positivo',
|
|
8
|
+
maxAccessCountMustBePositive: 'O número máximo de acessos deve ser positivo',
|
|
9
|
+
secretNotFound: 'Segredo não encontrado',
|
|
10
|
+
secretHasExpired: 'O segredo expirou',
|
|
11
|
+
maxAccessCountExceeded: 'Número máximo de acessos excedido',
|
|
12
|
+
connectionFailed: 'Falha na conexão com o servidor',
|
|
13
|
+
requestTimedOut: 'A solicitação expirou',
|
|
14
|
+
invalidApiEndpoint: 'Endpoint de API inválido',
|
|
15
|
+
invalidJsonResponse: 'Resposta JSON inválida do servidor',
|
|
16
|
+
networkError: 'Erro de rede',
|
|
17
|
+
// Help descriptions
|
|
18
|
+
programDescription: 'Ferramenta de CLI para o sistema de transferência de segredos Confidant',
|
|
19
|
+
createDescription: 'Criar um novo segredo',
|
|
20
|
+
getDescription: 'Recuperar um segredo pelo ID',
|
|
21
|
+
deleteDescription: 'Excluir um segredo pelo ID',
|
|
22
|
+
statusDescription: 'Verificar o status de um segredo pelo ID',
|
|
23
|
+
serveDescription: 'Iniciar o servidor Confidant',
|
|
24
|
+
// Option descriptions
|
|
25
|
+
secretOption: 'Conteúdo do segredo (obrigatório)',
|
|
26
|
+
ttlOption: 'Tempo de vida em milissegundos (opcional)',
|
|
27
|
+
maxAccessCountOption: 'Número máximo de acessos (opcional)',
|
|
28
|
+
apiUrlOption: 'URL do endpoint da API',
|
|
29
|
+
portOption: 'Porta do servidor (padrão: 3000)',
|
|
30
|
+
hostOption: 'Host do servidor (padrão: localhost)',
|
|
31
|
+
// Examples
|
|
32
|
+
createExample: 'Exemplo: confidant create --secret "meu segredo" --ttl 60000 --max-access-count 3',
|
|
33
|
+
getExample: 'Exemplo: confidant get abc123',
|
|
34
|
+
deleteExample: 'Exemplo: confidant delete abc123',
|
|
35
|
+
statusExample: 'Exemplo: confidant status abc123',
|
|
36
|
+
// Success messages
|
|
37
|
+
secretCreated: 'Segredo criado com sucesso',
|
|
38
|
+
secretRetrieved: 'Segredo recuperado com sucesso',
|
|
39
|
+
secretDeleted: 'Segredo excluído com sucesso',
|
|
40
|
+
secretStatus: 'Status do segredo',
|
|
41
|
+
serverStarting: 'Iniciando servidor Confidant...',
|
|
42
|
+
serverRunning: '✅ Confidant rodando em:',
|
|
43
|
+
serverShutdown: 'Encerrando servidor Confidant...',
|
|
44
|
+
serverStopped: 'Servidor encerrado',
|
|
45
|
+
// Usage information
|
|
46
|
+
usage: 'Uso',
|
|
47
|
+
options: 'Opções',
|
|
48
|
+
commands: 'Comandos',
|
|
49
|
+
arguments: 'Argumentos',
|
|
50
|
+
required: '(obrigatório)',
|
|
51
|
+
optional: '(opcional)',
|
|
52
|
+
// Server messages
|
|
53
|
+
localhostUrl: ' - %s (localhost)',
|
|
54
|
+
networkUrl: ' - %s (rede local)',
|
|
55
|
+
pressCtrlCToStop: 'Pressione Ctrl+C para parar o servidor',
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Get a translation by key
|
|
59
|
+
*/
|
|
60
|
+
export function t(key) {
|
|
61
|
+
return translations[key];
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,iBAAiB;IACjB,mBAAmB,EAAE,gCAAgC;IACrD,iBAAiB,EAAE,mCAAmC;IACtD,4BAA4B,EAAE,8CAA8C;IAC5E,cAAc,EAAE,wBAAwB;IACxC,gBAAgB,EAAE,mBAAmB;IACrC,sBAAsB,EAAE,mCAAmC;IAC3D,gBAAgB,EAAE,iCAAiC;IACnD,eAAe,EAAE,uBAAuB;IACxC,kBAAkB,EAAE,0BAA0B;IAC9C,mBAAmB,EAAE,oCAAoC;IACzD,YAAY,EAAE,cAAc;IAE5B,oBAAoB;IACpB,kBAAkB,EAAE,yEAAyE;IAC7F,iBAAiB,EAAE,uBAAuB;IAC1C,cAAc,EAAE,8BAA8B;IAC9C,iBAAiB,EAAE,4BAA4B;IAC/C,iBAAiB,EAAE,0CAA0C;IAC7D,gBAAgB,EAAE,8BAA8B;IAEhD,sBAAsB;IACtB,YAAY,EAAE,mCAAmC;IACjD,SAAS,EAAE,2CAA2C;IACtD,oBAAoB,EAAE,qCAAqC;IAC3D,YAAY,EAAE,wBAAwB;IACtC,UAAU,EAAE,kCAAkC;IAC9C,UAAU,EAAE,sCAAsC;IAElD,WAAW;IACX,aAAa,EAAE,mFAAmF;IAClG,UAAU,EAAE,+BAA+B;IAC3C,aAAa,EAAE,kCAAkC;IACjD,aAAa,EAAE,kCAAkC;IAEjD,mBAAmB;IACnB,aAAa,EAAE,4BAA4B;IAC3C,eAAe,EAAE,gCAAgC;IACjD,aAAa,EAAE,8BAA8B;IAC7C,YAAY,EAAE,mBAAmB;IACjC,cAAc,EAAE,iCAAiC;IACjD,aAAa,EAAE,yBAAyB;IACxC,cAAc,EAAE,kCAAkC;IAClD,aAAa,EAAE,oBAAoB;IAEnC,oBAAoB;IACpB,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,QAAQ;IACjB,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,YAAY;IACvB,QAAQ,EAAE,eAAe;IACzB,QAAQ,EAAE,YAAY;IAEtB,kBAAkB;IAClB,YAAY,EAAE,oBAAoB;IAClC,UAAU,EAAE,qBAAqB;IACjC,gBAAgB,EAAE,wCAAwC;CAClD,CAAC;AAIX;;GAEG;AACH,MAAM,UAAU,CAAC,CAAC,GAAmB;IACnC,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { serve } from '@hono/node-server';
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { routes } from './routes.js';
|
|
4
|
+
import { storageRegistry, validatorRegistry, transformerRegistry, MemoryStorageModule, BasicValidatorModule, UppercaseTransformerModule } from './registry.js';
|
|
5
|
+
import { detectLocalIp } from './network-detection.js';
|
|
6
|
+
export { MemoryStorage } from './storage.js';
|
|
7
|
+
const app = new Hono();
|
|
8
|
+
// Register routes
|
|
9
|
+
app.route('/', routes);
|
|
10
|
+
// Health check endpoint
|
|
11
|
+
app.get('/health', (c) => {
|
|
12
|
+
return c.json({ status: 'ok', message: 'Confidant is running' });
|
|
13
|
+
});
|
|
14
|
+
// Initialize registries with example modules
|
|
15
|
+
async function initializeRegistries() {
|
|
16
|
+
try {
|
|
17
|
+
// Register example storage module
|
|
18
|
+
await storageRegistry.register('memory', MemoryStorageModule);
|
|
19
|
+
console.log('✅ Storage registry initialized with memory module');
|
|
20
|
+
// Register example validator module
|
|
21
|
+
await validatorRegistry.register('basic', BasicValidatorModule);
|
|
22
|
+
console.log('✅ Validator registry initialized with basic module');
|
|
23
|
+
// Register example transformer module
|
|
24
|
+
await transformerRegistry.register('uppercase', UppercaseTransformerModule);
|
|
25
|
+
console.log('✅ Transformer registry initialized with uppercase module');
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error('❌ Failed to initialize registries:', error);
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Start server
|
|
33
|
+
const port = parseInt(process.env.PORT || '3000');
|
|
34
|
+
console.log(`Starting Confidant server on port ${port}...`);
|
|
35
|
+
// Initialize registries before starting server
|
|
36
|
+
initializeRegistries().then(() => {
|
|
37
|
+
serve({
|
|
38
|
+
fetch: app.fetch,
|
|
39
|
+
port,
|
|
40
|
+
}, (info) => {
|
|
41
|
+
console.log(`✅ Confidant running at:`);
|
|
42
|
+
// Detect local IP for network URL
|
|
43
|
+
const localIp = detectLocalIp();
|
|
44
|
+
console.log(` - http://localhost:${info.port} (localhost)`);
|
|
45
|
+
if (localIp) {
|
|
46
|
+
console.log(` - http://${localIp}:${info.port} (rede local)`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}).catch((error) => {
|
|
50
|
+
console.error('Failed to start server:', error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC/J,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAA0C,MAAM,cAAc,CAAC;AAErF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;AAEvB,kBAAkB;AAClB,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAEvB,wBAAwB;AACxB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;IACvB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC;AAEH,6CAA6C;AAC7C,KAAK,UAAU,oBAAoB;IACjC,IAAI,CAAC;QACH,kCAAkC;QAClC,MAAM,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;QAEjE,oCAAoC;QACpC,MAAM,iBAAiB,CAAC,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAElE,sCAAsC;QACtC,MAAM,mBAAmB,CAAC,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;QAC3D,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,eAAe;AACf,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC;AAClD,OAAO,CAAC,GAAG,CAAC,qCAAqC,IAAI,KAAK,CAAC,CAAC;AAE5D,+CAA+C;AAC/C,oBAAoB,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;IAC/B,KAAK,CAAC;QACJ,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI;KACL,EAAE,CAAC,IAAI,EAAE,EAAE;QACV,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QAEvC,kCAAkC;QAClC,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;QAEhC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,IAAI,cAAc,CAAC,CAAC;QAC7D,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,IAAI,IAAI,CAAC,IAAI,eAAe,CAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if an IP address is in a private range
|
|
3
|
+
* Private ranges: 192.168.x.x, 10.x.x.x, 172.16-31.x.x
|
|
4
|
+
*/
|
|
5
|
+
export declare function isPrivateIp(ip: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Detect local network IP address for cross-device access
|
|
8
|
+
* Returns first private IP address found, or null if none detected
|
|
9
|
+
*/
|
|
10
|
+
export declare function detectLocalIp(): string | null;
|
|
11
|
+
//# sourceMappingURL=network-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-detection.d.ts","sourceRoot":"","sources":["../src/network-detection.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAuB/C;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CA0B7C"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as os from 'os';
|
|
2
|
+
/**
|
|
3
|
+
* Check if an IP address is in a private range
|
|
4
|
+
* Private ranges: 192.168.x.x, 10.x.x.x, 172.16-31.x.x
|
|
5
|
+
*/
|
|
6
|
+
export function isPrivateIp(ip) {
|
|
7
|
+
const parts = ip.split('.').map(Number);
|
|
8
|
+
if (parts.length !== 4) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
// 10.0.0.0 - 10.255.255.255
|
|
12
|
+
if (parts[0] === 10) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
// 172.16.0.0 - 172.31.255.255
|
|
16
|
+
if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
// 192.168.0.0 - 192.168.255.255
|
|
20
|
+
if (parts[0] === 192 && parts[1] === 168) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Detect local network IP address for cross-device access
|
|
27
|
+
* Returns first private IP address found, or null if none detected
|
|
28
|
+
*/
|
|
29
|
+
export function detectLocalIp() {
|
|
30
|
+
try {
|
|
31
|
+
const interfaces = os.networkInterfaces();
|
|
32
|
+
for (const name of Object.keys(interfaces)) {
|
|
33
|
+
const networkInterface = interfaces[name];
|
|
34
|
+
if (!networkInterface)
|
|
35
|
+
continue;
|
|
36
|
+
for (const iface of networkInterface) {
|
|
37
|
+
// Skip internal and non-IPv4 addresses
|
|
38
|
+
if (iface.internal || iface.family !== 'IPv4') {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// Check if IP is in private range
|
|
42
|
+
if (isPrivateIp(iface.address)) {
|
|
43
|
+
return iface.address;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// If detection fails, return null gracefully
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=network-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-detection.js","sourceRoot":"","sources":["../src/network-detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAExC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,4BAA4B;IAC5B,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8BAA8B;IAC9B,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gCAAgC;IAChC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;QAE1C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3C,MAAM,gBAAgB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,CAAC,gBAAgB;gBAAE,SAAS;YAEhC,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;gBACrC,uCAAuC;gBACvC,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;oBAC9C,SAAS;gBACX,CAAC;gBAED,kCAAkC;gBAClC,IAAI,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC/B,OAAO,KAAK,CAAC,OAAO,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,6CAA6C;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-detection.test.d.ts","sourceRoot":"","sources":["../src/network-detection.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import { isPrivateIp, detectLocalIp } from './network-detection.js';
|
|
4
|
+
// Mock the os module
|
|
5
|
+
vi.mock('os', () => ({
|
|
6
|
+
networkInterfaces: vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
describe('network detection', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
vi.clearAllMocks();
|
|
11
|
+
});
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
vi.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
describe('isPrivateIp', () => {
|
|
16
|
+
it('should return true for 10.x.x.x addresses', () => {
|
|
17
|
+
expect(isPrivateIp('10.0.0.1')).toBe(true);
|
|
18
|
+
expect(isPrivateIp('10.255.255.255')).toBe(true);
|
|
19
|
+
expect(isPrivateIp('10.128.64.32')).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it('should return true for 172.16.x.x to 172.31.x.x addresses', () => {
|
|
22
|
+
expect(isPrivateIp('172.16.0.1')).toBe(true);
|
|
23
|
+
expect(isPrivateIp('172.31.255.255')).toBe(true);
|
|
24
|
+
expect(isPrivateIp('172.20.128.64')).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('should return false for 172.15.x.x addresses', () => {
|
|
27
|
+
expect(isPrivateIp('172.15.255.255')).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
it('should return false for 172.32.x.x addresses', () => {
|
|
30
|
+
expect(isPrivateIp('172.32.0.1')).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
it('should return true for 192.168.x.x addresses', () => {
|
|
33
|
+
expect(isPrivateIp('192.168.0.1')).toBe(true);
|
|
34
|
+
expect(isPrivateIp('192.168.255.255')).toBe(true);
|
|
35
|
+
expect(isPrivateIp('192.168.128.64')).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
it('should return false for public IP addresses', () => {
|
|
38
|
+
expect(isPrivateIp('8.8.8.8')).toBe(false);
|
|
39
|
+
expect(isPrivateIp('1.1.1.1')).toBe(false);
|
|
40
|
+
expect(isPrivateIp('172.32.0.1')).toBe(false);
|
|
41
|
+
expect(isPrivateIp('192.169.0.1')).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
it('should return false for invalid IP addresses', () => {
|
|
44
|
+
expect(isPrivateIp('')).toBe(false);
|
|
45
|
+
expect(isPrivateIp('invalid')).toBe(false);
|
|
46
|
+
expect(isPrivateIp('192.168')).toBe(false);
|
|
47
|
+
expect(isPrivateIp('192.168.1.1.1')).toBe(false);
|
|
48
|
+
expect(isPrivateIp('256.168.1.1')).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('detectLocalIp', () => {
|
|
52
|
+
it('should return first private IP address found', () => {
|
|
53
|
+
const mockInterfaces = [
|
|
54
|
+
{ address: '192.168.1.100', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: false, cidr: '192.168.1.100/24' },
|
|
55
|
+
{ address: '10.0.0.1', netmask: '255.0.0.0', family: 'IPv4', mac: '00:00:00:00:00:01', internal: false, cidr: '10.0.0.1/8' },
|
|
56
|
+
];
|
|
57
|
+
vi.mocked(os.networkInterfaces).mockReturnValue({
|
|
58
|
+
'eth0': mockInterfaces,
|
|
59
|
+
});
|
|
60
|
+
const result = detectLocalIp();
|
|
61
|
+
expect(result).toBe('192.168.1.100');
|
|
62
|
+
});
|
|
63
|
+
it('should skip internal addresses', () => {
|
|
64
|
+
const mockInterfaces = [
|
|
65
|
+
{ address: '127.0.0.1', netmask: '255.0.0.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: true, cidr: '127.0.0.1/8' },
|
|
66
|
+
{ address: '192.168.1.100', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:01', internal: false, cidr: '192.168.1.100/24' },
|
|
67
|
+
];
|
|
68
|
+
vi.mocked(os.networkInterfaces).mockReturnValue({
|
|
69
|
+
'lo': [mockInterfaces[0]],
|
|
70
|
+
'eth0': [mockInterfaces[1]],
|
|
71
|
+
});
|
|
72
|
+
const result = detectLocalIp();
|
|
73
|
+
expect(result).toBe('192.168.1.100');
|
|
74
|
+
});
|
|
75
|
+
it('should skip IPv6 addresses', () => {
|
|
76
|
+
const mockInterfaces = [
|
|
77
|
+
{ address: 'fe80::1', netmask: 'ffff:ffff:ffff:ffff::', family: 'IPv6', mac: '00:00:00:00:00:00', internal: false, cidr: 'fe80::1/64', scopeid: 1 },
|
|
78
|
+
{ address: '192.168.1.100', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:01', internal: false, cidr: '192.168.1.100/24' },
|
|
79
|
+
];
|
|
80
|
+
vi.mocked(os.networkInterfaces).mockReturnValue({
|
|
81
|
+
'eth0': mockInterfaces,
|
|
82
|
+
});
|
|
83
|
+
const result = detectLocalIp();
|
|
84
|
+
expect(result).toBe('192.168.1.100');
|
|
85
|
+
});
|
|
86
|
+
it('should skip public IP addresses', () => {
|
|
87
|
+
const mockInterfaces = [
|
|
88
|
+
{ address: '8.8.8.8', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: false, cidr: '8.8.8.8/24' },
|
|
89
|
+
{ address: '192.168.1.100', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:01', internal: false, cidr: '192.168.1.100/24' },
|
|
90
|
+
];
|
|
91
|
+
vi.mocked(os.networkInterfaces).mockReturnValue({
|
|
92
|
+
'eth0': mockInterfaces,
|
|
93
|
+
});
|
|
94
|
+
const result = detectLocalIp();
|
|
95
|
+
expect(result).toBe('192.168.1.100');
|
|
96
|
+
});
|
|
97
|
+
it('should return null when no private IP is found', () => {
|
|
98
|
+
const mockInterfaces = [
|
|
99
|
+
{ address: '8.8.8.8', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: false, cidr: '8.8.8.8/24' },
|
|
100
|
+
{ address: '127.0.0.1', netmask: '255.0.0.0', family: 'IPv4', mac: '00:00:00:00:00:01', internal: true, cidr: '127.0.0.1/8' },
|
|
101
|
+
];
|
|
102
|
+
vi.mocked(os.networkInterfaces).mockReturnValue({
|
|
103
|
+
'eth0': [mockInterfaces[0]],
|
|
104
|
+
'lo': [mockInterfaces[1]],
|
|
105
|
+
});
|
|
106
|
+
const result = detectLocalIp();
|
|
107
|
+
expect(result).toBeNull();
|
|
108
|
+
});
|
|
109
|
+
it('should return null when networkInterfaces returns empty object', () => {
|
|
110
|
+
vi.mocked(os.networkInterfaces).mockReturnValue({});
|
|
111
|
+
const result = detectLocalIp();
|
|
112
|
+
expect(result).toBeNull();
|
|
113
|
+
});
|
|
114
|
+
it('should return null when networkInterfaces throws error', () => {
|
|
115
|
+
vi.mocked(os.networkInterfaces).mockImplementation(() => {
|
|
116
|
+
throw new Error('Network error');
|
|
117
|
+
});
|
|
118
|
+
const result = detectLocalIp();
|
|
119
|
+
expect(result).toBeNull();
|
|
120
|
+
});
|
|
121
|
+
it('should handle multiple network interfaces', () => {
|
|
122
|
+
const mockInterfaces = {
|
|
123
|
+
'eth0': [
|
|
124
|
+
{ address: '8.8.8.8', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: false, cidr: '8.8.8.8/24' },
|
|
125
|
+
],
|
|
126
|
+
'wlan0': [
|
|
127
|
+
{ address: '192.168.1.100', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:01', internal: false, cidr: '192.168.1.100/24' },
|
|
128
|
+
],
|
|
129
|
+
'lo': [
|
|
130
|
+
{ address: '127.0.0.1', netmask: '255.0.0.0', family: 'IPv4', mac: '00:00:00:00:00:02', internal: true, cidr: '127.0.0.1/8' },
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
vi.mocked(os.networkInterfaces).mockReturnValue(mockInterfaces);
|
|
134
|
+
const result = detectLocalIp();
|
|
135
|
+
expect(result).toBe('192.168.1.100');
|
|
136
|
+
});
|
|
137
|
+
it('should prefer 10.x.x.x over 192.168.x.x when both present', () => {
|
|
138
|
+
const mockInterfaces = [
|
|
139
|
+
{ address: '192.168.1.100', netmask: '255.255.255.0', family: 'IPv4', mac: '00:00:00:00:00:00', internal: false, cidr: '192.168.1.100/24' },
|
|
140
|
+
{ address: '10.0.0.1', netmask: '255.0.0.0', family: 'IPv4', mac: '00:00:00:00:00:01', internal: false, cidr: '10.0.0.1/8' },
|
|
141
|
+
];
|
|
142
|
+
vi.mocked(os.networkInterfaces).mockReturnValue({
|
|
143
|
+
'eth0': mockInterfaces,
|
|
144
|
+
});
|
|
145
|
+
const result = detectLocalIp();
|
|
146
|
+
expect(result).toBe('192.168.1.100'); // First one found
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=network-detection.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-detection.test.js","sourceRoot":"","sources":["../src/network-detection.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter
|
|
3
|
+
*
|
|
4
|
+
* Implements in-memory rate limiting using a sliding window algorithm.
|
|
5
|
+
* Prevents brute-force attacks on hash space and API abuse.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Rate limiter configuration
|
|
9
|
+
*/
|
|
10
|
+
export interface RateLimiterConfig {
|
|
11
|
+
maxRequests: number;
|
|
12
|
+
windowMs: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Rate limiter result
|
|
16
|
+
*/
|
|
17
|
+
export interface RateLimitResult {
|
|
18
|
+
allowed: boolean;
|
|
19
|
+
remaining: number;
|
|
20
|
+
resetTime: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* In-memory rate limiter using sliding window algorithm
|
|
24
|
+
*/
|
|
25
|
+
export declare class RateLimiter {
|
|
26
|
+
private records;
|
|
27
|
+
private config;
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new rate limiter
|
|
30
|
+
* @param config Rate limiter configuration
|
|
31
|
+
*/
|
|
32
|
+
constructor(config: RateLimiterConfig);
|
|
33
|
+
/**
|
|
34
|
+
* Check if a request from the given IP is allowed
|
|
35
|
+
* @param ip The client IP address
|
|
36
|
+
* @returns Rate limit result
|
|
37
|
+
*/
|
|
38
|
+
check(ip: string): RateLimitResult;
|
|
39
|
+
/**
|
|
40
|
+
* Reset the rate limit for a specific IP
|
|
41
|
+
* @param ip The client IP address
|
|
42
|
+
*/
|
|
43
|
+
reset(ip: string): void;
|
|
44
|
+
/**
|
|
45
|
+
* Clean up old records to prevent memory leaks
|
|
46
|
+
* @param maxAge Maximum age of records to keep in milliseconds
|
|
47
|
+
*/
|
|
48
|
+
cleanup(maxAge?: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* Get the current rate limit status for an IP without incrementing
|
|
51
|
+
* @param ip The client IP address
|
|
52
|
+
* @returns Rate limit result
|
|
53
|
+
*/
|
|
54
|
+
getStatus(ip: string): RateLimitResult;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Default rate limiter for secret request endpoints
|
|
58
|
+
* 10 requests per minute per IP
|
|
59
|
+
*/
|
|
60
|
+
export declare const defaultRateLimiter: RateLimiter;
|
|
61
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,MAAM,CAAoB;IAElC;;;OAGG;gBACS,MAAM,EAAE,iBAAiB;IAKrC;;;;OAIG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe;IAmDlC;;;OAGG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIvB;;;OAGG;IACH,OAAO,CAAC,MAAM,GAAE,MAAgB,GAAG,IAAI;IAUvC;;;;OAIG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe;CA4BvC;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,aAG7B,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter
|
|
3
|
+
*
|
|
4
|
+
* Implements in-memory rate limiting using a sliding window algorithm.
|
|
5
|
+
* Prevents brute-force attacks on hash space and API abuse.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* In-memory rate limiter using sliding window algorithm
|
|
9
|
+
*/
|
|
10
|
+
export class RateLimiter {
|
|
11
|
+
records;
|
|
12
|
+
config;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new rate limiter
|
|
15
|
+
* @param config Rate limiter configuration
|
|
16
|
+
*/
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.records = new Map();
|
|
19
|
+
this.config = config;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if a request from the given IP is allowed
|
|
23
|
+
* @param ip The client IP address
|
|
24
|
+
* @returns Rate limit result
|
|
25
|
+
*/
|
|
26
|
+
check(ip) {
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
const record = this.records.get(ip);
|
|
29
|
+
// No existing record, create a new one
|
|
30
|
+
if (!record) {
|
|
31
|
+
this.records.set(ip, {
|
|
32
|
+
count: 1,
|
|
33
|
+
windowStart: now
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
allowed: true,
|
|
37
|
+
remaining: this.config.maxRequests - 1,
|
|
38
|
+
resetTime: now + this.config.windowMs
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// Check if the window has expired
|
|
42
|
+
const windowAge = now - record.windowStart;
|
|
43
|
+
if (windowAge >= this.config.windowMs) {
|
|
44
|
+
// Reset the window
|
|
45
|
+
record.count = 1;
|
|
46
|
+
record.windowStart = now;
|
|
47
|
+
return {
|
|
48
|
+
allowed: true,
|
|
49
|
+
remaining: this.config.maxRequests - 1,
|
|
50
|
+
resetTime: now + this.config.windowMs
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Check if the limit has been exceeded
|
|
54
|
+
if (record.count >= this.config.maxRequests) {
|
|
55
|
+
return {
|
|
56
|
+
allowed: false,
|
|
57
|
+
remaining: 0,
|
|
58
|
+
resetTime: record.windowStart + this.config.windowMs
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Increment the count
|
|
62
|
+
record.count++;
|
|
63
|
+
return {
|
|
64
|
+
allowed: true,
|
|
65
|
+
remaining: this.config.maxRequests - record.count,
|
|
66
|
+
resetTime: record.windowStart + this.config.windowMs
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Reset the rate limit for a specific IP
|
|
71
|
+
* @param ip The client IP address
|
|
72
|
+
*/
|
|
73
|
+
reset(ip) {
|
|
74
|
+
this.records.delete(ip);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Clean up old records to prevent memory leaks
|
|
78
|
+
* @param maxAge Maximum age of records to keep in milliseconds
|
|
79
|
+
*/
|
|
80
|
+
cleanup(maxAge = 3600000) {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
for (const [ip, record] of Array.from(this.records.entries())) {
|
|
83
|
+
const recordAge = now - record.windowStart;
|
|
84
|
+
if (recordAge > maxAge) {
|
|
85
|
+
this.records.delete(ip);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get the current rate limit status for an IP without incrementing
|
|
91
|
+
* @param ip The client IP address
|
|
92
|
+
* @returns Rate limit result
|
|
93
|
+
*/
|
|
94
|
+
getStatus(ip) {
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
const record = this.records.get(ip);
|
|
97
|
+
if (!record) {
|
|
98
|
+
return {
|
|
99
|
+
allowed: true,
|
|
100
|
+
remaining: this.config.maxRequests,
|
|
101
|
+
resetTime: now + this.config.windowMs
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// Check if the window has expired
|
|
105
|
+
const windowAge = now - record.windowStart;
|
|
106
|
+
if (windowAge >= this.config.windowMs) {
|
|
107
|
+
return {
|
|
108
|
+
allowed: true,
|
|
109
|
+
remaining: this.config.maxRequests,
|
|
110
|
+
resetTime: now + this.config.windowMs
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
allowed: record.count < this.config.maxRequests,
|
|
115
|
+
remaining: Math.max(0, this.config.maxRequests - record.count),
|
|
116
|
+
resetTime: record.windowStart + this.config.windowMs
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Default rate limiter for secret request endpoints
|
|
122
|
+
* 10 requests per minute per IP
|
|
123
|
+
*/
|
|
124
|
+
export const defaultRateLimiter = new RateLimiter({
|
|
125
|
+
maxRequests: 10,
|
|
126
|
+
windowMs: 60000 // 1 minute
|
|
127
|
+
});
|
|
128
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.test.d.ts","sourceRoot":"","sources":["../src/rate-limiter.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|