@plasius/api 1.0.4 → 1.0.6
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 +33 -1
- package/README.md +5 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.d.ts +10 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +26 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/withCSRF.d.ts +3 -0
- package/dist/middleware/withCSRF.d.ts.map +1 -0
- package/dist/middleware/withCSRF.js +52 -0
- package/dist/middleware/withCSRF.js.map +1 -0
- package/dist/middleware/withCors.d.ts +3 -0
- package/dist/middleware/withCors.d.ts.map +1 -0
- package/dist/middleware/withCors.js +41 -0
- package/dist/middleware/withCors.js.map +1 -0
- package/dist/middleware/withDefaultMiddleware.d.ts +3 -0
- package/dist/middleware/withDefaultMiddleware.d.ts.map +1 -0
- package/dist/middleware/withDefaultMiddleware.js +42 -0
- package/dist/middleware/withDefaultMiddleware.js.map +1 -0
- package/dist/middleware/withLogging.d.ts +3 -0
- package/dist/middleware/withLogging.d.ts.map +1 -0
- package/dist/middleware/withLogging.js +19 -0
- package/dist/middleware/withLogging.js.map +1 -0
- package/dist/middleware/withMCPHeader.d.ts +3 -0
- package/dist/middleware/withMCPHeader.d.ts.map +1 -0
- package/dist/middleware/withMCPHeader.js +17 -0
- package/dist/middleware/withMCPHeader.js.map +1 -0
- package/dist/middleware/withMiddleware.d.ts +5 -0
- package/dist/middleware/withMiddleware.d.ts.map +1 -0
- package/dist/middleware/withMiddleware.js +45 -0
- package/dist/middleware/withMiddleware.js.map +1 -0
- package/dist/middleware/withRateLimiting.d.ts +12 -0
- package/dist/middleware/withRateLimiting.d.ts.map +1 -0
- package/dist/middleware/withRateLimiting.js +131 -0
- package/dist/middleware/withRateLimiting.js.map +1 -0
- package/dist/middleware/withSecurity.d.ts +3 -0
- package/dist/middleware/withSecurity.d.ts.map +1 -0
- package/dist/middleware/withSecurity.js +25 -0
- package/dist/middleware/withSecurity.js.map +1 -0
- package/dist/middleware/withSession.d.ts +3 -0
- package/dist/middleware/withSession.d.ts.map +1 -0
- package/dist/middleware/withSession.js +16 -0
- package/dist/middleware/withSession.js.map +1 -0
- package/dist/utils/context.d.ts +6 -0
- package/dist/utils/context.d.ts.map +1 -0
- package/dist/utils/context.js +9 -0
- package/dist/utils/context.js.map +1 -0
- package/dist/utils/extract.ip.d.ts +3 -0
- package/dist/utils/extract.ip.d.ts.map +1 -0
- package/dist/utils/extract.ip.js +14 -0
- package/dist/utils/extract.ip.js.map +1 -0
- package/dist/utils/http.errors.d.ts +13 -0
- package/dist/utils/http.errors.d.ts.map +1 -0
- package/dist/utils/http.errors.js +48 -0
- package/dist/utils/http.errors.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +26 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/names.d.ts +6 -0
- package/dist/utils/names.d.ts.map +1 -0
- package/dist/utils/names.js +21 -0
- package/dist/utils/names.js.map +1 -0
- package/dist/utils/sanitize.table.key.d.ts +2 -0
- package/dist/utils/sanitize.table.key.d.ts.map +1 -0
- package/dist/utils/sanitize.table.key.js +17 -0
- package/dist/utils/sanitize.table.key.js.map +1 -0
- package/package.json +19 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
- **Added**
|
|
10
|
+
- (placeholder)
|
|
11
|
+
|
|
12
|
+
- **Changed**
|
|
13
|
+
- (placeholder)
|
|
14
|
+
|
|
15
|
+
- **Fixed**
|
|
16
|
+
- (placeholder)
|
|
17
|
+
|
|
18
|
+
- **Security**
|
|
19
|
+
- (placeholder)
|
|
20
|
+
|
|
21
|
+
## [1.0.6] - 2026-03-01
|
|
22
|
+
|
|
23
|
+
- **Added**
|
|
24
|
+
- Public middleware export surface via package root and `@plasius/api/middleware` subpath.
|
|
25
|
+
- Middleware export-surface tests for root and middleware barrel coverage.
|
|
26
|
+
|
|
27
|
+
- **Changed**
|
|
28
|
+
- Root package now re-exports middleware primitives (`withMiddleware`, `withCors`, `withRateLimiting`, etc.).
|
|
29
|
+
- `withRateLimiting` now lazily initializes Redis clients to avoid import-time side effects.
|
|
30
|
+
|
|
31
|
+
- **Fixed**
|
|
32
|
+
- Removed middleware import-time Redis connection attempts that could emit runtime errors in consumer environments.
|
|
33
|
+
|
|
34
|
+
- **Security**
|
|
35
|
+
- (placeholder)
|
|
36
|
+
|
|
37
|
+
## [1.0.5] - 2026-03-01
|
|
38
|
+
|
|
9
39
|
- **Added**
|
|
10
40
|
- (placeholder)
|
|
11
41
|
|
|
@@ -103,9 +133,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
103
133
|
|
|
104
134
|
- Initial public release scaffold for `@plasius/api`.
|
|
105
135
|
|
|
106
|
-
[Unreleased]: https://github.com/Plasius-LTD/api/compare/v1.0.
|
|
136
|
+
[Unreleased]: https://github.com/Plasius-LTD/api/compare/v1.0.6...HEAD
|
|
107
137
|
[1.0.0]: https://github.com/Plasius-LTD/api/releases/tag/v1.0.0
|
|
108
138
|
[1.0.1]: https://github.com/Plasius-LTD/api/releases/tag/v1.0.1
|
|
109
139
|
[1.0.2]: https://github.com/Plasius-LTD/api/releases/tag/v1.0.2
|
|
110
140
|
[1.0.3]: https://github.com/Plasius-LTD/api/releases/tag/v1.0.3
|
|
111
141
|
[1.0.4]: https://github.com/Plasius-LTD/api/releases/tag/v1.0.4
|
|
142
|
+
[1.0.5]: https://github.com/Plasius-LTD/api/releases/tag/v1.0.5
|
|
143
|
+
[1.0.6]: https://github.com/Plasius-LTD/api/releases/tag/v1.0.6
|
package/README.md
CHANGED
|
@@ -51,6 +51,7 @@ npm install @plasius/api
|
|
|
51
51
|
## Entrypoints
|
|
52
52
|
|
|
53
53
|
- Main module: `@plasius/api`
|
|
54
|
+
- Middleware module: `@plasius/api/middleware`
|
|
54
55
|
|
|
55
56
|
### Example
|
|
56
57
|
|
|
@@ -62,6 +63,10 @@ import {
|
|
|
62
63
|
} from "@plasius/api";
|
|
63
64
|
```
|
|
64
65
|
|
|
66
|
+
```ts
|
|
67
|
+
import { withCors, withRateLimiting, withMiddleware } from "@plasius/api/middleware";
|
|
68
|
+
```
|
|
69
|
+
|
|
65
70
|
## Local development
|
|
66
71
|
|
|
67
72
|
```bash
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { applyBaselineSecurityHeaders, isHttpsRequest, isInsecureLocalRequest, shouldEnforceHttps, } from "./middleware/transportSecurity.js";
|
|
2
|
+
export * from "./middleware/index.js";
|
|
2
3
|
export { decodeOAuthReturnToState, parseEncodedState, verifyState, } from "./utils/state.js";
|
|
3
4
|
export { generatePkceCodeChallenge, generatePkceCodeVerifier, generatePkceCookieId, getPkceCookieName, isValidPkceCodeVerifier, isValidPkceCookieId, } from "./utils/oauth-pkce.js";
|
|
4
5
|
export { DEFAULT_SESSION_COOKIE_NAME, createSessionCookie, ensureSession, getSessionIdFromRequest, } from "./utils/session.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,cAAc,EACd,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,cAAc,EACd,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mCAAmC,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AAEtC,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,aAAa,EACb,uBAAuB,GACxB,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
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.getSessionIdFromRequest = exports.ensureSession = exports.createSessionCookie = exports.DEFAULT_SESSION_COOKIE_NAME = exports.isValidPkceCookieId = exports.isValidPkceCodeVerifier = exports.getPkceCookieName = exports.generatePkceCookieId = exports.generatePkceCodeVerifier = exports.generatePkceCodeChallenge = exports.verifyState = exports.parseEncodedState = exports.decodeOAuthReturnToState = exports.shouldEnforceHttps = exports.isInsecureLocalRequest = exports.isHttpsRequest = exports.applyBaselineSecurityHeaders = void 0;
|
|
4
18
|
var transportSecurity_js_1 = require("./middleware/transportSecurity.js");
|
|
@@ -6,6 +20,7 @@ Object.defineProperty(exports, "applyBaselineSecurityHeaders", { enumerable: tru
|
|
|
6
20
|
Object.defineProperty(exports, "isHttpsRequest", { enumerable: true, get: function () { return transportSecurity_js_1.isHttpsRequest; } });
|
|
7
21
|
Object.defineProperty(exports, "isInsecureLocalRequest", { enumerable: true, get: function () { return transportSecurity_js_1.isInsecureLocalRequest; } });
|
|
8
22
|
Object.defineProperty(exports, "shouldEnforceHttps", { enumerable: true, get: function () { return transportSecurity_js_1.shouldEnforceHttps; } });
|
|
23
|
+
__exportStar(require("./middleware/index.js"), exports);
|
|
9
24
|
var state_js_1 = require("./utils/state.js");
|
|
10
25
|
Object.defineProperty(exports, "decodeOAuthReturnToState", { enumerable: true, get: function () { return state_js_1.decodeOAuthReturnToState; } });
|
|
11
26
|
Object.defineProperty(exports, "parseEncodedState", { enumerable: true, get: function () { return state_js_1.parseEncodedState; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,0EAK2C;AAJzC,oIAAA,4BAA4B,OAAA;AAC5B,sHAAA,cAAc,OAAA;AACd,8HAAA,sBAAsB,OAAA;AACtB,0HAAA,kBAAkB,OAAA;AAEpB,wDAAsC;AAEtC,6CAI0B;AAHxB,oHAAA,wBAAwB,OAAA;AACxB,6GAAA,iBAAiB,OAAA;AACjB,uGAAA,WAAW,OAAA;AAGb,uDAO+B;AAN7B,0HAAA,yBAAyB,OAAA;AACzB,yHAAA,wBAAwB,OAAA;AACxB,qHAAA,oBAAoB,OAAA;AACpB,kHAAA,iBAAiB,OAAA;AACjB,wHAAA,uBAAuB,OAAA;AACvB,oHAAA,mBAAmB,OAAA;AAGrB,iDAK4B;AAJ1B,yHAAA,2BAA2B,OAAA;AAC3B,iHAAA,mBAAmB,OAAA;AACnB,2GAAA,aAAa,OAAA;AACb,qHAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./withMiddleware.js";
|
|
2
|
+
export * from "./withMCPHeader.js";
|
|
3
|
+
export * from "./withCors.js";
|
|
4
|
+
export * from "./withRateLimiting.js";
|
|
5
|
+
export * from "./withLogging.js";
|
|
6
|
+
export * from "./withSession.js";
|
|
7
|
+
export * from "./withCSRF.js";
|
|
8
|
+
export * from "./withSecurity.js";
|
|
9
|
+
export * from "./withDefaultMiddleware.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./withMiddleware.js"), exports);
|
|
18
|
+
__exportStar(require("./withMCPHeader.js"), exports);
|
|
19
|
+
__exportStar(require("./withCors.js"), exports);
|
|
20
|
+
__exportStar(require("./withRateLimiting.js"), exports);
|
|
21
|
+
__exportStar(require("./withLogging.js"), exports);
|
|
22
|
+
__exportStar(require("./withSession.js"), exports);
|
|
23
|
+
__exportStar(require("./withCSRF.js"), exports);
|
|
24
|
+
__exportStar(require("./withSecurity.js"), exports);
|
|
25
|
+
__exportStar(require("./withDefaultMiddleware.js"), exports);
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC;AACpC,qDAAmC;AACnC,gDAA8B;AAC9B,wDAAsC;AACtC,mDAAiC;AACjC,mDAAiC;AACjC,gDAA8B;AAC9B,oDAAkC;AAClC,6DAA2C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCSRF.d.ts","sourceRoot":"","sources":["../../src/middleware/withCSRF.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAQnD,eAAO,MAAM,QAAQ,QAAO,UAoD3B,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withCSRF = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const index_js_1 = require("../utils/index.js");
|
|
7
|
+
const CSRF_HEADER_NAME = "x-csrf-token";
|
|
8
|
+
const CSRF_COOKIE_NAME = "csrf-token";
|
|
9
|
+
const withCSRF = () => {
|
|
10
|
+
return async (request, context) => {
|
|
11
|
+
const logger = context.extraInputs.get("logger");
|
|
12
|
+
const { headers, cookies } = (0, index_js_1.getExtraOutputs)(context);
|
|
13
|
+
const method = request.method?.toUpperCase();
|
|
14
|
+
const isReadOnly = method === "GET" || method === "HEAD" || method === "OPTIONS";
|
|
15
|
+
// Read token from header and cookie
|
|
16
|
+
const headerToken = request.headers?.get(CSRF_HEADER_NAME);
|
|
17
|
+
const cookieToken = (0, utils_1.getCookie)(request, CSRF_COOKIE_NAME);
|
|
18
|
+
// ✅ If GET and no CSRF cookie set, generate one
|
|
19
|
+
if (isReadOnly && !cookieToken) {
|
|
20
|
+
const newToken = (0, crypto_1.randomUUID)();
|
|
21
|
+
const newCookies = [
|
|
22
|
+
...cookies,
|
|
23
|
+
{
|
|
24
|
+
name: CSRF_COOKIE_NAME,
|
|
25
|
+
value: newToken,
|
|
26
|
+
secure: true,
|
|
27
|
+
sameSite: "None",
|
|
28
|
+
path: "/",
|
|
29
|
+
maxAge: 10 * 60, // 10 minutes
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
context.extraOutputs.set("cookies", newCookies);
|
|
33
|
+
logger.log("CSRF token set on GET request");
|
|
34
|
+
}
|
|
35
|
+
// Only validate CSRF token on non-readonly methods
|
|
36
|
+
if (!isReadOnly) {
|
|
37
|
+
if (!headerToken || !cookieToken || headerToken !== cookieToken) {
|
|
38
|
+
logger.warn("CSRF token validation failed.");
|
|
39
|
+
context.extraOutputs.set("http", {
|
|
40
|
+
status: 403,
|
|
41
|
+
headers,
|
|
42
|
+
cookies,
|
|
43
|
+
body: "Invalid CSRF token.",
|
|
44
|
+
});
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
exports.withCSRF = withCSRF;
|
|
52
|
+
//# sourceMappingURL=withCSRF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCSRF.js","sourceRoot":"","sources":["../../src/middleware/withCSRF.ts"],"names":[],"mappings":";;;AAEA,oCAAqC;AACrC,mCAAoC;AACpC,gDAAoD;AAEpD,MAAM,gBAAgB,GAAG,cAAc,CAAC;AACxC,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAE/B,MAAM,QAAQ,GAAG,GAAe,EAAE;IACvC,OAAO,KAAK,EAAE,OAAoB,EAAE,OAA0B,EAAE,EAAE;QAChE,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAI9C,CAAC;QAEF,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAA,0BAAe,EAAC,OAAO,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;QAC7C,MAAM,UAAU,GACd,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS,CAAC;QAEhE,oCAAoC;QACpC,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC3D,MAAM,WAAW,GAAG,IAAA,iBAAS,EAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;QAEzD,gDAAgD;QAChD,IAAI,UAAU,IAAI,CAAC,WAAW,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,IAAA,mBAAU,GAAE,CAAC;YAC9B,MAAM,UAAU,GAAG;gBACjB,GAAG,OAAO;gBACV;oBACE,IAAI,EAAE,gBAAgB;oBACtB,KAAK,EAAE,QAAQ;oBACf,MAAM,EAAE,IAAI;oBACZ,QAAQ,EAAE,MAAM;oBAChB,IAAI,EAAE,GAAG;oBACT,MAAM,EAAE,EAAE,GAAG,EAAE,EAAE,aAAa;iBAC/B;aACF,CAAC;YAEF,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;YAChD,MAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;QAC9C,CAAC;QAED,mDAAmD;QACnD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;gBAChE,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;gBAC7C,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE;oBAC/B,MAAM,EAAE,GAAG;oBACX,OAAO;oBACP,OAAO;oBACP,IAAI,EAAE,qBAAqB;iBAC5B,CAAC,CAAC;gBACH,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC,CAAC;AApDW,QAAA,QAAQ,YAoDnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCors.d.ts","sourceRoot":"","sources":["../../src/middleware/withCors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD,wBAAgB,QAAQ,CACtB,cAAc,GAAE,MAAM,EAAU,EAChC,cAAc,GAAE,MAAM,EAQrB,EACD,cAAc,GAAE,MAAM,EAAsC,GAC3D,UAAU,CA0CZ"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withCors = withCors;
|
|
4
|
+
const index_js_1 = require("../utils/index.js");
|
|
5
|
+
function withCors(allowedOrigins = ["*"], allowedMethods = [
|
|
6
|
+
"GET",
|
|
7
|
+
"POST",
|
|
8
|
+
"PUT",
|
|
9
|
+
"PATCH",
|
|
10
|
+
"DELETE",
|
|
11
|
+
"OPTIONS",
|
|
12
|
+
"HEAD",
|
|
13
|
+
], allowedHeaders = ["Content-Type", "Authorization"]) {
|
|
14
|
+
return async (req, context) => {
|
|
15
|
+
const logger = context.extraInputs.get("logger");
|
|
16
|
+
const { headers, cookies } = (0, index_js_1.getExtraOutputs)(context);
|
|
17
|
+
logger?.log(`[withCors] Executing middleware for ${req.method} ${req.url}`);
|
|
18
|
+
const origin = req.headers.get("origin") ?? "*";
|
|
19
|
+
const isOriginAllowed = allowedOrigins.includes("*") || allowedOrigins.includes(origin);
|
|
20
|
+
if (!isOriginAllowed) {
|
|
21
|
+
logger?.warn(`CORS blocked request from origin: ${origin}`);
|
|
22
|
+
}
|
|
23
|
+
headers.set("Access-Control-Allow-Origin", isOriginAllowed ? origin : "null");
|
|
24
|
+
headers.set("Access-Control-Allow-Methods", allowedMethods.join(", "));
|
|
25
|
+
headers.set("Access-Control-Allow-Headers", allowedHeaders.join(", "));
|
|
26
|
+
headers.set("Access-Control-Allow-Credentials", "true");
|
|
27
|
+
headers.set("Referrer-Policy", "origin-when-cross-origin");
|
|
28
|
+
context.extraOutputs.set("headers", headers);
|
|
29
|
+
if (req.method === "OPTIONS") {
|
|
30
|
+
logger?.log("CORS preflight request received. Returning early with 204.");
|
|
31
|
+
context.extraOutputs.set("http", {
|
|
32
|
+
status: 204,
|
|
33
|
+
headers,
|
|
34
|
+
cookies,
|
|
35
|
+
});
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=withCors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCors.js","sourceRoot":"","sources":["../../src/middleware/withCors.ts"],"names":[],"mappings":";;AAIA,4BAsDC;AAxDD,gDAAoD;AAEpD,SAAgB,QAAQ,CACtB,iBAA2B,CAAC,GAAG,CAAC,EAChC,iBAA2B;IACzB,KAAK;IACL,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,SAAS;IACT,MAAM;CACP,EACD,iBAA2B,CAAC,cAAc,EAAE,eAAe,CAAC;IAE5D,OAAO,KAAK,EAAE,GAAgB,EAAE,OAA0B,EAAE,EAAE;QAC5D,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAI9C,CAAC;QAEF,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAA,0BAAe,EAAC,OAAO,CAAC,CAAC;QACtD,MAAM,EAAE,GAAG,CAAC,uCAAuC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAE5E,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;QAChD,MAAM,eAAe,GACnB,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAElE,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,MAAM,EAAE,IAAI,CAAC,qCAAqC,MAAM,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,CAAC,GAAG,CACT,6BAA6B,EAC7B,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAClC,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,0BAA0B,CAAC,CAAC;QAE3D,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAE7C,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,EAAE,GAAG,CAAC,4DAA4D,CAAC,CAAC;YAC1E,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE;gBAC/B,MAAM,EAAE,GAAG;gBACX,OAAO;gBACP,OAAO;aACR,CAAC,CAAC;YACH,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withDefaultMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/withDefaultMiddleware.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAItD,wBAAgB,qBAAqB,IAAI,UAAU,EAAE,CAmCpD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// backend/src/middleware/defaultMiddleware.ts
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.withDefaultMiddleware = withDefaultMiddleware;
|
|
5
|
+
const withCors_1 = require("./withCors");
|
|
6
|
+
const withSecurity_1 = require("./withSecurity");
|
|
7
|
+
const withRateLimiting_1 = require("./withRateLimiting");
|
|
8
|
+
const withCSRF_1 = require("./withCSRF");
|
|
9
|
+
const withSession_1 = require("./withSession");
|
|
10
|
+
function withDefaultMiddleware() {
|
|
11
|
+
return [
|
|
12
|
+
(0, withCSRF_1.withCSRF)(),
|
|
13
|
+
(0, withSecurity_1.withSecurity)(),
|
|
14
|
+
(0, withCors_1.withCors)([
|
|
15
|
+
"*",
|
|
16
|
+
], ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], [
|
|
17
|
+
"Content-Type",
|
|
18
|
+
"Authorization",
|
|
19
|
+
"x-csrf-token",
|
|
20
|
+
"x-requested-with",
|
|
21
|
+
"Accept",
|
|
22
|
+
"Cookie",
|
|
23
|
+
"Set-Cookie",
|
|
24
|
+
"Origin",
|
|
25
|
+
"Referer",
|
|
26
|
+
"X-Forwarded-For",
|
|
27
|
+
"X-Real-IP",
|
|
28
|
+
"X-Session-Id",
|
|
29
|
+
"Cache-Control",
|
|
30
|
+
"Pragma",
|
|
31
|
+
"If-None-Match",
|
|
32
|
+
"ETag",
|
|
33
|
+
]),
|
|
34
|
+
(0, withRateLimiting_1.withRateLimiting)({
|
|
35
|
+
global: { limit: 1000, windowMs: 60 * 1000 }, // 1000 requests per minute
|
|
36
|
+
perUser: { limit: 10, windowMs: 60 * 1000 }, // 100 requests per user per minute
|
|
37
|
+
perApi: { limit: 500, windowMs: 60 * 1000 }, // 500 requests per API endpoint per minute
|
|
38
|
+
}),
|
|
39
|
+
withSession_1.withSession,
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=withDefaultMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withDefaultMiddleware.js","sourceRoot":"","sources":["../../src/middleware/withDefaultMiddleware.ts"],"names":[],"mappings":";AAAA,8CAA8C;;AAS9C,sDAmCC;AA1CD,yCAAsC;AACtC,iDAA8C;AAC9C,yDAAsD;AAEtD,yCAAsC;AACtC,+CAA4C;AAE5C,SAAgB,qBAAqB;IACnC,OAAO;QACL,IAAA,mBAAQ,GAAE;QACV,IAAA,2BAAY,GAAE;QACd,IAAA,mBAAQ,EACN;YACE,GAAG;SACJ,EACD,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,EACpD;YACE,cAAc;YACd,eAAe;YACf,cAAc;YACd,kBAAkB;YAClB,QAAQ;YACR,QAAQ;YACR,YAAY;YACZ,QAAQ;YACR,SAAS;YACT,iBAAiB;YACjB,WAAW;YACX,cAAc;YACd,eAAe;YACf,QAAQ;YACR,eAAe;YACf,MAAM;SACP,CACF;QACD,IAAA,mCAAgB,EAAC;YACf,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,2BAA2B;YACzE,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,mCAAmC;YAChF,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,2CAA2C;SACzF,CAAC;QACF,yBAAW;KACZ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withLogging.d.ts","sourceRoot":"","sources":["../../src/middleware/withLogging.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,eAAO,MAAM,WAAW,EAAE,UA6BzB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withLogging = void 0;
|
|
4
|
+
const withLogging = async (req, context) => {
|
|
5
|
+
const method = req.method;
|
|
6
|
+
const path = req.url;
|
|
7
|
+
const prefix = `${method} ${path} `;
|
|
8
|
+
function makeLogger(context) {
|
|
9
|
+
return {
|
|
10
|
+
log: (...args) => context.log(...args.map((arg) => (typeof arg === "string" ? prefix + arg : arg))),
|
|
11
|
+
warn: (...args) => context.warn(...args.map((arg) => (typeof arg === "string" ? prefix + arg : arg))),
|
|
12
|
+
error: (...args) => context.error(...args.map((arg) => (typeof arg === "string" ? prefix + arg : arg))),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
context.extraInputs.set("logger", makeLogger(context));
|
|
16
|
+
return true;
|
|
17
|
+
};
|
|
18
|
+
exports.withLogging = withLogging;
|
|
19
|
+
//# sourceMappingURL=withLogging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withLogging.js","sourceRoot":"","sources":["../../src/middleware/withLogging.ts"],"names":[],"mappings":";;;AAGO,MAAM,WAAW,GAAe,KAAK,EAC1C,GAAgB,EAChB,OAA0B,EAC1B,EAAE;IACF,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC1B,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC;IAErB,MAAM,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,GAAG,CAAC;IAEpC,SAAS,UAAU,CAAC,OAA0B;QAC5C,OAAO;YACL,GAAG,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE,CACtB,OAAO,CAAC,GAAG,CACT,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CACrE;YACH,IAAI,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE,CACvB,OAAO,CAAC,IAAI,CACV,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CACrE;YACH,KAAK,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE,CACxB,OAAO,CAAC,KAAK,CACX,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CACrE;SACJ,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AA7BW,QAAA,WAAW,eA6BtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withMCPHeader.d.ts","sourceRoot":"","sources":["../../src/middleware/withMCPHeader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,eAAO,MAAM,aAAa,EAAE,UAc3B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withMCPHeader = void 0;
|
|
4
|
+
const withMCPHeader = async (req, context) => {
|
|
5
|
+
const modelHeader = req.headers.get("x-mcp-model");
|
|
6
|
+
if (!modelHeader) {
|
|
7
|
+
context.extraOutputs.set("response", {
|
|
8
|
+
status: 400,
|
|
9
|
+
body: { error: "Missing x-mcp-model header" },
|
|
10
|
+
});
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
// Could add more validation or parsing here
|
|
14
|
+
return true;
|
|
15
|
+
};
|
|
16
|
+
exports.withMCPHeader = withMCPHeader;
|
|
17
|
+
//# sourceMappingURL=withMCPHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withMCPHeader.js","sourceRoot":"","sources":["../../src/middleware/withMCPHeader.ts"],"names":[],"mappings":";;;AAGO,MAAM,aAAa,GAAe,KAAK,EAC5C,GAAgB,EAChB,OAA0B,EAC1B,EAAE;IACF,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACnD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE;YACnC,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE;SAC9C,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;IACD,4CAA4C;IAC5C,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAdW,QAAA,aAAa,iBAcxB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
|
|
2
|
+
export type AzureFunction = (req: HttpRequest, context: InvocationContext) => Promise<HttpResponseInit>;
|
|
3
|
+
export type Middleware = (req: HttpRequest, context: InvocationContext) => Promise<boolean>;
|
|
4
|
+
export declare function withMiddleware(handler: AzureFunction, middlewares: Middleware[]): AzureFunction;
|
|
5
|
+
//# sourceMappingURL=withMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/withMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AASzF,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAE/B,MAAM,MAAM,UAAU,GAAG,CACvB,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,wBAAgB,cAAc,CAC5B,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,UAAU,EAAE,GACxB,aAAa,CAuDf"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withMiddleware = withMiddleware;
|
|
4
|
+
const withLogging_1 = require("./withLogging");
|
|
5
|
+
const index_js_1 = require("../utils/index.js");
|
|
6
|
+
const transportSecurity_js_1 = require("./transportSecurity.js");
|
|
7
|
+
function withMiddleware(handler, middlewares) {
|
|
8
|
+
return async function (req, context) {
|
|
9
|
+
context.extraInputs.set("fetchData", handler);
|
|
10
|
+
const start = Date.now();
|
|
11
|
+
const ip = (0, index_js_1.extractAndHashClientIp)(req);
|
|
12
|
+
const userAgent = req.headers.get("user-agent") ?? "unknown";
|
|
13
|
+
const method = req.method;
|
|
14
|
+
const path = req.url;
|
|
15
|
+
// Add additional logging context to all context.log/.warn/.error messages
|
|
16
|
+
await (0, withLogging_1.withLogging)(req, context);
|
|
17
|
+
const { headers, cookies } = (0, index_js_1.getExtraOutputs)(context);
|
|
18
|
+
(0, transportSecurity_js_1.applyBaselineSecurityHeaders)(headers);
|
|
19
|
+
context.extraOutputs.set("headers", headers);
|
|
20
|
+
if ((0, transportSecurity_js_1.shouldEnforceHttps)() &&
|
|
21
|
+
!(0, transportSecurity_js_1.isHttpsRequest)(req) &&
|
|
22
|
+
!(0, transportSecurity_js_1.isInsecureLocalRequest)(req)) {
|
|
23
|
+
context.log("request rejected: insecure transport in https-enforced mode");
|
|
24
|
+
return {
|
|
25
|
+
status: 426,
|
|
26
|
+
headers,
|
|
27
|
+
cookies,
|
|
28
|
+
body: "HTTPS is required.",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
for (const mw of middlewares) {
|
|
32
|
+
const continueProcessing = await mw(req, context);
|
|
33
|
+
if (!continueProcessing) {
|
|
34
|
+
// Middleware handled response or aborted
|
|
35
|
+
return context.extraOutputs.get("http");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const value = await handler(req, context);
|
|
39
|
+
const end = Date.now();
|
|
40
|
+
const duration = end - start;
|
|
41
|
+
context.log(`Handled ${method} ${path} | IP: ${ip} | Agent: ${userAgent} | Duration: ${duration}ms`);
|
|
42
|
+
return value;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=withMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withMiddleware.js","sourceRoot":"","sources":["../../src/middleware/withMiddleware.ts"],"names":[],"mappings":";;AAmBA,wCA0DC;AA5ED,+CAA4C;AAC5C,gDAA4E;AAC5E,iEAKgC;AAWhC,SAAgB,cAAc,CAC5B,OAAsB,EACtB,WAAyB;IAEzB,OAAO,KAAK,WACV,GAAgB,EAChB,OAA0B;QAE1B,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAE9C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,MAAM,EAAE,GAAG,IAAA,iCAAsB,EAAC,GAAG,CAAC,CAAC;QACvC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,SAAS,CAAC;QAC7D,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAC1B,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC;QAErB,0EAA0E;QAC1E,MAAM,IAAA,yBAAW,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEhC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAA,0BAAe,EAAC,OAAO,CAAC,CAAC;QACtD,IAAA,mDAA4B,EAAC,OAAO,CAAC,CAAC;QACtC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAE7C,IACE,IAAA,yCAAkB,GAAE;YACpB,CAAC,IAAA,qCAAc,EAAC,GAAG,CAAC;YACpB,CAAC,IAAA,6CAAsB,EAAC,GAAG,CAAC,EAC5B,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;YAC3E,OAAO;gBACL,MAAM,EAAE,GAAG;gBACX,OAAO;gBACP,OAAO;gBACP,IAAI,EAAE,oBAAoB;aAC3B,CAAC;QACJ,CAAC;QAED,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;YAC7B,MAAM,kBAAkB,GAAG,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAClD,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACxB,yCAAyC;gBAEzC,OAAO,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAqB,CAAC;YAC9D,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAE1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC;QAE7B,OAAO,CAAC,GAAG,CACT,WAAW,MAAM,IAAI,IAAI,UAAU,EAAE,aAAa,SAAS,gBAAgB,QAAQ,IAAI,CACxF,CAAC;QAEF,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Middleware } from "./withMiddleware.js";
|
|
2
|
+
export interface RateLimitConfig {
|
|
3
|
+
limit: number;
|
|
4
|
+
windowMs: number;
|
|
5
|
+
}
|
|
6
|
+
export interface ApiRateLimiterConfig {
|
|
7
|
+
global?: RateLimitConfig;
|
|
8
|
+
perUser?: RateLimitConfig;
|
|
9
|
+
perApi?: RateLimitConfig;
|
|
10
|
+
}
|
|
11
|
+
export declare function withRateLimiting(config: ApiRateLimiterConfig): Middleware;
|
|
12
|
+
//# sourceMappingURL=withRateLimiting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withRateLimiting.d.ts","sourceRoot":"","sources":["../../src/middleware/withRateLimiting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGjD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAuFD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,GAAG,UAAU,CA+EzE"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.withRateLimiting = withRateLimiting;
|
|
7
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
8
|
+
const redisUrl = process.env.REDIS_URL?.trim();
|
|
9
|
+
const redisHost = process.env.REDIS_HOST?.trim();
|
|
10
|
+
const redisEnabled = (process.env.REDIS_ENABLED ??
|
|
11
|
+
((redisUrl || redisHost) ? "true" : "false")).toLowerCase() === "true";
|
|
12
|
+
let redisClient;
|
|
13
|
+
function getRedisClient() {
|
|
14
|
+
if (!redisEnabled) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
if (redisClient !== undefined) {
|
|
18
|
+
return redisClient;
|
|
19
|
+
}
|
|
20
|
+
redisClient = redisUrl
|
|
21
|
+
? new ioredis_1.default(redisUrl, { lazyConnect: true })
|
|
22
|
+
: new ioredis_1.default({
|
|
23
|
+
host: redisHost ?? "redis",
|
|
24
|
+
port: Number(process.env.REDIS_PORT ?? 6379),
|
|
25
|
+
password: process.env.REDIS_PASSWORD,
|
|
26
|
+
lazyConnect: true,
|
|
27
|
+
});
|
|
28
|
+
return redisClient;
|
|
29
|
+
}
|
|
30
|
+
async function checkRateLimit(key, config, context) {
|
|
31
|
+
const logger = context.extraInputs.get("logger");
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
const windowKey = `${key}:${Math.floor(now / config.windowMs)}`;
|
|
34
|
+
const redis = getRedisClient();
|
|
35
|
+
if (!redis) {
|
|
36
|
+
logger?.log(`Rate limiting bypassed for ${key} (Redis disabled)`);
|
|
37
|
+
return {
|
|
38
|
+
allowed: true,
|
|
39
|
+
remaining: config.limit,
|
|
40
|
+
reset: Math.ceil((now + config.windowMs) / 1000),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const count = await redis.incr(windowKey);
|
|
45
|
+
if (count === 1) {
|
|
46
|
+
await redis.pexpire(windowKey, config.windowMs);
|
|
47
|
+
}
|
|
48
|
+
const ttl = await redis.pttl(windowKey);
|
|
49
|
+
const retryAfter = count > config.limit ? Math.ceil(ttl / 1000) : undefined;
|
|
50
|
+
const remaining = Math.max(config.limit - count, 0);
|
|
51
|
+
const reset = Math.ceil((now + ttl) / 1000); // Unix timestamp when reset will happen
|
|
52
|
+
if (count > config.limit) {
|
|
53
|
+
logger?.warn(`Rate limit exceeded for ${key}. Retry after ${retryAfter}s.`);
|
|
54
|
+
return { allowed: false, remaining: 0, retryAfter, reset };
|
|
55
|
+
}
|
|
56
|
+
return { allowed: true, remaining, reset };
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
logger?.warn(`Rate limit backend unavailable for ${key}; allowing request.`);
|
|
60
|
+
logger?.warn(error);
|
|
61
|
+
return {
|
|
62
|
+
allowed: true,
|
|
63
|
+
remaining: config.limit,
|
|
64
|
+
reset: Math.ceil((now + config.windowMs) / 1000),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function withRateLimiting(config) {
|
|
69
|
+
return async (req, context) => {
|
|
70
|
+
const path = new URL(req.url).pathname;
|
|
71
|
+
// ----- GLOBAL -----
|
|
72
|
+
if (config.global) {
|
|
73
|
+
const result = await checkRateLimit("rate:global", config.global, context);
|
|
74
|
+
if (!result.allowed) {
|
|
75
|
+
context.extraOutputs.set("http", {
|
|
76
|
+
status: 429,
|
|
77
|
+
body: "Server is busy (global limit). Please retry later.",
|
|
78
|
+
headers: {
|
|
79
|
+
"Retry-After": result.retryAfter?.toString(),
|
|
80
|
+
"X-RateLimit-Limit": config.global.limit.toString(),
|
|
81
|
+
"X-RateLimit-Remaining": result.remaining.toString(),
|
|
82
|
+
"X-RateLimit-Reset": result.reset.toString(),
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ----- PER USER -----
|
|
89
|
+
if (config.perUser) {
|
|
90
|
+
const userId = req.headers.get("x-user-id") ||
|
|
91
|
+
req.headers.get("authorization") ||
|
|
92
|
+
req.headers.get("x-forwarded-for") ||
|
|
93
|
+
"anonymous";
|
|
94
|
+
const result = await checkRateLimit(`rate:user:${userId}`, config.perUser, context);
|
|
95
|
+
if (!result.allowed) {
|
|
96
|
+
context.extraOutputs.set("http", {
|
|
97
|
+
status: 429,
|
|
98
|
+
body: "You are sending requests too fast (user limit). Please retry later.",
|
|
99
|
+
headers: {
|
|
100
|
+
"Retry-After": result.retryAfter?.toString(),
|
|
101
|
+
"X-RateLimit-Limit": config.perUser.limit.toString(),
|
|
102
|
+
"X-RateLimit-Remaining": result.remaining.toString(),
|
|
103
|
+
"X-RateLimit-Reset": result.reset.toString(),
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ----- PER API -----
|
|
110
|
+
if (config.perApi) {
|
|
111
|
+
const apiKey = req.method + ":" + path;
|
|
112
|
+
const result = await checkRateLimit(`rate:api:${apiKey}`, config.perApi, context);
|
|
113
|
+
if (!result.allowed) {
|
|
114
|
+
context.extraOutputs.set("http", {
|
|
115
|
+
status: 429,
|
|
116
|
+
body: "This API is receiving too many requests. Please retry later.",
|
|
117
|
+
headers: {
|
|
118
|
+
"Retry-After": result.retryAfter?.toString(),
|
|
119
|
+
"X-RateLimit-Limit": config.perApi.limit.toString(),
|
|
120
|
+
"X-RateLimit-Remaining": result.remaining.toString(),
|
|
121
|
+
"X-RateLimit-Reset": result.reset.toString(),
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// All passed
|
|
128
|
+
return true;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=withRateLimiting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withRateLimiting.js","sourceRoot":"","sources":["../../src/middleware/withRateLimiting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withSecurity.d.ts","sourceRoot":"","sources":["../../src/middleware/withSecurity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAQnD,wBAAgB,YAAY,IAAI,UAAU,CAwBzC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withSecurity = withSecurity;
|
|
4
|
+
const index_js_1 = require("../utils/index.js");
|
|
5
|
+
const transportSecurity_js_1 = require("./transportSecurity.js");
|
|
6
|
+
function withSecurity() {
|
|
7
|
+
return async (request, context) => {
|
|
8
|
+
const { headers, cookies } = (0, index_js_1.getExtraOutputs)(context);
|
|
9
|
+
(0, transportSecurity_js_1.applyBaselineSecurityHeaders)(headers);
|
|
10
|
+
context.extraOutputs.set("headers", headers);
|
|
11
|
+
if ((0, transportSecurity_js_1.shouldEnforceHttps)() &&
|
|
12
|
+
!(0, transportSecurity_js_1.isHttpsRequest)(request) &&
|
|
13
|
+
!(0, transportSecurity_js_1.isInsecureLocalRequest)(request)) {
|
|
14
|
+
context.extraOutputs.set("http", {
|
|
15
|
+
status: 426,
|
|
16
|
+
headers,
|
|
17
|
+
cookies,
|
|
18
|
+
body: "HTTPS is required.",
|
|
19
|
+
});
|
|
20
|
+
return Promise.resolve(false);
|
|
21
|
+
}
|
|
22
|
+
return Promise.resolve(true);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=withSecurity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withSecurity.js","sourceRoot":"","sources":["../../src/middleware/withSecurity.ts"],"names":[],"mappings":";;AASA,oCAwBC;AA/BD,gDAAoD;AACpD,iEAKgC;AAChC,SAAgB,YAAY;IAC1B,OAAO,KAAK,EAAE,OAAoB,EAAE,OAA0B,EAAE,EAAE;QAChE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAA,0BAAe,EAAC,OAAO,CAAC,CAAC;QAEtD,IAAA,mDAA4B,EAAC,OAAO,CAAC,CAAC;QAEtC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAE7C,IACE,IAAA,yCAAkB,GAAE;YACpB,CAAC,IAAA,qCAAc,EAAC,OAAO,CAAC;YACxB,CAAC,IAAA,6CAAsB,EAAC,OAAO,CAAC,EAChC,CAAC;YACD,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE;gBAC/B,MAAM,EAAE,GAAG;gBACX,OAAO;gBACP,OAAO;gBACP,IAAI,EAAE,oBAAoB;aAC3B,CAAC,CAAC;YACH,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withSession.d.ts","sourceRoot":"","sources":["../../src/middleware/withSession.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAIjD,eAAO,MAAM,WAAW,EAAE,UAezB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withSession = void 0;
|
|
4
|
+
const index_js_1 = require("../utils/index.js");
|
|
5
|
+
const withSession = async (req, context) => {
|
|
6
|
+
const { cookies } = (0, index_js_1.getExtraOutputs)(context);
|
|
7
|
+
const session = (0, index_js_1.ensureSession)(req);
|
|
8
|
+
if (session.isNew && session.cookie) {
|
|
9
|
+
const newCookies = [...cookies, session.cookie];
|
|
10
|
+
context.extraOutputs.set("cookies", newCookies);
|
|
11
|
+
}
|
|
12
|
+
context.extraInputs.set("sessionId", session.sessionId);
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
15
|
+
exports.withSession = withSession;
|
|
16
|
+
//# sourceMappingURL=withSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withSession.js","sourceRoot":"","sources":["../../src/middleware/withSession.ts"],"names":[],"mappings":";;;AAGA,gDAAmE;AAE5D,MAAM,WAAW,GAAe,KAAK,EAC1C,GAAgB,EAChB,OAA0B,EAC1B,EAAE;IACF,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,0BAAe,EAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAA,wBAAa,EAAC,GAAG,CAAC,CAAC;IAEnC,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,CAAC,GAAG,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAChD,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAExD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAfW,QAAA,WAAW,eAetB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/utils/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAKA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getExtraOutputs = getExtraOutputs;
|
|
4
|
+
function getExtraOutputs(context) {
|
|
5
|
+
const headers = context.extraOutputs.get("headers") || new Headers();
|
|
6
|
+
const cookies = context.extraOutputs.get("cookies") || [];
|
|
7
|
+
return { headers, cookies };
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/utils/context.ts"],"names":[],"mappings":";;AAEA,0CAQC;AARD,SAAgB,eAAe,CAAC,OAA0B;IAIxD,MAAM,OAAO,GACV,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAa,IAAI,IAAI,OAAO,EAAE,CAAC;IACpE,MAAM,OAAO,GAAI,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAc,IAAI,EAAE,CAAC;IACxE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.ip.d.ts","sourceRoot":"","sources":["../../src/utils/extract.ip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAM/C,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAQ/D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractAndHashClientIp = extractAndHashClientIp;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const HMAC_SECRET = process.env.HMAC_SECRET || "OuYDwS9zpItZ9d84mIuZ+rzU6c9abFkzDWzXAPk4elg="; // Replace for production
|
|
6
|
+
function extractAndHashClientIp(req) {
|
|
7
|
+
const rawIp = req.headers.get("x-forwarded-for")?.split(",")[0].trim() ||
|
|
8
|
+
req.headers.get("x-client-ip")?.trim() ||
|
|
9
|
+
req.headers.get("host")?.trim() ||
|
|
10
|
+
"unknown";
|
|
11
|
+
const ip = (0, crypto_1.createHmac)("sha256", HMAC_SECRET).update(rawIp).digest("hex");
|
|
12
|
+
return ip;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=extract.ip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.ip.js","sourceRoot":"","sources":["../../src/utils/extract.ip.ts"],"names":[],"mappings":";;AAMA,wDAQC;AAbD,mCAAoC;AAEpC,MAAM,WAAW,GACf,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,8CAA8C,CAAC,CAAC,yBAAyB;AAEtG,SAAgB,sBAAsB,CAAC,GAAgB;IACrD,MAAM,KAAK,GACT,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;QACxD,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE;QACtC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE;QAC/B,SAAS,CAAC;IACZ,MAAM,EAAE,GAAG,IAAA,mBAAU,EAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzE,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HttpResponseInit } from "@azure/functions";
|
|
2
|
+
export declare const badRequestResponse: HttpResponseInit;
|
|
3
|
+
export declare const unauthorizedResponse: HttpResponseInit;
|
|
4
|
+
export declare const forbiddenResponse: HttpResponseInit;
|
|
5
|
+
export declare const notFoundResponse: HttpResponseInit;
|
|
6
|
+
export declare const requestTimeoutResponse: HttpResponseInit;
|
|
7
|
+
export declare const tooManyRequestsResponse: HttpResponseInit;
|
|
8
|
+
export declare const internalServerErrorResponse: HttpResponseInit;
|
|
9
|
+
export declare const notImplementedResponse: HttpResponseInit;
|
|
10
|
+
export declare const badGatewayResponse: HttpResponseInit;
|
|
11
|
+
export declare const serviceUnavailableResponse: HttpResponseInit;
|
|
12
|
+
export declare const gatewayTimeoutResponse: HttpResponseInit;
|
|
13
|
+
//# sourceMappingURL=http.errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.errors.d.ts","sourceRoot":"","sources":["../../src/utils/http.errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAEnD,eAAO,MAAM,kBAAkB,EAAE,gBAGhC,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,gBAGlC,CAAA;AAED,eAAO,MAAM,iBAAiB,EAAE,gBAG/B,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,gBAG9B,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAE,gBAGpC,CAAA;AAED,eAAO,MAAM,uBAAuB,EAAE,gBAGrC,CAAA;AAED,eAAO,MAAM,2BAA2B,EAAE,gBAGzC,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAE,gBAGpC,CAAA;AAED,eAAO,MAAM,kBAAkB,EAAE,gBAGhC,CAAA;AAED,eAAO,MAAM,0BAA0B,EAAE,gBAGxC,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAE,gBAGpC,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gatewayTimeoutResponse = exports.serviceUnavailableResponse = exports.badGatewayResponse = exports.notImplementedResponse = exports.internalServerErrorResponse = exports.tooManyRequestsResponse = exports.requestTimeoutResponse = exports.notFoundResponse = exports.forbiddenResponse = exports.unauthorizedResponse = exports.badRequestResponse = void 0;
|
|
4
|
+
exports.badRequestResponse = {
|
|
5
|
+
status: 400,
|
|
6
|
+
body: JSON.stringify({ error: 'Bad Request' }),
|
|
7
|
+
};
|
|
8
|
+
exports.unauthorizedResponse = {
|
|
9
|
+
status: 401,
|
|
10
|
+
body: JSON.stringify({ error: 'Unauthorized' }),
|
|
11
|
+
};
|
|
12
|
+
exports.forbiddenResponse = {
|
|
13
|
+
status: 403,
|
|
14
|
+
body: JSON.stringify({ error: 'Forbidden' }),
|
|
15
|
+
};
|
|
16
|
+
exports.notFoundResponse = {
|
|
17
|
+
status: 404,
|
|
18
|
+
body: JSON.stringify({ error: 'Not Found' }),
|
|
19
|
+
};
|
|
20
|
+
exports.requestTimeoutResponse = {
|
|
21
|
+
status: 408,
|
|
22
|
+
body: JSON.stringify({ error: 'Request Timeout' }),
|
|
23
|
+
};
|
|
24
|
+
exports.tooManyRequestsResponse = {
|
|
25
|
+
status: 429,
|
|
26
|
+
body: JSON.stringify({ error: 'Too Many Requests' }),
|
|
27
|
+
};
|
|
28
|
+
exports.internalServerErrorResponse = {
|
|
29
|
+
status: 500,
|
|
30
|
+
body: JSON.stringify({ error: 'Internal Server Error' }),
|
|
31
|
+
};
|
|
32
|
+
exports.notImplementedResponse = {
|
|
33
|
+
status: 501,
|
|
34
|
+
body: JSON.stringify({ error: 'Not Implemented' }),
|
|
35
|
+
};
|
|
36
|
+
exports.badGatewayResponse = {
|
|
37
|
+
status: 502,
|
|
38
|
+
body: JSON.stringify({ error: 'Bad Gateway' }),
|
|
39
|
+
};
|
|
40
|
+
exports.serviceUnavailableResponse = {
|
|
41
|
+
status: 503,
|
|
42
|
+
body: JSON.stringify({ error: 'Service Unavailable' }),
|
|
43
|
+
};
|
|
44
|
+
exports.gatewayTimeoutResponse = {
|
|
45
|
+
status: 504,
|
|
46
|
+
body: JSON.stringify({ error: 'Gateway Timeout' }),
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=http.errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.errors.js","sourceRoot":"","sources":["../../src/utils/http.errors.ts"],"names":[],"mappings":";;;AAEa,QAAA,kBAAkB,GAAqB;IAChD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;CACjD,CAAA;AAEY,QAAA,oBAAoB,GAAqB;IAClD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;CAClD,CAAA;AAEY,QAAA,iBAAiB,GAAqB;IAC/C,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;CAC/C,CAAA;AAEY,QAAA,gBAAgB,GAAqB;IAC9C,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;CAC/C,CAAA;AAEY,QAAA,sBAAsB,GAAqB;IACpD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;CACrD,CAAA;AAEY,QAAA,uBAAuB,GAAqB;IACrD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;CACvD,CAAA;AAEY,QAAA,2BAA2B,GAAqB;IACzD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;CAC3D,CAAA;AAEY,QAAA,sBAAsB,GAAqB;IACpD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;CACrD,CAAA;AAEY,QAAA,kBAAkB,GAAqB;IAChD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;CACjD,CAAA;AAEY,QAAA,0BAA0B,GAAqB;IACxD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;CACzD,CAAA;AAEY,QAAA,sBAAsB,GAAqB;IACpD,MAAM,EAAE,GAAG;IACX,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;CACrD,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./cookies.js";
|
|
2
|
+
export * from "./state.js";
|
|
3
|
+
export * from "./http.errors.js";
|
|
4
|
+
export * from "./extract.ip.js";
|
|
5
|
+
export * from "./names.js";
|
|
6
|
+
export * from "./context.js";
|
|
7
|
+
export * from "./sanitize.table.key.js";
|
|
8
|
+
export * from "./oauth-pkce.js";
|
|
9
|
+
export * from "./session.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./cookies.js"), exports);
|
|
18
|
+
__exportStar(require("./state.js"), exports);
|
|
19
|
+
__exportStar(require("./http.errors.js"), exports);
|
|
20
|
+
__exportStar(require("./extract.ip.js"), exports);
|
|
21
|
+
__exportStar(require("./names.js"), exports);
|
|
22
|
+
__exportStar(require("./context.js"), exports);
|
|
23
|
+
__exportStar(require("./sanitize.table.key.js"), exports);
|
|
24
|
+
__exportStar(require("./oauth-pkce.js"), exports);
|
|
25
|
+
__exportStar(require("./session.js"), exports);
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,6CAA2B;AAC3B,mDAAiC;AACjC,kDAAgC;AAChC,6CAA2B;AAC3B,+CAA6B;AAC7B,0DAAwC;AACxC,kDAAgC;AAChC,+CAA6B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../src/utils/names.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.splitDisplayName = splitDisplayName;
|
|
4
|
+
function splitDisplayName(displayName) {
|
|
5
|
+
const parts = displayName.trim().split(/\s+/);
|
|
6
|
+
if (parts.length === 0) {
|
|
7
|
+
return { firstName: "", middleName: "", lastName: "" };
|
|
8
|
+
}
|
|
9
|
+
if (parts.length === 1) {
|
|
10
|
+
return { firstName: parts[0], middleName: "", lastName: "" };
|
|
11
|
+
}
|
|
12
|
+
if (parts.length === 2) {
|
|
13
|
+
return { firstName: parts[0], middleName: "", lastName: parts[1] };
|
|
14
|
+
}
|
|
15
|
+
// 3 or more parts
|
|
16
|
+
const firstName = parts[0];
|
|
17
|
+
const lastName = parts[parts.length - 1];
|
|
18
|
+
const middleName = parts.slice(1, parts.length - 1).join(" ");
|
|
19
|
+
return { firstName, middleName, lastName };
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.js","sourceRoot":"","sources":["../../src/utils/names.ts"],"names":[],"mappings":";;AAAA,4CAyBC;AAzBD,SAAgB,gBAAgB,CAAC,WAAmB;IAKlD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE9C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACzD,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC/D,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,CAAC;IAED,kBAAkB;IAClB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE9D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.table.key.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize.table.key.ts"],"names":[],"mappings":"AAAA,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWjE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeUrlForPartitionKey = sanitizeUrlForPartitionKey;
|
|
4
|
+
function sanitizeUrlForPartitionKey(rawUrl) {
|
|
5
|
+
try {
|
|
6
|
+
const { hostname } = new URL(rawUrl);
|
|
7
|
+
const sanitized = hostname
|
|
8
|
+
.toLowerCase()
|
|
9
|
+
.replace(/[^a-z0-9]/g, "-") // convert all non-alphanumeric characters to hyphens
|
|
10
|
+
.replace(/^-+|-+$/g, ""); // remove leading/trailing hyphens
|
|
11
|
+
return sanitized;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw new Error(`Invalid URL passed for sanitization: "${rawUrl}"`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=sanitize.table.key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.table.key.js","sourceRoot":"","sources":["../../src/utils/sanitize.table.key.ts"],"names":[],"mappings":";;AAAA,gEAWC;AAXD,SAAgB,0BAA0B,CAAC,MAAc;IACvD,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,QAAQ;aACvB,WAAW,EAAE;aACb,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,qDAAqD;aAChF,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,kCAAkC;QAC9D,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,GAAG,CAAC,CAAC;IACtE,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plasius/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Generic public API security and middleware helpers.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,6 +21,14 @@
|
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"default": "./dist/index.js"
|
|
23
23
|
},
|
|
24
|
+
"./middleware": {
|
|
25
|
+
"types": "./dist/middleware/index.d.ts",
|
|
26
|
+
"default": "./dist/middleware/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./middleware/*": {
|
|
29
|
+
"types": "./dist/middleware/*.d.ts",
|
|
30
|
+
"default": "./dist/middleware/*.js"
|
|
31
|
+
},
|
|
24
32
|
"./package.json": "./package.json"
|
|
25
33
|
},
|
|
26
34
|
"scripts": {
|
|
@@ -32,8 +40,13 @@
|
|
|
32
40
|
"dev": "func start --javascript --host 0.0.0.0 --port 7071 --cors '*' --cors-credentials",
|
|
33
41
|
"test": "vitest run",
|
|
34
42
|
"test:watch": "vitest",
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
35
44
|
"test:coverage": "vitest run --coverage",
|
|
36
|
-
"
|
|
45
|
+
"audit:eslint": "eslint . --max-warnings=0",
|
|
46
|
+
"audit:deps": "npm ls --all --omit=optional --omit=peer > /dev/null 2>&1 || true",
|
|
47
|
+
"audit:npm": "npm audit --audit-level=high --omit=dev",
|
|
48
|
+
"audit:test": "vitest run --coverage",
|
|
49
|
+
"lint": "eslint . --max-warnings=0",
|
|
37
50
|
"pack:check": "node scripts/verify-public-package.cjs",
|
|
38
51
|
"prepublishOnly": "npm run build && npm run pack:check",
|
|
39
52
|
"prepare": "npm run build"
|
|
@@ -56,9 +69,11 @@
|
|
|
56
69
|
},
|
|
57
70
|
"homepage": "https://github.com/Plasius-LTD/api#readme",
|
|
58
71
|
"dependencies": {
|
|
59
|
-
"@azure/functions": "^4.0.0"
|
|
72
|
+
"@azure/functions": "^4.0.0",
|
|
73
|
+
"ioredis": "^5.8.2"
|
|
60
74
|
},
|
|
61
75
|
"devDependencies": {
|
|
76
|
+
"@eslint/js": "^10.0.1",
|
|
62
77
|
"@types/jsonwebtoken": "^9.0.10",
|
|
63
78
|
"@types/node": "^24.3.1",
|
|
64
79
|
"@typescript-eslint/eslint-plugin": "^8.56.0",
|
|
@@ -66,6 +81,7 @@
|
|
|
66
81
|
"@vitest/coverage-v8": "^4.0.18",
|
|
67
82
|
"azure-functions-core-tools": "^2.0.0",
|
|
68
83
|
"eslint": "^10.0.1",
|
|
84
|
+
"globals": "^17.3.0",
|
|
69
85
|
"rimraf": "^6.0.1",
|
|
70
86
|
"tsx": "^4.20.5",
|
|
71
87
|
"typescript": "^5.9.2",
|