@qelos/integrator-express 4.0.1 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cookies.d.ts +19 -0
- package/dist/cookies.js +43 -0
- package/dist/cookies.js.map +1 -0
- package/dist/index.d.ts +29 -2
- package/dist/index.js +34 -5
- package/dist/index.js.map +1 -1
- package/dist/middleware.d.ts +4 -8
- package/dist/middleware.js +64 -101
- package/dist/middleware.js.map +1 -1
- package/dist/proxy-target.d.ts +17 -0
- package/dist/proxy-target.js +29 -0
- package/dist/proxy-target.js.map +1 -0
- package/dist/proxy.d.ts +16 -0
- package/dist/proxy.js +132 -0
- package/dist/proxy.js.map +1 -0
- package/dist/sdk-factory.d.ts +3 -11
- package/dist/sdk-factory.js +13 -77
- package/dist/sdk-factory.js.map +1 -1
- package/dist/social-auth.d.ts +6 -5
- package/dist/social-auth.js +13 -6
- package/dist/social-auth.js.map +1 -1
- package/dist/types.d.ts +45 -11
- package/package.json +3 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rewrite the `Domain=` attribute of a single `Set-Cookie` header value.
|
|
3
|
+
*
|
|
4
|
+
* - If the cookie contains a `Domain=<value>` attribute (case-insensitive), its
|
|
5
|
+
* value is replaced with `newDomain`, with any trailing `:port` suffix
|
|
6
|
+
* stripped first (cookie `Domain` attributes do not include a port).
|
|
7
|
+
* - If `newDomain` is `undefined` (or empty), the entire `; Domain=<value>`
|
|
8
|
+
* segment is removed so the browser scopes the cookie to the current host.
|
|
9
|
+
* - If no `Domain=` attribute is present, the input is returned unchanged.
|
|
10
|
+
*
|
|
11
|
+
* All other attributes, their casing/order and the original cookie name/value
|
|
12
|
+
* bytes are preserved.
|
|
13
|
+
*/
|
|
14
|
+
export declare function rewriteSetCookieDomain(setCookie: string, newDomain: string | undefined): string;
|
|
15
|
+
/**
|
|
16
|
+
* Apply {@link rewriteSetCookieDomain} to each entry of a `Set-Cookie` array
|
|
17
|
+
* (e.g. the result of `Headers.getSetCookie()`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function rewriteSetCookieDomains(values: string[], newDomain: string | undefined): string[];
|
package/dist/cookies.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rewriteSetCookieDomain = rewriteSetCookieDomain;
|
|
4
|
+
exports.rewriteSetCookieDomains = rewriteSetCookieDomains;
|
|
5
|
+
/**
|
|
6
|
+
* Rewrite the `Domain=` attribute of a single `Set-Cookie` header value.
|
|
7
|
+
*
|
|
8
|
+
* - If the cookie contains a `Domain=<value>` attribute (case-insensitive), its
|
|
9
|
+
* value is replaced with `newDomain`, with any trailing `:port` suffix
|
|
10
|
+
* stripped first (cookie `Domain` attributes do not include a port).
|
|
11
|
+
* - If `newDomain` is `undefined` (or empty), the entire `; Domain=<value>`
|
|
12
|
+
* segment is removed so the browser scopes the cookie to the current host.
|
|
13
|
+
* - If no `Domain=` attribute is present, the input is returned unchanged.
|
|
14
|
+
*
|
|
15
|
+
* All other attributes, their casing/order and the original cookie name/value
|
|
16
|
+
* bytes are preserved.
|
|
17
|
+
*/
|
|
18
|
+
function rewriteSetCookieDomain(setCookie, newDomain) {
|
|
19
|
+
const domainSegment = /;\s*Domain\s*=\s*[^;]+/i;
|
|
20
|
+
if (!domainSegment.test(setCookie))
|
|
21
|
+
return setCookie;
|
|
22
|
+
const stripped = newDomain ? stripPort(newDomain) : '';
|
|
23
|
+
if (!stripped) {
|
|
24
|
+
return setCookie.replace(domainSegment, '');
|
|
25
|
+
}
|
|
26
|
+
return setCookie.replace(/(;\s*Domain\s*=\s*)[^;]+/i, `$1${stripped}`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Apply {@link rewriteSetCookieDomain} to each entry of a `Set-Cookie` array
|
|
30
|
+
* (e.g. the result of `Headers.getSetCookie()`).
|
|
31
|
+
*/
|
|
32
|
+
function rewriteSetCookieDomains(values, newDomain) {
|
|
33
|
+
return values.map((value) => rewriteSetCookieDomain(value, newDomain));
|
|
34
|
+
}
|
|
35
|
+
function stripPort(host) {
|
|
36
|
+
if (host.startsWith('[')) {
|
|
37
|
+
const end = host.indexOf(']');
|
|
38
|
+
return end === -1 ? host : host.slice(1, end);
|
|
39
|
+
}
|
|
40
|
+
const colon = host.indexOf(':');
|
|
41
|
+
return colon === -1 ? host : host.slice(0, colon);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=cookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookies.js","sourceRoot":"","sources":["../src/cookies.ts"],"names":[],"mappings":";;AAaA,wDAeC;AAMD,0DAKC;AAvCD;;;;;;;;;;;;GAYG;AACH,SAAgB,sBAAsB,CACpC,SAAiB,EACjB,SAA6B;IAE7B,MAAM,aAAa,GAAG,yBAAyB,CAAC;IAChD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAErD,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,SAAS,CAAC,OAAO,CACtB,2BAA2B,EAC3B,KAAK,QAAQ,EAAE,CAChB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,uBAAuB,CACrC,MAAgB,EAChB,SAA6B;IAE7B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACpD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
|
+
import type { RequestHandler } from 'express';
|
|
2
|
+
import { type CreateMiddlewareOptions } from './middleware';
|
|
1
3
|
export { createQelosMiddleware, requireUser, } from './middleware';
|
|
2
4
|
export type { CreateMiddlewareOptions, QelosMiddleware, } from './middleware';
|
|
5
|
+
export { createQelosProxy } from './proxy';
|
|
6
|
+
export type { CreateProxyOptions, QelosProxyHandler } from './proxy';
|
|
3
7
|
export { createRequestSdk } from './sdk-factory';
|
|
4
8
|
export type { CreateSdkParams } from './sdk-factory';
|
|
5
|
-
export
|
|
6
|
-
export {
|
|
9
|
+
export { rewriteSetCookieDomain, rewriteSetCookieDomains } from './cookies';
|
|
10
|
+
export { resolveQelosProxyTarget } from './proxy-target';
|
|
11
|
+
export type { QelosExpressConfig, QelosRequestContext, } from './types';
|
|
12
|
+
export { completeSocialAuthCallback, getSocialAuthSetCookieParts, parseSocialCallbackRefreshToken, type SocialAuthCallbackPayload, type SocialCallbackInput, } from './social-auth';
|
|
13
|
+
export interface QelosIntegrator {
|
|
14
|
+
/**
|
|
15
|
+
* User-resolution middleware. Forwards inbound cookies to `/api/me` and
|
|
16
|
+
* exposes `req.qelos.user` / `req.qelos.workspace` / `req.qelos.workspaces`
|
|
17
|
+
* / `req.qelos.sdk`.
|
|
18
|
+
*/
|
|
19
|
+
middleware: RequestHandler;
|
|
20
|
+
/**
|
|
21
|
+
* Catch-all reverse-proxy handler for `/api/**`. Mount it AFTER your own
|
|
22
|
+
* `/api/*` routes so user-defined endpoints still take precedence. Returns
|
|
23
|
+
* `null` when `config.disableProxy === true`.
|
|
24
|
+
*/
|
|
25
|
+
proxy: RequestHandler | null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build both the user-resolution middleware and the `/api/**` reverse proxy
|
|
29
|
+
* from a single config. When the proxy is enabled (the default), `/api/` is
|
|
30
|
+
* auto-prepended to `skipPaths` so the middleware doesn't shadow the proxy
|
|
31
|
+
* by running its own `/api/me` probe on every proxied request.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createQelosIntegrator(options: CreateMiddlewareOptions): QelosIntegrator;
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseSocialCallbackRefreshToken = exports.getSocialAuthSetCookieParts = exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
exports.parseSocialCallbackRefreshToken = exports.getSocialAuthSetCookieParts = exports.completeSocialAuthCallback = exports.resolveQelosProxyTarget = exports.rewriteSetCookieDomains = exports.rewriteSetCookieDomain = exports.createRequestSdk = exports.createQelosProxy = exports.requireUser = exports.createQelosMiddleware = void 0;
|
|
4
|
+
exports.createQelosIntegrator = createQelosIntegrator;
|
|
5
|
+
const middleware_1 = require("./middleware");
|
|
6
|
+
const proxy_1 = require("./proxy");
|
|
7
|
+
var middleware_2 = require("./middleware");
|
|
8
|
+
Object.defineProperty(exports, "createQelosMiddleware", { enumerable: true, get: function () { return middleware_2.createQelosMiddleware; } });
|
|
9
|
+
Object.defineProperty(exports, "requireUser", { enumerable: true, get: function () { return middleware_2.requireUser; } });
|
|
10
|
+
var proxy_2 = require("./proxy");
|
|
11
|
+
Object.defineProperty(exports, "createQelosProxy", { enumerable: true, get: function () { return proxy_2.createQelosProxy; } });
|
|
7
12
|
var sdk_factory_1 = require("./sdk-factory");
|
|
8
13
|
Object.defineProperty(exports, "createRequestSdk", { enumerable: true, get: function () { return sdk_factory_1.createRequestSdk; } });
|
|
14
|
+
var cookies_1 = require("./cookies");
|
|
15
|
+
Object.defineProperty(exports, "rewriteSetCookieDomain", { enumerable: true, get: function () { return cookies_1.rewriteSetCookieDomain; } });
|
|
16
|
+
Object.defineProperty(exports, "rewriteSetCookieDomains", { enumerable: true, get: function () { return cookies_1.rewriteSetCookieDomains; } });
|
|
17
|
+
var proxy_target_1 = require("./proxy-target");
|
|
18
|
+
Object.defineProperty(exports, "resolveQelosProxyTarget", { enumerable: true, get: function () { return proxy_target_1.resolveQelosProxyTarget; } });
|
|
9
19
|
var social_auth_1 = require("./social-auth");
|
|
10
20
|
Object.defineProperty(exports, "completeSocialAuthCallback", { enumerable: true, get: function () { return social_auth_1.completeSocialAuthCallback; } });
|
|
11
|
-
Object.defineProperty(exports, "applySocialAuthCookiesToServerResponse", { enumerable: true, get: function () { return social_auth_1.applySocialAuthCookiesToServerResponse; } });
|
|
12
21
|
Object.defineProperty(exports, "getSocialAuthSetCookieParts", { enumerable: true, get: function () { return social_auth_1.getSocialAuthSetCookieParts; } });
|
|
13
22
|
Object.defineProperty(exports, "parseSocialCallbackRefreshToken", { enumerable: true, get: function () { return social_auth_1.parseSocialCallbackRefreshToken; } });
|
|
23
|
+
/**
|
|
24
|
+
* Build both the user-resolution middleware and the `/api/**` reverse proxy
|
|
25
|
+
* from a single config. When the proxy is enabled (the default), `/api/` is
|
|
26
|
+
* auto-prepended to `skipPaths` so the middleware doesn't shadow the proxy
|
|
27
|
+
* by running its own `/api/me` probe on every proxied request.
|
|
28
|
+
*/
|
|
29
|
+
function createQelosIntegrator(options) {
|
|
30
|
+
const proxyEnabled = options.config.disableProxy !== true;
|
|
31
|
+
let config = options.config;
|
|
32
|
+
if (proxyEnabled) {
|
|
33
|
+
const existingSkipPaths = options.config.skipPaths ?? [];
|
|
34
|
+
const alreadyCovered = existingSkipPaths.some((prefix) => '/api/'.startsWith(prefix));
|
|
35
|
+
if (!alreadyCovered) {
|
|
36
|
+
config = { ...options.config, skipPaths: ['/api/', ...existingSkipPaths] };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const middleware = (0, middleware_1.createQelosMiddleware)({ ...options, config });
|
|
40
|
+
const proxy = proxyEnabled ? (0, proxy_1.createQelosProxy)({ config }) : null;
|
|
41
|
+
return { middleware, proxy };
|
|
42
|
+
}
|
|
14
43
|
//# sourceMappingURL=index.js.map
|
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":";;;AAyDA,sDAkBC;AA1ED,6CAAmF;AACnF,mCAA2C;AAG3C,2CAGsB;AAFpB,mHAAA,qBAAqB,OAAA;AACrB,yGAAA,WAAW,OAAA;AAOb,iCAA2C;AAAlC,yGAAA,gBAAgB,OAAA;AAGzB,6CAAiD;AAAxC,+GAAA,gBAAgB,OAAA;AAGzB,qCAA4E;AAAnE,iHAAA,sBAAsB,OAAA;AAAE,kHAAA,uBAAuB,OAAA;AACxD,+CAAyD;AAAhD,uHAAA,uBAAuB,OAAA;AAOhC,6CAMuB;AALrB,yHAAA,0BAA0B,OAAA;AAC1B,0HAAA,2BAA2B,OAAA;AAC3B,8HAAA,+BAA+B,OAAA;AAoBjC;;;;;GAKG;AACH,SAAgB,qBAAqB,CACnC,OAAgC;IAEhC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,KAAK,IAAI,CAAC;IAE1D,IAAI,MAAM,GAAuB,OAAO,CAAC,MAAM,CAAC;IAChD,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QACzD,MAAM,cAAc,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QACtF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,OAAO,EAAE,GAAG,iBAAiB,CAAC,EAAE,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAA,kCAAqB,EAAC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,IAAA,wBAAgB,EAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEjE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC"}
|
package/dist/middleware.d.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import type { Request, RequestHandler } from 'express';
|
|
2
2
|
import type { IUser } from '@qelos/sdk/dist/authentication';
|
|
3
3
|
import type { IWorkspace } from '@qelos/sdk/workspaces';
|
|
4
|
-
import type { QelosExpressConfig
|
|
4
|
+
import type { QelosExpressConfig } from './types';
|
|
5
5
|
export interface CreateMiddlewareOptions {
|
|
6
6
|
config: QelosExpressConfig;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
onTokenRefresh?: TokenRefreshHook;
|
|
12
|
-
/**
|
|
13
|
-
* Resolve the active workspace for a request. Defaults to picking the first
|
|
14
|
-
* workspace returned from `sdk.workspaces.getList()`.
|
|
8
|
+
* Resolve the active workspace for a request. Defaults to whatever
|
|
9
|
+
* `/api/me` reports on `user.workspace` (the user's currently activated
|
|
10
|
+
* workspace, or `null` when none is active).
|
|
15
11
|
*/
|
|
16
12
|
resolveWorkspace?: (params: {
|
|
17
13
|
req: Request;
|
package/dist/middleware.js
CHANGED
|
@@ -2,56 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createQelosMiddleware = createQelosMiddleware;
|
|
4
4
|
exports.requireUser = requireUser;
|
|
5
|
+
const cookies_1 = require("./cookies");
|
|
6
|
+
const proxy_target_1 = require("./proxy-target");
|
|
5
7
|
const sdk_factory_1 = require("./sdk-factory");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (parsed && typeof parsed[name] === 'string') {
|
|
12
|
-
return parsed[name];
|
|
13
|
-
}
|
|
14
|
-
const header = req.headers.cookie;
|
|
15
|
-
if (!header)
|
|
16
|
-
return undefined;
|
|
17
|
-
const prefix = name + '=';
|
|
18
|
-
for (const part of header.split(';')) {
|
|
19
|
-
const trimmed = part.trim();
|
|
20
|
-
if (trimmed.startsWith(prefix)) {
|
|
21
|
-
try {
|
|
22
|
-
return decodeURIComponent(trimmed.slice(prefix.length));
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
return trimmed.slice(prefix.length);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
function readTokens(req, config) {
|
|
32
|
-
const accessCookie = config.accessTokenCookie || DEFAULT_ACCESS_COOKIE;
|
|
33
|
-
const refreshCookie = config.refreshTokenCookie || DEFAULT_REFRESH_COOKIE;
|
|
34
|
-
const cookieAccess = readCookie(req, accessCookie);
|
|
35
|
-
const cookieRefresh = readCookie(req, refreshCookie);
|
|
36
|
-
const authHeader = req.headers.authorization;
|
|
37
|
-
const headerAccess = authHeader && authHeader.toLowerCase().startsWith('bearer ')
|
|
38
|
-
? authHeader.slice(7).trim()
|
|
39
|
-
: undefined;
|
|
40
|
-
return {
|
|
41
|
-
accessToken: headerAccess || cookieAccess || undefined,
|
|
42
|
-
refreshToken: cookieRefresh || undefined,
|
|
43
|
-
};
|
|
8
|
+
function shouldSkip(req, config) {
|
|
9
|
+
if (!config.skipPaths?.length)
|
|
10
|
+
return false;
|
|
11
|
+
const path = req.path || req.url || '';
|
|
12
|
+
return config.skipPaths.some((prefix) => path.startsWith(prefix));
|
|
44
13
|
}
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
`${name}=${encodeURIComponent(value)}`,
|
|
48
|
-
'Path=/',
|
|
49
|
-
'HttpOnly',
|
|
50
|
-
'SameSite=Lax',
|
|
51
|
-
];
|
|
52
|
-
if (secure)
|
|
53
|
-
parts.push('Secure');
|
|
54
|
-
return parts.join('; ');
|
|
14
|
+
function buildMeUrl(base) {
|
|
15
|
+
return `${base.replace(/\/+$/, '')}/api/me`;
|
|
55
16
|
}
|
|
56
17
|
function appendSetCookie(res, value) {
|
|
57
18
|
const existing = res.getHeader('set-cookie');
|
|
@@ -65,58 +26,24 @@ function appendSetCookie(res, value) {
|
|
|
65
26
|
res.setHeader('set-cookie', [value]);
|
|
66
27
|
}
|
|
67
28
|
}
|
|
68
|
-
function writeTokensToCookies(res, config, tokens) {
|
|
69
|
-
const accessCookie = config.accessTokenCookie || DEFAULT_ACCESS_COOKIE;
|
|
70
|
-
const refreshCookie = config.refreshTokenCookie || DEFAULT_REFRESH_COOKIE;
|
|
71
|
-
const secure = !/^http:\/\//i.test(config.appUrl);
|
|
72
|
-
const cookieRes = res;
|
|
73
|
-
if (typeof cookieRes.cookie === 'function') {
|
|
74
|
-
const cookieOptions = {
|
|
75
|
-
httpOnly: true,
|
|
76
|
-
secure,
|
|
77
|
-
sameSite: 'lax',
|
|
78
|
-
path: '/',
|
|
79
|
-
};
|
|
80
|
-
cookieRes.cookie(accessCookie, tokens.accessToken, cookieOptions);
|
|
81
|
-
if (tokens.refreshToken) {
|
|
82
|
-
cookieRes.cookie(refreshCookie, tokens.refreshToken, cookieOptions);
|
|
83
|
-
}
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
appendSetCookie(res, serializeCookie(accessCookie, tokens.accessToken, secure));
|
|
87
|
-
if (tokens.refreshToken) {
|
|
88
|
-
appendSetCookie(res, serializeCookie(refreshCookie, tokens.refreshToken, secure));
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function shouldSkip(req, config) {
|
|
92
|
-
if (!config.skipPaths?.length)
|
|
93
|
-
return false;
|
|
94
|
-
const path = req.path || req.url || '';
|
|
95
|
-
return config.skipPaths.some((prefix) => path.startsWith(prefix));
|
|
96
|
-
}
|
|
97
29
|
function createQelosMiddleware(options) {
|
|
98
30
|
const { config, resolveWorkspace } = options;
|
|
99
|
-
const
|
|
100
|
-
(async ({ res, newTokens }) => {
|
|
101
|
-
writeTokensToCookies(res, config, newTokens);
|
|
102
|
-
});
|
|
31
|
+
const sdkFetch = (config.sdkOptions?.fetch ?? globalThis.fetch);
|
|
103
32
|
return async function qelosMiddleware(req, res, next) {
|
|
104
33
|
if (shouldSkip(req, config)) {
|
|
105
34
|
next();
|
|
106
35
|
return;
|
|
107
36
|
}
|
|
108
|
-
const
|
|
109
|
-
const sdk = (0, sdk_factory_1.createRequestSdk)({ config, tokens, req, res, onTokenRefresh });
|
|
37
|
+
const sdk = (0, sdk_factory_1.createRequestSdk)({ config, req });
|
|
110
38
|
const ctx = {
|
|
111
39
|
user: null,
|
|
112
40
|
workspace: null,
|
|
113
41
|
workspaces: [],
|
|
114
42
|
sdk,
|
|
115
|
-
tokens,
|
|
116
43
|
};
|
|
117
44
|
req.qelos = ctx;
|
|
118
|
-
const
|
|
119
|
-
if (!
|
|
45
|
+
const base = (0, proxy_target_1.resolveQelosProxyTarget)(config);
|
|
46
|
+
if (!base && !config.apiToken) {
|
|
120
47
|
if (config.requireAuth) {
|
|
121
48
|
res.status(401).json({ code: 'UNAUTHORIZED' });
|
|
122
49
|
return;
|
|
@@ -124,10 +51,44 @@ function createQelosMiddleware(options) {
|
|
|
124
51
|
next();
|
|
125
52
|
return;
|
|
126
53
|
}
|
|
127
|
-
|
|
128
|
-
|
|
54
|
+
if (base) {
|
|
55
|
+
const headers = {};
|
|
56
|
+
if (req.headers.cookie)
|
|
57
|
+
headers.cookie = req.headers.cookie;
|
|
58
|
+
if (req.headers.authorization) {
|
|
59
|
+
headers.authorization = req.headers.authorization;
|
|
60
|
+
}
|
|
61
|
+
const originalHost = req.headers.host;
|
|
62
|
+
let upstream;
|
|
63
|
+
try {
|
|
64
|
+
upstream = await sdkFetch(buildMeUrl(base), {
|
|
65
|
+
method: 'GET',
|
|
66
|
+
headers,
|
|
67
|
+
redirect: 'manual',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
if (config.requireAuth) {
|
|
72
|
+
res.status(401).json({ code: 'UNAUTHORIZED' });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
next();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const setCookieValues = upstream.headers.getSetCookie?.() ?? [];
|
|
79
|
+
for (const value of setCookieValues) {
|
|
80
|
+
appendSetCookie(res, (0, cookies_1.rewriteSetCookieDomain)(value, originalHost));
|
|
81
|
+
}
|
|
82
|
+
if (upstream.ok) {
|
|
83
|
+
try {
|
|
84
|
+
ctx.user = (await upstream.json());
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
ctx.user = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
129
90
|
}
|
|
130
|
-
|
|
91
|
+
if (!ctx.user) {
|
|
131
92
|
if (config.requireAuth) {
|
|
132
93
|
res.status(401).json({ code: 'UNAUTHORIZED' });
|
|
133
94
|
return;
|
|
@@ -141,18 +102,20 @@ function createQelosMiddleware(options) {
|
|
|
141
102
|
catch {
|
|
142
103
|
ctx.workspaces = [];
|
|
143
104
|
}
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
105
|
+
if (resolveWorkspace) {
|
|
106
|
+
ctx.workspace =
|
|
107
|
+
(await resolveWorkspace({
|
|
108
|
+
req,
|
|
109
|
+
user: ctx.user,
|
|
110
|
+
workspaces: ctx.workspaces,
|
|
111
|
+
})) || null;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// `/api/me` carries `user.workspace` (`{ _id, name, roles }`) only when
|
|
115
|
+
// the user has activated a workspace. Null means the frontend must
|
|
116
|
+
// prompt to activate/create one — don't silently pick workspaces[0].
|
|
117
|
+
ctx.workspace =
|
|
118
|
+
ctx.user.workspace || null;
|
|
156
119
|
}
|
|
157
120
|
next();
|
|
158
121
|
};
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { QelosExpressConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the origin to which `/api/**` requests are proxied. The managed
|
|
4
|
+
* Qelos app URL (`config.appUrl`) is the proxy target — env vars are only
|
|
5
|
+
* dev-time overrides when the configured `appUrl` is not reachable from
|
|
6
|
+
* the local host.
|
|
7
|
+
*
|
|
8
|
+
* Priority (highest first):
|
|
9
|
+
* 1. `process.env.QELOS_PROXY_TARGET`
|
|
10
|
+
* 2. `process.env.QELOS_IP`
|
|
11
|
+
* 3. `process.env.QELOS_API_IP`
|
|
12
|
+
* 4. `config.appUrl`
|
|
13
|
+
*
|
|
14
|
+
* Empty / whitespace-only values are skipped, and `undefined` is returned when
|
|
15
|
+
* nothing is configured so the caller can surface a clear error.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveQelosProxyTarget(config: QelosExpressConfig): string | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveQelosProxyTarget = resolveQelosProxyTarget;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the origin to which `/api/**` requests are proxied. The managed
|
|
6
|
+
* Qelos app URL (`config.appUrl`) is the proxy target — env vars are only
|
|
7
|
+
* dev-time overrides when the configured `appUrl` is not reachable from
|
|
8
|
+
* the local host.
|
|
9
|
+
*
|
|
10
|
+
* Priority (highest first):
|
|
11
|
+
* 1. `process.env.QELOS_PROXY_TARGET`
|
|
12
|
+
* 2. `process.env.QELOS_IP`
|
|
13
|
+
* 3. `process.env.QELOS_API_IP`
|
|
14
|
+
* 4. `config.appUrl`
|
|
15
|
+
*
|
|
16
|
+
* Empty / whitespace-only values are skipped, and `undefined` is returned when
|
|
17
|
+
* nothing is configured so the caller can surface a clear error.
|
|
18
|
+
*/
|
|
19
|
+
function resolveQelosProxyTarget(config) {
|
|
20
|
+
const env = process.env;
|
|
21
|
+
const fromEnv = env.QELOS_PROXY_TARGET?.trim() ||
|
|
22
|
+
env.QELOS_IP?.trim() ||
|
|
23
|
+
env.QELOS_API_IP?.trim();
|
|
24
|
+
if (fromEnv)
|
|
25
|
+
return fromEnv;
|
|
26
|
+
const fromAppUrl = config.appUrl?.trim();
|
|
27
|
+
return fromAppUrl || undefined;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=proxy-target.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-target.js","sourceRoot":"","sources":["../src/proxy-target.ts"],"names":[],"mappings":";;AAiBA,0DAYC;AA3BD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,uBAAuB,CACrC,MAA0B;IAE1B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,MAAM,OAAO,GACX,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE;QAC9B,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE;QACpB,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IACzC,OAAO,UAAU,IAAI,SAAS,CAAC;AACjC,CAAC"}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RequestHandler } from 'express';
|
|
2
|
+
import type { QelosExpressConfig } from './types';
|
|
3
|
+
export interface CreateProxyOptions {
|
|
4
|
+
config: QelosExpressConfig;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Catch-all `/api/**` reverse proxy. Forwards the inbound request to the
|
|
8
|
+
* configured Qelos origin, streaming bodies in both directions and rewriting
|
|
9
|
+
* the `Domain=` attribute of every upstream `Set-Cookie` header to the
|
|
10
|
+
* inbound request's host so the cookie becomes first-party.
|
|
11
|
+
*
|
|
12
|
+
* Responds with `503` when no proxy target is configured. Does not proxy
|
|
13
|
+
* WebSocket upgrades.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createQelosProxy(options: CreateProxyOptions): RequestHandler;
|
|
16
|
+
export type QelosProxyHandler = ReturnType<typeof createQelosProxy>;
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.createQelosProxy = createQelosProxy;
|
|
27
|
+
const http = __importStar(require("node:http"));
|
|
28
|
+
const https = __importStar(require("node:https"));
|
|
29
|
+
const node_url_1 = require("node:url");
|
|
30
|
+
const cookies_1 = require("./cookies");
|
|
31
|
+
const proxy_target_1 = require("./proxy-target");
|
|
32
|
+
const HOP_BY_HOP = new Set([
|
|
33
|
+
'connection',
|
|
34
|
+
'keep-alive',
|
|
35
|
+
'proxy-authenticate',
|
|
36
|
+
'proxy-authorization',
|
|
37
|
+
'te',
|
|
38
|
+
'trailer',
|
|
39
|
+
'transfer-encoding',
|
|
40
|
+
'upgrade',
|
|
41
|
+
'host',
|
|
42
|
+
'content-length',
|
|
43
|
+
]);
|
|
44
|
+
function buildForwardedHeaders(source, targetHost) {
|
|
45
|
+
const out = {};
|
|
46
|
+
for (const [name, value] of Object.entries(source)) {
|
|
47
|
+
if (value === undefined)
|
|
48
|
+
continue;
|
|
49
|
+
if (HOP_BY_HOP.has(name.toLowerCase()))
|
|
50
|
+
continue;
|
|
51
|
+
out[name] = value;
|
|
52
|
+
}
|
|
53
|
+
out['host'] = targetHost;
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Catch-all `/api/**` reverse proxy. Forwards the inbound request to the
|
|
58
|
+
* configured Qelos origin, streaming bodies in both directions and rewriting
|
|
59
|
+
* the `Domain=` attribute of every upstream `Set-Cookie` header to the
|
|
60
|
+
* inbound request's host so the cookie becomes first-party.
|
|
61
|
+
*
|
|
62
|
+
* Responds with `503` when no proxy target is configured. Does not proxy
|
|
63
|
+
* WebSocket upgrades.
|
|
64
|
+
*/
|
|
65
|
+
function createQelosProxy(options) {
|
|
66
|
+
const { config } = options;
|
|
67
|
+
return function qelosApiProxy(req, res) {
|
|
68
|
+
const base = (0, proxy_target_1.resolveQelosProxyTarget)(config);
|
|
69
|
+
if (!base) {
|
|
70
|
+
res.status(503).json({
|
|
71
|
+
code: 'QELOS_PROXY_NOT_CONFIGURED',
|
|
72
|
+
message: '[@qelos/integrator-express] Qelos API proxy is not configured. ' +
|
|
73
|
+
'Set config.appUrl (or QELOS_PROXY_TARGET / QELOS_IP / QELOS_API_IP in development).',
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
let target;
|
|
78
|
+
try {
|
|
79
|
+
const baseUrl = new node_url_1.URL(base);
|
|
80
|
+
target = new node_url_1.URL(req.originalUrl || req.url, baseUrl);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
res.status(502).json({
|
|
84
|
+
code: 'QELOS_PROXY_BAD_TARGET',
|
|
85
|
+
message: '[@qelos/integrator-express] Invalid proxy target URL.',
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const client = target.protocol === 'https:' ? https : http;
|
|
90
|
+
const originalHost = req.headers.host;
|
|
91
|
+
const forwardedHeaders = buildForwardedHeaders(req.headers, target.host);
|
|
92
|
+
const upstreamReq = client.request({
|
|
93
|
+
protocol: target.protocol,
|
|
94
|
+
hostname: target.hostname,
|
|
95
|
+
port: target.port || (target.protocol === 'https:' ? 443 : 80),
|
|
96
|
+
method: req.method,
|
|
97
|
+
path: target.pathname + target.search,
|
|
98
|
+
headers: forwardedHeaders,
|
|
99
|
+
}, (upstreamRes) => {
|
|
100
|
+
const status = upstreamRes.statusCode ?? 502;
|
|
101
|
+
for (const [name, value] of Object.entries(upstreamRes.headers)) {
|
|
102
|
+
if (value === undefined)
|
|
103
|
+
continue;
|
|
104
|
+
const lower = name.toLowerCase();
|
|
105
|
+
if (HOP_BY_HOP.has(lower))
|
|
106
|
+
continue;
|
|
107
|
+
if (lower === 'set-cookie') {
|
|
108
|
+
const values = Array.isArray(value) ? value : [value];
|
|
109
|
+
res.setHeader('set-cookie', values.map((v) => (0, cookies_1.rewriteSetCookieDomain)(v, originalHost)));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
res.setHeader(name, value);
|
|
113
|
+
}
|
|
114
|
+
res.status(status);
|
|
115
|
+
upstreamRes.pipe(res);
|
|
116
|
+
});
|
|
117
|
+
upstreamReq.on('error', (err) => {
|
|
118
|
+
if (!res.headersSent) {
|
|
119
|
+
res.status(502).json({
|
|
120
|
+
code: 'QELOS_PROXY_UPSTREAM_ERROR',
|
|
121
|
+
message: err.message,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
res.end();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
req.on('aborted', () => upstreamReq.destroy());
|
|
129
|
+
req.pipe(upstreamReq);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/sdk-factory.d.ts
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
import type { Request
|
|
1
|
+
import type { Request } from 'express';
|
|
2
2
|
import QelosSDK from '@qelos/sdk';
|
|
3
|
-
import type { QelosExpressConfig
|
|
3
|
+
import type { QelosExpressConfig } from './types';
|
|
4
4
|
export interface CreateSdkParams {
|
|
5
5
|
config: QelosExpressConfig;
|
|
6
|
-
/**
|
|
7
|
-
* Tokens for the current request. The factory mutates this object in place
|
|
8
|
-
* when a token refresh occurs, so callers can read the latest pair after
|
|
9
|
-
* the SDK has been used.
|
|
10
|
-
*/
|
|
11
|
-
tokens: QelosTokenPair;
|
|
12
6
|
req: Request;
|
|
13
|
-
res: Response;
|
|
14
|
-
onTokenRefresh?: TokenRefreshHook;
|
|
15
7
|
}
|
|
16
|
-
export declare function createRequestSdk({ config,
|
|
8
|
+
export declare function createRequestSdk({ config, req }: CreateSdkParams): QelosSDK;
|
package/dist/sdk-factory.js
CHANGED
|
@@ -5,93 +5,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createRequestSdk = createRequestSdk;
|
|
7
7
|
const sdk_1 = __importDefault(require("@qelos/sdk"));
|
|
8
|
-
|
|
9
|
-
'/api/token/refresh',
|
|
10
|
-
'/api/cookie/refresh',
|
|
11
|
-
'/api/signin',
|
|
12
|
-
'/api/signup',
|
|
13
|
-
]);
|
|
14
|
-
function createRequestSdk({ config, tokens, req, res, onTokenRefresh, }) {
|
|
15
|
-
let sdk;
|
|
16
|
-
let refreshInFlight = null;
|
|
8
|
+
function createRequestSdk({ config, req }) {
|
|
17
9
|
const baseOptions = config.sdkOptions || {};
|
|
18
|
-
async function performRefresh() {
|
|
19
|
-
if (!tokens.refreshToken && !tokens.accessToken) {
|
|
20
|
-
throw new Error('no refresh token available');
|
|
21
|
-
}
|
|
22
|
-
const previous = {
|
|
23
|
-
accessToken: tokens.accessToken,
|
|
24
|
-
refreshToken: tokens.refreshToken,
|
|
25
|
-
};
|
|
26
|
-
let refreshed;
|
|
27
|
-
if (tokens.refreshToken) {
|
|
28
|
-
const result = await sdk.authentication.refreshToken(tokens.refreshToken);
|
|
29
|
-
refreshed = {
|
|
30
|
-
accessToken: result.payload.token,
|
|
31
|
-
refreshToken: result.payload.refreshToken,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
const result = await sdk.authentication.refreshCookieToken(tokens.accessToken);
|
|
36
|
-
refreshed = {
|
|
37
|
-
accessToken: result.payload.cookieToken,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
tokens.accessToken = refreshed.accessToken;
|
|
41
|
-
tokens.refreshToken = refreshed.refreshToken;
|
|
42
|
-
if (onTokenRefresh) {
|
|
43
|
-
await onTokenRefresh({
|
|
44
|
-
req,
|
|
45
|
-
res,
|
|
46
|
-
oldTokens: previous,
|
|
47
|
-
newTokens: refreshed,
|
|
48
|
-
sdk,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function ensureRefresh() {
|
|
53
|
-
if (!refreshInFlight) {
|
|
54
|
-
refreshInFlight = performRefresh().finally(() => {
|
|
55
|
-
refreshInFlight = null;
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
return refreshInFlight;
|
|
59
|
-
}
|
|
60
10
|
const options = {
|
|
61
11
|
appUrl: config.appUrl,
|
|
62
12
|
fetch: globalThis.fetch,
|
|
63
|
-
forceRefresh: !config.apiToken,
|
|
64
13
|
...baseOptions,
|
|
65
14
|
};
|
|
66
15
|
if (config.apiToken) {
|
|
67
16
|
options.apiToken = config.apiToken;
|
|
17
|
+
return new sdk_1.default(options);
|
|
68
18
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
19
|
+
options.extraHeaders = async () => {
|
|
20
|
+
const headers = {};
|
|
21
|
+
const cookieHeader = req.headers.cookie;
|
|
22
|
+
if (cookieHeader) {
|
|
23
|
+
headers.cookie = cookieHeader;
|
|
72
24
|
}
|
|
73
|
-
|
|
74
|
-
|
|
25
|
+
const authHeader = req.headers.authorization;
|
|
26
|
+
if (authHeader) {
|
|
27
|
+
headers.authorization = authHeader;
|
|
75
28
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return headers;
|
|
80
|
-
}
|
|
81
|
-
if (forceRefresh && tokens.refreshToken) {
|
|
82
|
-
await ensureRefresh();
|
|
83
|
-
}
|
|
84
|
-
const token = sdk?.authentication?.accessToken || tokens.accessToken;
|
|
85
|
-
if (token) {
|
|
86
|
-
headers.authorization = 'Bearer ' + token;
|
|
87
|
-
}
|
|
88
|
-
return headers;
|
|
89
|
-
};
|
|
90
|
-
options.onFailedRefreshToken = async () => {
|
|
91
|
-
await ensureRefresh();
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
sdk = new sdk_1.default(options);
|
|
95
|
-
return sdk;
|
|
29
|
+
return headers;
|
|
30
|
+
};
|
|
31
|
+
return new sdk_1.default(options);
|
|
96
32
|
}
|
|
97
33
|
//# sourceMappingURL=sdk-factory.js.map
|
package/dist/sdk-factory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-factory.js","sourceRoot":"","sources":["../src/sdk-factory.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"sdk-factory.js","sourceRoot":"","sources":["../src/sdk-factory.ts"],"names":[],"mappings":";;;;;AAUA,4CA4BC;AArCD,qDAAkC;AASlC,SAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAmB;IAC/D,MAAM,WAAW,GAA6B,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;IAEtE,MAAM,OAAO,GAAoB;QAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK,EAAE,UAAU,CAAC,KAA6B;QAC/C,GAAG,WAAW;KACf,CAAC;IAEF,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACnC,OAAO,IAAI,aAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,CAAC,YAAY,GAAG,KAAK,IAAI,EAAE;QAChC,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QACxC,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC;QAChC,CAAC;QACD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QAC7C,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,aAAa,GAAG,UAAU,CAAC;QACrC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO,IAAI,aAAQ,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC"}
|
package/dist/social-auth.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import type { Request, Response } from 'express';
|
|
1
2
|
import type QelosSDK from '@qelos/sdk';
|
|
2
3
|
import type { SocialAuthCallbackPayload } from '@qelos/sdk';
|
|
3
4
|
/**
|
|
4
5
|
* Runs {@link QelosSDK.authentication.socialCallback} for `requestUrl` and
|
|
5
|
-
* forwards session `Set-Cookie` headers to the Express response
|
|
6
|
+
* forwards session `Set-Cookie` headers to the Express response, rewriting
|
|
7
|
+
* the `Domain=` attribute of each cookie to the inbound request's host so
|
|
8
|
+
* the upstream-issued cookies land as first-party on the integrator host.
|
|
6
9
|
*/
|
|
7
|
-
export declare function completeSocialAuthCallback(sdk: QelosSDK,
|
|
8
|
-
|
|
9
|
-
}): Promise<SocialAuthCallbackPayload>;
|
|
10
|
-
export { applySocialAuthCookiesToServerResponse, getSocialAuthSetCookieParts, parseSocialCallbackRefreshToken, type SocialAuthCallbackPayload, type SocialCallbackInput, } from '@qelos/sdk';
|
|
10
|
+
export declare function completeSocialAuthCallback(sdk: QelosSDK, req: Pick<Request, 'url' | 'headers'>, res: Pick<Response, 'setHeader'>): Promise<SocialAuthCallbackPayload>;
|
|
11
|
+
export { getSocialAuthSetCookieParts, parseSocialCallbackRefreshToken, type SocialAuthCallbackPayload, type SocialCallbackInput, } from '@qelos/sdk';
|
package/dist/social-auth.js
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseSocialCallbackRefreshToken = exports.getSocialAuthSetCookieParts =
|
|
3
|
+
exports.parseSocialCallbackRefreshToken = exports.getSocialAuthSetCookieParts = void 0;
|
|
4
4
|
exports.completeSocialAuthCallback = completeSocialAuthCallback;
|
|
5
5
|
const sdk_1 = require("@qelos/sdk");
|
|
6
|
+
const cookies_1 = require("./cookies");
|
|
6
7
|
/**
|
|
7
8
|
* Runs {@link QelosSDK.authentication.socialCallback} for `requestUrl` and
|
|
8
|
-
* forwards session `Set-Cookie` headers to the Express response
|
|
9
|
+
* forwards session `Set-Cookie` headers to the Express response, rewriting
|
|
10
|
+
* the `Domain=` attribute of each cookie to the inbound request's host so
|
|
11
|
+
* the upstream-issued cookies land as first-party on the integrator host.
|
|
9
12
|
*/
|
|
10
|
-
async function completeSocialAuthCallback(sdk,
|
|
11
|
-
const result = await sdk.authentication.socialCallback(
|
|
12
|
-
(0, sdk_1.
|
|
13
|
+
async function completeSocialAuthCallback(sdk, req, res) {
|
|
14
|
+
const result = await sdk.authentication.socialCallback(req.url);
|
|
15
|
+
const parts = (0, sdk_1.getSocialAuthSetCookieParts)(result);
|
|
16
|
+
if (parts.length) {
|
|
17
|
+
const host = req.headers.host;
|
|
18
|
+
const rewritten = parts.map((value) => (0, cookies_1.rewriteSetCookieDomain)(value, host));
|
|
19
|
+
res.setHeader('Set-Cookie', rewritten.length === 1 ? rewritten[0] : rewritten);
|
|
20
|
+
}
|
|
13
21
|
return result;
|
|
14
22
|
}
|
|
15
23
|
var sdk_2 = require("@qelos/sdk");
|
|
16
|
-
Object.defineProperty(exports, "applySocialAuthCookiesToServerResponse", { enumerable: true, get: function () { return sdk_2.applySocialAuthCookiesToServerResponse; } });
|
|
17
24
|
Object.defineProperty(exports, "getSocialAuthSetCookieParts", { enumerable: true, get: function () { return sdk_2.getSocialAuthSetCookieParts; } });
|
|
18
25
|
Object.defineProperty(exports, "parseSocialCallbackRefreshToken", { enumerable: true, get: function () { return sdk_2.parseSocialCallbackRefreshToken; } });
|
|
19
26
|
//# sourceMappingURL=social-auth.js.map
|
package/dist/social-auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"social-auth.js","sourceRoot":"","sources":["../src/social-auth.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"social-auth.js","sourceRoot":"","sources":["../src/social-auth.ts"],"names":[],"mappings":";;;AAYA,gEAaC;AAtBD,oCAAyD;AACzD,uCAAmD;AAEnD;;;;;GAKG;AACI,KAAK,UAAU,0BAA0B,CAC9C,GAAa,EACb,GAAqC,EACrC,GAAgC;IAEhC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,IAAA,iCAA2B,EAAC,MAAM,CAAC,CAAC;IAClD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;QAC9B,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAA,gCAAsB,EAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC5E,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kCAKoB;AAJlB,kHAAA,2BAA2B,OAAA;AAC3B,sHAAA,+BAA+B,OAAA"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,25 +1,59 @@
|
|
|
1
|
-
import type { Request, Response } from 'express';
|
|
2
1
|
import type QelosSDK from '@qelos/sdk';
|
|
3
2
|
import type { IUser } from '@qelos/sdk/dist/authentication';
|
|
4
3
|
import type { IWorkspace } from '@qelos/sdk/workspaces';
|
|
5
4
|
import type { QelosSDKOptions } from '@qelos/sdk/types';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export interface QelosExpressConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Base URL of the Qelos backend (e.g. https://yourdomain.com).
|
|
8
|
+
*/
|
|
9
|
+
appUrl: string;
|
|
10
|
+
/**
|
|
11
|
+
* Static API token used for service-to-service calls. When provided, no
|
|
12
|
+
* cookie-based authentication is performed.
|
|
13
|
+
*/
|
|
14
|
+
apiToken?: string;
|
|
15
|
+
/**
|
|
16
|
+
* If true, the request is rejected (401) when the user cannot be resolved.
|
|
17
|
+
* Defaults to `false` — anonymous requests pass through with
|
|
18
|
+
* `req.qelos.user = null`.
|
|
19
|
+
*/
|
|
20
|
+
requireAuth?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Skip the middleware entirely for requests matching any of these path
|
|
23
|
+
* prefixes. Useful for `/api/_auth`, `/health`, etc.
|
|
24
|
+
*/
|
|
25
|
+
skipPaths?: string[];
|
|
26
|
+
/**
|
|
27
|
+
* If true, the catch-all `/api/**` proxy handler is not registered when
|
|
28
|
+
* using `createQelosIntegrator`. Defaults to `false`.
|
|
29
|
+
*/
|
|
30
|
+
disableProxy?: boolean;
|
|
9
31
|
/**
|
|
10
32
|
* Optional extra options merged into the per-request SDK instance.
|
|
11
33
|
*/
|
|
12
34
|
sdkOptions?: Partial<QelosSDKOptions>;
|
|
13
35
|
}
|
|
14
|
-
export interface
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
36
|
+
export interface QelosRequestContext {
|
|
37
|
+
/**
|
|
38
|
+
* The authenticated user, or `null` when anonymous.
|
|
39
|
+
*/
|
|
40
|
+
user: IUser | null;
|
|
41
|
+
/**
|
|
42
|
+
* The active workspace for the request, or `null` when none is active /
|
|
43
|
+
* the user is anonymous.
|
|
44
|
+
*/
|
|
45
|
+
workspace: IWorkspace | null;
|
|
46
|
+
/**
|
|
47
|
+
* The full list of workspaces the user has access to.
|
|
48
|
+
*/
|
|
49
|
+
workspaces: IWorkspace[];
|
|
50
|
+
/**
|
|
51
|
+
* SDK instance bound to the current request's cookies. `extraHeaders`
|
|
52
|
+
* re-reads cookies live on each call, so cookie rotations applied by the
|
|
53
|
+
* middleware are picked up automatically.
|
|
54
|
+
*/
|
|
19
55
|
sdk: QelosSDK;
|
|
20
56
|
}
|
|
21
|
-
export type TokenRefreshHook = (ctx: TokenRefreshContext) => void | Promise<void>;
|
|
22
|
-
export type QelosRequestContext = QelosContext<QelosSDK, IUser, IWorkspace>;
|
|
23
57
|
declare module 'express' {
|
|
24
58
|
interface Request {
|
|
25
59
|
qelos: QelosRequestContext;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qelos/integrator-express",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"description": "Express middleware that identifies the Qelos user and active workspace before your route handlers run",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@qelos/global-types": "4.
|
|
51
|
-
"@qelos/sdk": "4.
|
|
50
|
+
"@qelos/global-types": "4.1.1",
|
|
51
|
+
"@qelos/sdk": "4.1.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/express": "^4.17.21",
|