@depup/redbird 1.0.2-depup.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.
Files changed (41) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +35 -0
  3. package/changes.json +26 -0
  4. package/dist/docker.d.ts +30 -0
  5. package/dist/docker.js +136 -0
  6. package/dist/docker.js.map +1 -0
  7. package/dist/etcd-backend.d.ts +12 -0
  8. package/dist/etcd-backend.js +80 -0
  9. package/dist/etcd-backend.js.map +1 -0
  10. package/dist/index.d.ts +4 -0
  11. package/dist/index.js +7 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/interfaces/index.d.ts +2 -0
  14. package/dist/interfaces/index.js +3 -0
  15. package/dist/interfaces/index.js.map +1 -0
  16. package/dist/interfaces/proxy-options.d.ts +36 -0
  17. package/dist/interfaces/proxy-options.js +2 -0
  18. package/dist/interfaces/proxy-options.js.map +1 -0
  19. package/dist/interfaces/proxy-route.d.ts +14 -0
  20. package/dist/interfaces/proxy-route.js +2 -0
  21. package/dist/interfaces/proxy-route.js.map +1 -0
  22. package/dist/interfaces/proxy-target-url.d.ts +8 -0
  23. package/dist/interfaces/proxy-target-url.js +2 -0
  24. package/dist/interfaces/proxy-target-url.js.map +1 -0
  25. package/dist/interfaces/resolver.d.ts +12 -0
  26. package/dist/interfaces/resolver.js +2 -0
  27. package/dist/interfaces/resolver.js.map +1 -0
  28. package/dist/interfaces/route-options.d.ts +15 -0
  29. package/dist/interfaces/route-options.js +2 -0
  30. package/dist/interfaces/route-options.js.map +1 -0
  31. package/dist/letsencrypt.d.ts +19 -0
  32. package/dist/letsencrypt.js +127 -0
  33. package/dist/letsencrypt.js.map +1 -0
  34. package/dist/proxy.d.ts +122 -0
  35. package/dist/proxy.js +812 -0
  36. package/dist/proxy.js.map +1 -0
  37. package/dist/third-party/le-challenge-fs.d.ts +8 -0
  38. package/dist/third-party/le-challenge-fs.js +140 -0
  39. package/dist/third-party/le-challenge-fs.js.map +1 -0
  40. package/dist/tsconfig.tsbuildinfo +1 -0
  41. package/package.json +143 -0
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Letsecript module for Redbird (c) Optimalbits 2016-2024
3
+ *
4
+ *
5
+ *
6
+ */
7
+ import { createServer } from 'http';
8
+ import path from 'path';
9
+ import url from 'url';
10
+ import fs from 'fs';
11
+ import LeChallengeFs from './third-party/le-challenge-fs.js';
12
+ /**
13
+ * LetsEncrypt certificates are stored like the following:
14
+ *
15
+ * /example.com
16
+ * /
17
+ *
18
+ *
19
+ *
20
+ */
21
+ let leStoreConfig = {};
22
+ const webrootPath = ':configDir/:hostname/.well-known/acme-challenge';
23
+ function init(certPath, port, logger) {
24
+ logger === null || logger === void 0 ? void 0 : logger.info('Initializing letsencrypt, path %s, port: %s', certPath, port);
25
+ leStoreConfig = {
26
+ configDir: certPath,
27
+ privkeyPath: ':configDir/:hostname/privkey.pem',
28
+ fullchainPath: ':configDir/:hostname/fullchain.pem',
29
+ certPath: ':configDir/:hostname/cert.pem',
30
+ chainPath: ':configDir/:hostname/chain.pem',
31
+ workDir: ':configDir/letsencrypt/var/lib',
32
+ logsDir: ':configDir/letsencrypt/var/log',
33
+ webrootPath,
34
+ debug: false,
35
+ };
36
+ // we need to proxy for example: 'example.com/.well-known/acme-challenge' -> 'localhost:port/example.com/'
37
+ return createServer(function (req, res) {
38
+ if (req.method !== 'GET') {
39
+ res.statusCode = 405; // Method Not Allowed
40
+ res.end();
41
+ return;
42
+ }
43
+ const reqPath = url.parse(req.url).pathname;
44
+ const basePath = path.resolve(certPath);
45
+ const safePath = path.normalize(reqPath).replace(/^(\.\.[\/\\])+/, ''); // Prevent directory traversal
46
+ const fullPath = path.join(basePath, safePath);
47
+ if (!fullPath.startsWith(basePath)) {
48
+ logger === null || logger === void 0 ? void 0 : logger.info(`Attempted directory traversal attack: ${req.url}`);
49
+ res.statusCode = 403; // Forbidden
50
+ res.end('Access denied');
51
+ return;
52
+ }
53
+ logger === null || logger === void 0 ? void 0 : logger.info('LetsEncrypt CA trying to validate challenge %s', fullPath);
54
+ fs.stat(fullPath, function (err, stats) {
55
+ if (err || !stats.isFile()) {
56
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
57
+ res.write('404 Not Found\n');
58
+ res.end();
59
+ return;
60
+ }
61
+ res.writeHead(200);
62
+ fs.createReadStream(fullPath, 'binary').pipe(res);
63
+ });
64
+ }).listen(port);
65
+ }
66
+ /**
67
+ * Gets the certificates for the given domain.
68
+ * Handles all the LetsEncrypt protocol. Uses
69
+ * existing certificates if any, or negotiates a new one.
70
+ * Returns a promise that resolves to an object with the certificates.
71
+ * TODO: We should use something like https://github.com/PaquitoSoft/memored/blob/master/index.js
72
+ * to avoid
73
+ */
74
+ async function getCertificates(domain, email, loopbackPort, production, renew, logger) {
75
+ const LE = (await import('greenlock')).default;
76
+ // Storage Backend
77
+ const leStore = (await import('le-store-certbot')).create(leStoreConfig);
78
+ // ACME Challenge Handlers
79
+ const leChallenge = LeChallengeFs.create({
80
+ loopbackPort: loopbackPort,
81
+ webrootPath,
82
+ debug: false,
83
+ });
84
+ const le = LE.create({
85
+ server: production
86
+ ? 'https://acme-v02.api.letsencrypt.org/directory'
87
+ : 'https://acme-staging-v02.api.letsencrypt.org/directory',
88
+ store: leStore, // handles saving of config, accounts, and certificates
89
+ challenges: { 'http-01': leChallenge }, // handles /.well-known/acme-challege keys and tokens
90
+ challengeType: 'http-01', // default to this challenge type
91
+ debug: false,
92
+ log: function () {
93
+ logger === null || logger === void 0 ? void 0 : logger.info(arguments, 'Lets encrypt debugger');
94
+ },
95
+ });
96
+ // Check in-memory cache of certificates for the named domain
97
+ const cert = await le.check({ domains: [domain] });
98
+ const opts = {
99
+ domains: [domain],
100
+ email: email,
101
+ agreeTos: true,
102
+ rsaKeySize: 2048, // 2048 or higher
103
+ challengeType: 'http-01',
104
+ };
105
+ if (cert) {
106
+ if (renew) {
107
+ logger && logger.info('renewing cert for ' + domain);
108
+ opts.duplicate = true;
109
+ return le.renew(opts, cert).catch(function (err) {
110
+ logger && logger.error(err, 'Error renewing certificates for ', domain);
111
+ });
112
+ }
113
+ else {
114
+ logger && logger.info('Using cached cert for ' + domain);
115
+ return cert;
116
+ }
117
+ }
118
+ else {
119
+ // Register Certificate manually
120
+ logger === null || logger === void 0 ? void 0 : logger.info('Manually registering certificate for %s', domain);
121
+ return le.register(opts).catch(function (err) {
122
+ logger === null || logger === void 0 ? void 0 : logger.error(err, 'Error registering LetsEncrypt certificates');
123
+ });
124
+ }
125
+ }
126
+ export { init, getCertificates };
127
+ //# sourceMappingURL=letsencrypt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"letsencrypt.js","sourceRoot":"","sources":["../lib/letsencrypt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAmC,YAAY,EAAE,MAAM,MAAM,CAAC;AACrE,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,MAAM,IAAI,CAAC;AAGpB,OAAO,aAAa,MAAM,kCAAkC,CAAC;AAE7D;;;;;;;;GAQG;AACH,IAAI,aAAa,GAAG,EAAE,CAAC;AACvB,MAAM,WAAW,GAAG,iDAAiD,CAAC;AAEtE,SAAS,IAAI,CAAC,QAAgB,EAAE,IAAY,EAAE,MAAmC;IAC/E,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,CAAC,6CAA6C,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAE5E,aAAa,GAAG;QACd,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,kCAAkC;QAC/C,aAAa,EAAE,oCAAoC;QACnD,QAAQ,EAAE,+BAA+B;QACzC,SAAS,EAAE,gCAAgC;QAE3C,OAAO,EAAE,gCAAgC;QACzC,OAAO,EAAE,gCAAgC;QAEzC,WAAW;QACX,KAAK,EAAE,KAAK;KACb,CAAC;IAEF,0GAA0G;IAC1G,OAAO,YAAY,CAAC,UAAU,GAAoB,EAAE,GAAmB;QACrE,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YACzB,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,qBAAqB;YAC3C,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,8BAA8B;QACtG,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAE/C,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,CAAC,yCAAyC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;YACjE,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,YAAY;YAClC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACzB,OAAO;QACT,CAAC;QAED,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,CAAC,gDAAgD,EAAE,QAAQ,CAAC,CAAC;QAEzE,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,GAAU,EAAE,KAAU;YAChD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC3B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;gBACrD,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;gBAC7B,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,eAAe,CAC5B,MAAc,EACd,KAAa,EACb,YAAoB,EACpB,UAAmB,EACnB,KAAc,EACd,MAAmC;IAEnC,MAAM,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;IAE/C,kBAAkB;IAClB,MAAM,OAAO,GAAG,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAEzE,0BAA0B;IAC1B,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC;QACvC,YAAY,EAAE,YAAY;QAC1B,WAAW;QACX,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;IAEH,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC;QACnB,MAAM,EAAE,UAAU;YAChB,CAAC,CAAC,gDAAgD;YAClD,CAAC,CAAC,wDAAwD;QAC5D,KAAK,EAAE,OAAO,EAAE,uDAAuD;QACvE,UAAU,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,qDAAqD;QAC7F,aAAa,EAAE,SAAS,EAAE,iCAAiC;QAC3D,KAAK,EAAE,KAAK;QACZ,GAAG,EAAE;YACH,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;QACnD,CAAC;KACF,CAAC,CAAC;IAEH,6DAA6D;IAC7D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEnD,MAAM,IAAI,GAON;QACF,OAAO,EAAE,CAAC,MAAM,CAAC;QACjB,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,IAAI,EAAE,iBAAiB;QACnC,aAAa,EAAE,SAAS;KACzB,CAAC;IAEF,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,oBAAoB,GAAG,MAAM,CAAC,CAAC;YACrD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,GAAU;gBACpD,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,kCAAkC,EAAE,MAAM,CAAC,CAAC;YAC1E,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,wBAAwB,GAAG,MAAM,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;SAAM,CAAC;QACN,gCAAgC;QAChC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,CAAC,yCAAyC,EAAE,MAAM,CAAC,CAAC;QAChE,OAAO,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,GAAU;YACjD,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,GAAG,EAAE,4CAA4C,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,122 @@
1
+ import { URL } from 'url';
2
+ import http, { IncomingMessage, ServerResponse } from 'http';
3
+ import httpProxy from 'http-proxy';
4
+ import { pino, Logger } from 'pino';
5
+ import { ProxyOptions } from './interfaces/proxy-options.js';
6
+ import { ProxyRoute } from './interfaces/proxy-route.js';
7
+ import { RouteOptions } from './interfaces/route-options.js';
8
+ import { Resolver, ResolverFn } from './interfaces/resolver.js';
9
+ export declare class Redbird {
10
+ private opts;
11
+ logger?: Logger;
12
+ routing: any;
13
+ resolvers: Resolver[];
14
+ certs: any;
15
+ lazyCerts: {
16
+ [key: string]: {
17
+ email: string;
18
+ production: boolean;
19
+ renewWithin: number;
20
+ };
21
+ };
22
+ private _defaultResolver;
23
+ private proxy;
24
+ private agent;
25
+ private server;
26
+ private httpsServer;
27
+ private letsencryptHost;
28
+ private letsencryptServer;
29
+ get defaultResolver(): any;
30
+ constructor(opts?: ProxyOptions);
31
+ setupHttpProxy(proxy: httpProxy, websocketsUpgrade: any, log: pino.Logger, opts: ProxyOptions): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
32
+ /**
33
+ * Special resolver for handling Let's Encrypt ACME challenges.
34
+ * @param opts
35
+ */
36
+ setupLetsencrypt(opts: ProxyOptions): void;
37
+ setupHttpsProxy(proxy: httpProxy, websocketsUpgrade: any, sslOpts: any): void;
38
+ addResolver(resolverFn: ResolverFn, priority?: number): this;
39
+ removeResolver(resolverFn: ResolverFn): this;
40
+ /**
41
+ Register a new route.
42
+
43
+ @src {String|URL} A string or a url parsed by node url module.
44
+ Note that port is ignored, since the proxy just listens to one port.
45
+
46
+ @target {String|URL} A string or a url parsed by node url module.
47
+ @opts {Object} Route options.
48
+ */
49
+ register(opts: {
50
+ src: string | URL;
51
+ target: string | URL;
52
+ } & RouteOptions): Promise<void>;
53
+ register(src: string, opts: any): Promise<void>;
54
+ register(src: string | URL, target: string | URL, opts: RouteOptions): Promise<void>;
55
+ updateCertificates(domain: string, email: string, production: boolean, renewWithin: number, renew?: boolean): Promise<void>;
56
+ unregister(src: string | URL, target?: string | URL): Redbird;
57
+ private applyResolvers;
58
+ /**
59
+ * Resolves to route
60
+ * @param host
61
+ * @param url
62
+ * @returns {*}
63
+ */
64
+ resolve(host: string, url?: string, req?: IncomingMessage): Promise<ProxyRoute | undefined>;
65
+ getTarget(src: string, req: IncomingMessage, res?: ServerResponse): Promise<void | import("./interfaces/proxy-target-url.js").ProxyTargetUrl>;
66
+ getSource(req: IncomingMessage): string;
67
+ close(): Promise<void>;
68
+ /**
69
+ Routing table structure. An object with hostname as key, and an array as value.
70
+ The array has one element per path associated to the given hostname.
71
+ Every path has a Round-Robin value (rr) and urls array, with all the urls available
72
+ for this target route.
73
+
74
+ {
75
+ hostA :
76
+ [
77
+ {
78
+ path: '/',
79
+ rr: 3,
80
+ urls: []
81
+ }
82
+ ]
83
+ }
84
+ */
85
+ notFound(callback: any): void;
86
+ shouldRedirectToHttps(target: any): boolean;
87
+ }
88
+ export declare const buildRoute: (route: string | ProxyRoute) => ProxyRoute | null;
89
+ export declare const buildTarget: (target: string | URL, opts?: {
90
+ ssl?: any;
91
+ useTargetHostHeader?: boolean;
92
+ }) => {
93
+ sslRedirect: boolean;
94
+ useTargetHostHeader: boolean;
95
+ hash: string;
96
+ host: string;
97
+ hostname: string;
98
+ href: string;
99
+ origin: string;
100
+ password: string;
101
+ pathname: string;
102
+ port: string;
103
+ protocol: string;
104
+ search: string;
105
+ searchParams: import("url").URLSearchParams;
106
+ username: string;
107
+ } | {
108
+ sslRedirect: boolean;
109
+ useTargetHostHeader: boolean;
110
+ query: string | null;
111
+ auth: string | null;
112
+ hash: string | null;
113
+ host: string | null;
114
+ hostname: string | null;
115
+ href: string;
116
+ path: string | null;
117
+ pathname: string | null;
118
+ protocol: string | null;
119
+ search: string | null;
120
+ slashes: boolean | null;
121
+ port: string | null;
122
+ };