@objectstack/core 11.0.0 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +55 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -2
- package/dist/index.d.ts +32 -2
- package/dist/index.js +53 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Logger, IServiceRegistry } from '@objectstack/spec/contracts';
|
|
2
|
-
export {
|
|
2
|
+
export { IDataDriver, IDataEngine, IHttpRequest, IHttpResponse, IHttpServer, Logger, Middleware, RouteHandler } from '@objectstack/spec/contracts';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { LoggerConfig } from '@objectstack/spec/system';
|
|
5
5
|
import { ObjectLogger } from './logger.cjs';
|
|
@@ -1778,6 +1778,36 @@ declare function resolveLocalizationContext(input: ResolveLocalizationInput): Pr
|
|
|
1778
1778
|
currency?: string;
|
|
1779
1779
|
}>;
|
|
1780
1780
|
|
|
1781
|
+
/**
|
|
1782
|
+
* ADR-0069 — authentication-policy session gate.
|
|
1783
|
+
*
|
|
1784
|
+
* Some auth policies (password expiry, enforced MFA) must block an
|
|
1785
|
+
* authenticated user from PROTECTED RESOURCES until they remediate, while
|
|
1786
|
+
* still letting them reach the auth endpoints (change-password, two-factor
|
|
1787
|
+
* enrollment, sign-out) and a few UI-bootstrap reads.
|
|
1788
|
+
*
|
|
1789
|
+
* The posture is computed ONCE, in the auth `customSession` enrichment, and
|
|
1790
|
+
* attached to the session user as `user.authGate = { code, message }`. The
|
|
1791
|
+
* transport seams (REST middleware, dispatcher) then call
|
|
1792
|
+
* {@link evaluateAuthGate} to decide whether THIS request is blocked. Keeping
|
|
1793
|
+
* the allow-list + decision in one pure function means the seams can never
|
|
1794
|
+
* drift on what is blocked.
|
|
1795
|
+
*/
|
|
1796
|
+
interface AuthGate {
|
|
1797
|
+
/** Stable machine code, e.g. `PASSWORD_EXPIRED` / `MFA_REQUIRED`. */
|
|
1798
|
+
code: string;
|
|
1799
|
+
/** Human-facing message. */
|
|
1800
|
+
message: string;
|
|
1801
|
+
}
|
|
1802
|
+
/** True when `path` is exempt from the auth gate (auth + remediation + health). */
|
|
1803
|
+
declare function isAuthGateAllowlisted(rawPath: string | undefined | null): boolean;
|
|
1804
|
+
/**
|
|
1805
|
+
* Returns the active gate when `sessionUser` carries an `authGate` AND `path`
|
|
1806
|
+
* is not allow-listed; otherwise null. Anonymous users (no `authGate`) and
|
|
1807
|
+
* allow-listed paths always pass.
|
|
1808
|
+
*/
|
|
1809
|
+
declare function evaluateAuthGate(sessionUser: any, path: string): AuthGate | null;
|
|
1810
|
+
|
|
1781
1811
|
/**
|
|
1782
1812
|
* Environment utilities for universal (Node/Browser) compatibility.
|
|
1783
1813
|
*/
|
|
@@ -2225,4 +2255,4 @@ declare class NamespaceResolver {
|
|
|
2225
2255
|
private suggestAlternative;
|
|
2226
2256
|
}
|
|
2227
2257
|
|
|
2228
|
-
export { API_KEY_PREFIX, type ApiKeyPrincipal, ApiRegistry, type ApiRegistryPluginConfig, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type GeneratedApiKey, HotReloadManager, type KernelState, type KeyInput, LiteKernel, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolvedAuthzContext, type ResourceUsage, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type VersionCompatibility, buildPermissionsFromGrants, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, extractApiKey, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isExpired, isNode, parseScopes, parseSignature, resolveApiKeyPrincipal, resolveAuthzContext, resolveLocale, resolveLocalizationContext, safeExit, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature };
|
|
2258
|
+
export { API_KEY_PREFIX, type ApiKeyPrincipal, ApiRegistry, type ApiRegistryPluginConfig, type AuthGate, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type GeneratedApiKey, HotReloadManager, type KernelState, type KeyInput, LiteKernel, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolvedAuthzContext, type ResourceUsage, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type VersionCompatibility, buildPermissionsFromGrants, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, evaluateAuthGate, extractApiKey, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isAuthGateAllowlisted, isExpired, isNode, parseScopes, parseSignature, resolveApiKeyPrincipal, resolveAuthzContext, resolveLocale, resolveLocalizationContext, safeExit, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Logger, IServiceRegistry } from '@objectstack/spec/contracts';
|
|
2
|
-
export {
|
|
2
|
+
export { IDataDriver, IDataEngine, IHttpRequest, IHttpResponse, IHttpServer, Logger, Middleware, RouteHandler } from '@objectstack/spec/contracts';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { LoggerConfig } from '@objectstack/spec/system';
|
|
5
5
|
import { ObjectLogger } from './logger.js';
|
|
@@ -1778,6 +1778,36 @@ declare function resolveLocalizationContext(input: ResolveLocalizationInput): Pr
|
|
|
1778
1778
|
currency?: string;
|
|
1779
1779
|
}>;
|
|
1780
1780
|
|
|
1781
|
+
/**
|
|
1782
|
+
* ADR-0069 — authentication-policy session gate.
|
|
1783
|
+
*
|
|
1784
|
+
* Some auth policies (password expiry, enforced MFA) must block an
|
|
1785
|
+
* authenticated user from PROTECTED RESOURCES until they remediate, while
|
|
1786
|
+
* still letting them reach the auth endpoints (change-password, two-factor
|
|
1787
|
+
* enrollment, sign-out) and a few UI-bootstrap reads.
|
|
1788
|
+
*
|
|
1789
|
+
* The posture is computed ONCE, in the auth `customSession` enrichment, and
|
|
1790
|
+
* attached to the session user as `user.authGate = { code, message }`. The
|
|
1791
|
+
* transport seams (REST middleware, dispatcher) then call
|
|
1792
|
+
* {@link evaluateAuthGate} to decide whether THIS request is blocked. Keeping
|
|
1793
|
+
* the allow-list + decision in one pure function means the seams can never
|
|
1794
|
+
* drift on what is blocked.
|
|
1795
|
+
*/
|
|
1796
|
+
interface AuthGate {
|
|
1797
|
+
/** Stable machine code, e.g. `PASSWORD_EXPIRED` / `MFA_REQUIRED`. */
|
|
1798
|
+
code: string;
|
|
1799
|
+
/** Human-facing message. */
|
|
1800
|
+
message: string;
|
|
1801
|
+
}
|
|
1802
|
+
/** True when `path` is exempt from the auth gate (auth + remediation + health). */
|
|
1803
|
+
declare function isAuthGateAllowlisted(rawPath: string | undefined | null): boolean;
|
|
1804
|
+
/**
|
|
1805
|
+
* Returns the active gate when `sessionUser` carries an `authGate` AND `path`
|
|
1806
|
+
* is not allow-listed; otherwise null. Anonymous users (no `authGate`) and
|
|
1807
|
+
* allow-listed paths always pass.
|
|
1808
|
+
*/
|
|
1809
|
+
declare function evaluateAuthGate(sessionUser: any, path: string): AuthGate | null;
|
|
1810
|
+
|
|
1781
1811
|
/**
|
|
1782
1812
|
* Environment utilities for universal (Node/Browser) compatibility.
|
|
1783
1813
|
*/
|
|
@@ -2225,4 +2255,4 @@ declare class NamespaceResolver {
|
|
|
2225
2255
|
private suggestAlternative;
|
|
2226
2256
|
}
|
|
2227
2257
|
|
|
2228
|
-
export { API_KEY_PREFIX, type ApiKeyPrincipal, ApiRegistry, type ApiRegistryPluginConfig, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type GeneratedApiKey, HotReloadManager, type KernelState, type KeyInput, LiteKernel, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolvedAuthzContext, type ResourceUsage, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type VersionCompatibility, buildPermissionsFromGrants, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, extractApiKey, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isExpired, isNode, parseScopes, parseSignature, resolveApiKeyPrincipal, resolveAuthzContext, resolveLocale, resolveLocalizationContext, safeExit, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature };
|
|
2258
|
+
export { API_KEY_PREFIX, type ApiKeyPrincipal, ApiRegistry, type ApiRegistryPluginConfig, type AuthGate, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type GeneratedApiKey, HotReloadManager, type KernelState, type KeyInput, LiteKernel, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolvedAuthzContext, type ResourceUsage, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, type VersionCompatibility, buildPermissionsFromGrants, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createApiRegistryPlugin, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, evaluateAuthGate, extractApiKey, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, isAuthGateAllowlisted, isExpired, isNode, parseScopes, parseSignature, resolveApiKeyPrincipal, resolveAuthzContext, resolveLocale, resolveLocalizationContext, safeExit, signPayload, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature };
|
package/dist/index.js
CHANGED
|
@@ -4057,9 +4057,19 @@ async function resolveAuthzContext(input) {
|
|
|
4057
4057
|
ctx.userId = userId;
|
|
4058
4058
|
if (tenantId) ctx.tenantId = tenantId;
|
|
4059
4059
|
if (!ql || typeof ql.find !== "function") return ctx;
|
|
4060
|
+
let userRowLoaded = false;
|
|
4061
|
+
let userRow;
|
|
4062
|
+
const getUserRow = async () => {
|
|
4063
|
+
if (!userRowLoaded) {
|
|
4064
|
+
userRowLoaded = true;
|
|
4065
|
+
const rows = await tryFind(ql, "sys_user", { id: userId }, 1);
|
|
4066
|
+
userRow = rows[0];
|
|
4067
|
+
}
|
|
4068
|
+
return userRow;
|
|
4069
|
+
};
|
|
4060
4070
|
if (!ctx.email) {
|
|
4061
|
-
const
|
|
4062
|
-
if (
|
|
4071
|
+
const u = await getUserRow();
|
|
4072
|
+
if (u?.email) ctx.email = String(u.email);
|
|
4063
4073
|
}
|
|
4064
4074
|
const memberWhere = tenantId ? { user_id: userId, organization_id: tenantId } : { user_id: userId };
|
|
4065
4075
|
const members = await tryFind(ql, "sys_member", memberWhere, 50);
|
|
@@ -4140,8 +4150,7 @@ async function resolveAuthzContext(input) {
|
|
|
4140
4150
|
ctx.roles.unshift(BUILTIN_ROLE_PLATFORM_ADMIN);
|
|
4141
4151
|
}
|
|
4142
4152
|
if (!ctx.permissions.includes("ai_seat")) {
|
|
4143
|
-
const
|
|
4144
|
-
const aiAccess = seatRows?.[0]?.ai_access;
|
|
4153
|
+
const aiAccess = (await getUserRow())?.ai_access;
|
|
4145
4154
|
if (aiAccess === true || aiAccess === 1 || aiAccess === "1") ctx.permissions.push("ai_seat");
|
|
4146
4155
|
}
|
|
4147
4156
|
return ctx;
|
|
@@ -4183,13 +4192,45 @@ async function resolveLocalizationContext(input) {
|
|
|
4183
4192
|
}
|
|
4184
4193
|
} catch {
|
|
4185
4194
|
}
|
|
4186
|
-
const
|
|
4187
|
-
|
|
4188
|
-
|
|
4195
|
+
const rows = await tryFind(
|
|
4196
|
+
ql,
|
|
4197
|
+
"sys_setting",
|
|
4198
|
+
{ namespace: "localization", key: { $in: ["timezone", "locale", "currency"] }, scope: "tenant" },
|
|
4199
|
+
10
|
|
4200
|
+
);
|
|
4201
|
+
const valueOf = (k) => rows.find((r) => r.key === k)?.value;
|
|
4202
|
+
return {
|
|
4203
|
+
timezone: coerceTimeZone(valueOf("timezone")) ?? "UTC",
|
|
4204
|
+
locale: coerceLocale(valueOf("locale")) ?? "en-US",
|
|
4205
|
+
currency: coerceCurrency(valueOf("currency"))
|
|
4206
|
+
};
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4209
|
+
// src/security/auth-gate.ts
|
|
4210
|
+
var ALLOW_PREFIXES = ["/api/v1/auth/", "/api/auth/", "/auth/"];
|
|
4211
|
+
var ALLOW_SUFFIXES = ["/health", "/ready", "/discovery", "/me/apps", "/me/localization"];
|
|
4212
|
+
function isAuthGateAllowlisted(rawPath) {
|
|
4213
|
+
if (!rawPath) return true;
|
|
4214
|
+
let path = rawPath.split("?")[0] || "/";
|
|
4215
|
+
let end = path.length;
|
|
4216
|
+
while (end > 1 && path.charCodeAt(end - 1) === 47) end--;
|
|
4217
|
+
path = path.slice(0, end) || "/";
|
|
4218
|
+
if (path.includes("/auth/")) return true;
|
|
4219
|
+
for (const p of ALLOW_PREFIXES) {
|
|
4220
|
+
if (path.startsWith(p) || path === p.replace(/\/$/, "")) return true;
|
|
4221
|
+
}
|
|
4222
|
+
for (const s of ALLOW_SUFFIXES) {
|
|
4223
|
+
if (path.endsWith(s)) return true;
|
|
4224
|
+
}
|
|
4225
|
+
return false;
|
|
4226
|
+
}
|
|
4227
|
+
function evaluateAuthGate(sessionUser, path) {
|
|
4228
|
+
const gate = sessionUser?.authGate;
|
|
4229
|
+
if (!gate || typeof gate.code !== "string") return null;
|
|
4230
|
+
if (isAuthGateAllowlisted(path)) return null;
|
|
4189
4231
|
return {
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
currency: coerceCurrency(currencyRows[0]?.value)
|
|
4232
|
+
code: gate.code,
|
|
4233
|
+
message: typeof gate.message === "string" && gate.message ? gate.message : "Access is blocked by an authentication policy."
|
|
4193
4234
|
};
|
|
4194
4235
|
}
|
|
4195
4236
|
|
|
@@ -5168,12 +5209,14 @@ export {
|
|
|
5168
5209
|
createMemoryQueue,
|
|
5169
5210
|
createPluginConfigValidator,
|
|
5170
5211
|
createPluginPermissionEnforcer,
|
|
5212
|
+
evaluateAuthGate,
|
|
5171
5213
|
extractApiKey,
|
|
5172
5214
|
generateApiKey,
|
|
5173
5215
|
generateEd25519KeyPair,
|
|
5174
5216
|
getEnv,
|
|
5175
5217
|
getMemoryUsage,
|
|
5176
5218
|
hashApiKey,
|
|
5219
|
+
isAuthGateAllowlisted,
|
|
5177
5220
|
isExpired,
|
|
5178
5221
|
isNode,
|
|
5179
5222
|
parseScopes,
|