@rapidmx/mapi-plugin 1.0.0-beta.10
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/LICENSE +382 -0
- package/README.md +60 -0
- package/dist/lib/BaseMapiEmsmdbRoute.js +489 -0
- package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -0
- package/dist/lib/BaseMapiNspiRoute.js +114 -0
- package/dist/lib/BaseMapiNspiRoute.js.map +1 -0
- package/dist/lib/MapiSessionManager.js +475 -0
- package/dist/lib/MapiSessionManager.js.map +1 -0
- package/dist/lib/RegexPatternUtils.js +30 -0
- package/dist/lib/RegexPatternUtils.js.map +1 -0
- package/dist/lib/RopDispatcher.js +145 -0
- package/dist/lib/RopDispatcher.js.map +1 -0
- package/dist/lib/codec/AppointmentRecurrence.js +315 -0
- package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
- package/dist/lib/codec/BufferCursor.js +242 -0
- package/dist/lib/codec/BufferCursor.js.map +1 -0
- package/dist/lib/codec/GlobalObjectId.js +98 -0
- package/dist/lib/codec/GlobalObjectId.js.map +1 -0
- package/dist/lib/codec/MapiGuid.js +41 -0
- package/dist/lib/codec/MapiGuid.js.map +1 -0
- package/dist/lib/codec/MapiTimeZone.js +126 -0
- package/dist/lib/codec/MapiTimeZone.js.map +1 -0
- package/dist/lib/codec/PropertyValue.js +240 -0
- package/dist/lib/codec/PropertyValue.js.map +1 -0
- package/dist/lib/codec/RopBuffer.js +38 -0
- package/dist/lib/codec/RopBuffer.js.map +1 -0
- package/dist/lib/codec/TypedString.js +54 -0
- package/dist/lib/codec/TypedString.js.map +1 -0
- package/dist/lib/index.js +99 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +85 -0
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -0
- package/dist/lib/mongo/MapiNspiRouteMongo.js +33 -0
- package/dist/lib/mongo/MapiNspiRouteMongo.js.map +1 -0
- package/dist/lib/mongo/index.js +7 -0
- package/dist/lib/mongo/index.js.map +1 -0
- package/dist/lib/mongo.js +6 -0
- package/dist/lib/mongo.js.map +1 -0
- package/dist/lib/nspi/NspiBindHandler.js +54 -0
- package/dist/lib/nspi/NspiBindHandler.js.map +1 -0
- package/dist/lib/nspi/NspiCodec.js +106 -0
- package/dist/lib/nspi/NspiCodec.js.map +1 -0
- package/dist/lib/nspi/NspiGetMatchesHandler.js +142 -0
- package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -0
- package/dist/lib/rop/AddressList.js +114 -0
- package/dist/lib/rop/AddressList.js.map +1 -0
- package/dist/lib/rop/CalendarEventTarget.js +30 -0
- package/dist/lib/rop/CalendarEventTarget.js.map +1 -0
- package/dist/lib/rop/CalendarNamedProperties.js +57 -0
- package/dist/lib/rop/CalendarNamedProperties.js.map +1 -0
- package/dist/lib/rop/ContactTarget.js +19 -0
- package/dist/lib/rop/ContactTarget.js.map +1 -0
- package/dist/lib/rop/ContentsTable.js +60 -0
- package/dist/lib/rop/ContentsTable.js.map +1 -0
- package/dist/lib/rop/ExecuteBudget.js +82 -0
- package/dist/lib/rop/ExecuteBudget.js.map +1 -0
- package/dist/lib/rop/FastTransferStream.js +195 -0
- package/dist/lib/rop/FastTransferStream.js.map +1 -0
- package/dist/lib/rop/FolderTarget.js +118 -0
- package/dist/lib/rop/FolderTarget.js.map +1 -0
- package/dist/lib/rop/HandleDataCache.js +412 -0
- package/dist/lib/rop/HandleDataCache.js.map +1 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js +241 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
- package/dist/lib/rop/MessageBodyStream.js +68 -0
- package/dist/lib/rop/MessageBodyStream.js.map +1 -0
- package/dist/lib/rop/MessageTarget.js +57 -0
- package/dist/lib/rop/MessageTarget.js.map +1 -0
- package/dist/lib/rop/NamedPropertyRegistry.js +69 -0
- package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
- package/dist/lib/rop/PropertyResolvers.js +353 -0
- package/dist/lib/rop/PropertyResolvers.js.map +1 -0
- package/dist/lib/rop/RepoPaging.js +54 -0
- package/dist/lib/rop/RepoPaging.js.map +1 -0
- package/dist/lib/rop/RestapiRules.js +52 -0
- package/dist/lib/rop/RestapiRules.js.map +1 -0
- package/dist/lib/rop/RopCreateMessageHandler.js +55 -0
- package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js +174 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js +110 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +61 -0
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +60 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +76 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js +55 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js +42 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +56 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js +92 -0
- package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js.map +1 -0
- package/dist/lib/rop/RopHandler.js +6 -0
- package/dist/lib/rop/RopHandler.js.map +1 -0
- package/dist/lib/rop/RopLogonHandler.js +135 -0
- package/dist/lib/rop/RopLogonHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenFolderHandler.js +48 -0
- package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenMessageHandler.js +83 -0
- package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenStreamHandler.js +84 -0
- package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopQueryRowsHandler.js +120 -0
- package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
- package/dist/lib/rop/RopReadStreamHandler.js +73 -0
- package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopReleaseHandler.js +23 -0
- package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js +269 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopSetColumnsHandler.js +50 -0
- package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js +173 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js +342 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopWriteStreamHandler.js +72 -0
- package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -0
- package/dist/lib/rop/TaskNamedProperties.js +29 -0
- package/dist/lib/rop/TaskNamedProperties.js.map +1 -0
- package/dist/lib/rop/TaskTarget.js +15 -0
- package/dist/lib/rop/TaskTarget.js.map +1 -0
- package/dist/lib/rop/TransportSend.js +16 -0
- package/dist/lib/rop/TransportSend.js.map +1 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js +85 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -0
- package/dist/lib/sql/MapiNspiRouteSQL.js +33 -0
- package/dist/lib/sql/MapiNspiRouteSQL.js.map +1 -0
- package/dist/lib/sql/index.js +7 -0
- package/dist/lib/sql/index.js.map +1 -0
- package/dist/lib/sql.js +6 -0
- package/dist/lib/sql.js.map +1 -0
- package/dist/types/BaseMapiEmsmdbRoute.d.ts +139 -0
- package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
- package/dist/types/MapiSessionManager.d.ts +285 -0
- package/dist/types/RegexPatternUtils.d.ts +14 -0
- package/dist/types/RopDispatcher.d.ts +53 -0
- package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
- package/dist/types/codec/BufferCursor.d.ts +92 -0
- package/dist/types/codec/GlobalObjectId.d.ts +15 -0
- package/dist/types/codec/MapiGuid.d.ts +6 -0
- package/dist/types/codec/MapiTimeZone.d.ts +7 -0
- package/dist/types/codec/PropertyValue.d.ts +87 -0
- package/dist/types/codec/RopBuffer.d.ts +32 -0
- package/dist/types/codec/TypedString.d.ts +17 -0
- package/dist/types/index.d.ts +94 -0
- package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +20 -0
- package/dist/types/mongo/MapiNspiRouteMongo.d.ts +13 -0
- package/dist/types/mongo/index.d.ts +2 -0
- package/dist/types/mongo.d.ts +1 -0
- package/dist/types/nspi/NspiBindHandler.d.ts +22 -0
- package/dist/types/nspi/NspiCodec.d.ts +59 -0
- package/dist/types/nspi/NspiGetMatchesHandler.d.ts +26 -0
- package/dist/types/rop/AddressList.d.ts +48 -0
- package/dist/types/rop/CalendarEventTarget.d.ts +33 -0
- package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
- package/dist/types/rop/ContactTarget.d.ts +29 -0
- package/dist/types/rop/ContentsTable.d.ts +16 -0
- package/dist/types/rop/ExecuteBudget.d.ts +48 -0
- package/dist/types/rop/FastTransferStream.d.ts +57 -0
- package/dist/types/rop/FolderTarget.d.ts +64 -0
- package/dist/types/rop/HandleDataCache.d.ts +145 -0
- package/dist/types/rop/MeetingMessageClassHandler.d.ts +30 -0
- package/dist/types/rop/MessageBodyStream.d.ts +35 -0
- package/dist/types/rop/MessageTarget.d.ts +45 -0
- package/dist/types/rop/NamedPropertyRegistry.d.ts +50 -0
- package/dist/types/rop/PropertyResolvers.d.ts +86 -0
- package/dist/types/rop/RepoPaging.d.ts +30 -0
- package/dist/types/rop/RestapiRules.d.ts +32 -0
- package/dist/types/rop/RopCreateMessageHandler.d.ts +24 -0
- package/dist/types/rop/RopDeleteFolderHandler.d.ts +53 -0
- package/dist/types/rop/RopDeleteMessagesHandler.d.ts +43 -0
- package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +25 -0
- package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +25 -0
- package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +22 -0
- package/dist/types/rop/RopGetContentsTableHandler.d.ts +25 -0
- package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +18 -0
- package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +26 -0
- package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
- package/dist/types/rop/RopHandler.d.ts +106 -0
- package/dist/types/rop/RopLogonHandler.d.ts +31 -0
- package/dist/types/rop/RopOpenFolderHandler.d.ts +20 -0
- package/dist/types/rop/RopOpenMessageHandler.d.ts +28 -0
- package/dist/types/rop/RopOpenStreamHandler.d.ts +28 -0
- package/dist/types/rop/RopQueryRowsHandler.d.ts +43 -0
- package/dist/types/rop/RopReadStreamHandler.d.ts +20 -0
- package/dist/types/rop/RopReleaseHandler.d.ts +15 -0
- package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +59 -0
- package/dist/types/rop/RopSetColumnsHandler.d.ts +21 -0
- package/dist/types/rop/RopSetPropertiesHandler.d.ts +38 -0
- package/dist/types/rop/RopSubmitMessageHandler.d.ts +80 -0
- package/dist/types/rop/RopWriteStreamHandler.d.ts +31 -0
- package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
- package/dist/types/rop/TaskTarget.d.ts +24 -0
- package/dist/types/rop/TransportSend.d.ts +10 -0
- package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +20 -0
- package/dist/types/sql/MapiNspiRouteSQL.d.ts +13 -0
- package/dist/types/sql/index.d.ts +2 -0
- package/dist/types/sql.d.ts +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
11
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
12
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
13
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
+
import * as crypto from "crypto";
|
|
15
|
+
import { ObjectDecorators } from "@rapidrest/core";
|
|
16
|
+
import { DatabaseDecorators, SimpleEntity } from "@rapidrest/service-core";
|
|
17
|
+
import { handleDataCache, handleDataKey, MemoryHandleDataStore, RedisHandleDataStore, sessionHandleDataIndex, writeStreamKey, } from "./rop/HandleDataCache.js";
|
|
18
|
+
const { Init } = ObjectDecorators;
|
|
19
|
+
const { Redis } = DatabaseDecorators;
|
|
20
|
+
/** A pragmatic idle-session lifetime. The spec leaves session lifetime to server policy, not a fixed wire
|
|
21
|
+
* value - a real client re-establishes (`Connect`) transparently whenever its session context has expired. */
|
|
22
|
+
export const SESSION_TTL_SECONDS = 15 * 60;
|
|
23
|
+
/** The longest a session may live, however active it stays. A client simply `Connect`s again afterwards. */
|
|
24
|
+
export const MAX_SESSION_LIFETIME_MS = 24 * 60 * 60 * 1000;
|
|
25
|
+
/** The most sessions one user may hold at once. `Connect` past this ends that user's least recently used session (each
|
|
26
|
+
* `Execute` refreshes its session's place - see `MapiSessionManager.touch`). */
|
|
27
|
+
export const MAX_SESSIONS_PER_USER = 20;
|
|
28
|
+
/** The largest a serialized session may grow. Everything that grows with use is capped on its own (handles by their
|
|
29
|
+
* one-byte index, named properties, MIDs; write streams live outside the session); this is the backstop, and a save
|
|
30
|
+
* past it fails with `MAPI_E_TOO_BIG` rather than storing megabytes every later request has to load. */
|
|
31
|
+
export const MAX_SESSION_BYTES = 4 * 1024 * 1024;
|
|
32
|
+
/** How long an `Execute`'s session lock lives without being renewed. A running `Execute` renews it every
|
|
33
|
+
* `SESSION_LOCK_RENEW_MS`, so only a crashed pod's lock expires. The session save is still compare-and-set, so an
|
|
34
|
+
* expired lock can't corrupt state. */
|
|
35
|
+
export const SESSION_LOCK_TTL_MS = 120 * 1000;
|
|
36
|
+
/** How often a running `Execute` renews its session lock and in-progress marker. */
|
|
37
|
+
export const SESSION_LOCK_RENEW_MS = SESSION_LOCK_TTL_MS / 3;
|
|
38
|
+
/**
|
|
39
|
+
* The MAPI/HTTP `Session Context` (`[MS-OXCMAPIHTTP]` §3.1.1.1): everything a `Connect`-established session
|
|
40
|
+
* needs across subsequent `Execute` requests. Never persisted to a real database - purely an ephemeral,
|
|
41
|
+
* TTL-bound store entry (see `MapiSessionManager` below), so this deliberately extends `SimpleEntity` (just a
|
|
42
|
+
* `uid`) rather than this library's own `BaseEntity`.
|
|
43
|
+
*
|
|
44
|
+
* `createdAt` is a plain ISO-8601 string, not a `Date`, since sessions round-trip through JSON. `version` is
|
|
45
|
+
* bumped on every successful save and compared on the next one - see `MapiSessionManager.save()`.
|
|
46
|
+
*/
|
|
47
|
+
export class MapiSessionContext extends SimpleEntity {
|
|
48
|
+
constructor(other) {
|
|
49
|
+
super(other);
|
|
50
|
+
this.version = 0;
|
|
51
|
+
this.handles = {};
|
|
52
|
+
this.nextHandleIndex = 1;
|
|
53
|
+
this.createdAt = new Date().toISOString();
|
|
54
|
+
/** This session's FID assignments for the 13 `RopLogon` special folders, keyed by FID (decimal string),
|
|
55
|
+
* valued `"virtual:<name>"` or `"folder:<uid>"` - see `RopLogonHandler`'s own doc comment. Populated by
|
|
56
|
+
* `RopLogon`, read back by a later `RopOpenFolder`. */
|
|
57
|
+
this.folderIds = {};
|
|
58
|
+
/** The reverse of `folderIds` (target -> FID) plus a monotonic counter, maintained alongside it by
|
|
59
|
+
* `FolderTarget.assignOrGetFid`/`RopLogonHandler` so "does this target already have a FID" is an O(1)
|
|
60
|
+
* lookup instead of a linear scan of `folderIds` repeated once per table row. */
|
|
61
|
+
this.folderTargetIds = {};
|
|
62
|
+
this.nextFolderId = 1;
|
|
63
|
+
/** This session's MID assignments, keyed by MID (decimal string), valued `"message:<uid>"` - the message
|
|
64
|
+
* analog of `folderIds` above. A MID only ever comes into existence lazily, the first time a `RopQueryRows`
|
|
65
|
+
* row exposes a message's `PidTagMid` column (see `MessageTarget.assignOrGetMid`), read back by a later
|
|
66
|
+
* `RopOpenMessage`. */
|
|
67
|
+
this.messageIds = {};
|
|
68
|
+
/** The reverse of `messageIds` (target -> MID) plus a monotonic counter. */
|
|
69
|
+
this.messageTargetIds = {};
|
|
70
|
+
this.nextMessageId = 1;
|
|
71
|
+
/** The oldest MID still mapped. Past `MAX_MESSAGE_IDS` mapped MIDs the oldest are dropped - see
|
|
72
|
+
* `MessageTarget.assignOrGetMid`. */
|
|
73
|
+
this.firstMessageId = 1;
|
|
74
|
+
/** This session's `RopGetPropertyIdsFromNames` mapping table (`[MS-OXCPRPT]` §2.2.12), keyed by a JSON
|
|
75
|
+
* string encoding of the `{guid, kind, lid|name}` `PropertyName` the numeric ID was assigned to - see
|
|
76
|
+
* `NamedPropertyRegistry.ts`. */
|
|
77
|
+
this.namedProperties = {};
|
|
78
|
+
/** The reverse of `namedProperties` (numeric ID -> `PropertyName` JSON key) plus a monotonic counter. */
|
|
79
|
+
this.namedPropertyIds = {};
|
|
80
|
+
this.nextNamedPropertyId = 0x8000;
|
|
81
|
+
this.mailboxUid = other.mailboxUid;
|
|
82
|
+
this.userUid = other.userUid;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Stores `handle` at `index` with a fresh generation. Whatever previously held that index is released first
|
|
87
|
+
* (see `releaseHandle`), so a stream or cached data belonging to the old handle never attaches to the new one.
|
|
88
|
+
*/
|
|
89
|
+
export function assignHandle(session, index, handle) {
|
|
90
|
+
releaseHandle(session, index);
|
|
91
|
+
handle.generation = crypto.randomUUID();
|
|
92
|
+
session.handles[index] = handle;
|
|
93
|
+
return handle;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Releases the handle at `index`: drops its cached data, and releases every write stream opened against it
|
|
97
|
+
* (a stream is meaningless once its draft message is gone, and would otherwise attach to whatever reuses the
|
|
98
|
+
* index next).
|
|
99
|
+
*/
|
|
100
|
+
export function releaseHandle(session, index) {
|
|
101
|
+
const handle = session.handles[index];
|
|
102
|
+
if (!handle) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
delete session.handles[index];
|
|
106
|
+
handleDataCache.delete(handleDataKey(session.uid, index, handle.generation));
|
|
107
|
+
if (handle.type === "fastTransfer" || handle.type === "stream") {
|
|
108
|
+
const released = releasedHandleData.get(session) ?? [];
|
|
109
|
+
released.push(handle.type === "fastTransfer" ? handleDataKey(session.uid, index, handle.generation) : writeStreamKey(session.uid, index, handle.generation));
|
|
110
|
+
releasedHandleData.set(session, released);
|
|
111
|
+
}
|
|
112
|
+
for (const [key, candidate] of Object.entries(session.handles)) {
|
|
113
|
+
if (candidate.writeTargetHandleIndex === index && candidate.writeTargetGeneration === handle.generation) {
|
|
114
|
+
releaseHandle(session, Number(key));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/** Session object -> the `HandleDataStore` keys of the handles released on it since the last `takeReleasedHandleData`.
|
|
119
|
+
* Kept beside the session, never in it, so it isn't saved. */
|
|
120
|
+
const releasedHandleData = new WeakMap();
|
|
121
|
+
/** The shared-store keys (FastTransfer streams, write-stream chunks) of every handle released on `session` since the
|
|
122
|
+
* last call, for the route to delete once the session's changes are saved. */
|
|
123
|
+
export function takeReleasedHandleData(session) {
|
|
124
|
+
const released = releasedHandleData.get(session) ?? [];
|
|
125
|
+
releasedHandleData.delete(session);
|
|
126
|
+
return released;
|
|
127
|
+
}
|
|
128
|
+
/** Creates a session at version 0. KEYS: session, version. ARGV: json, ttl. */
|
|
129
|
+
export const CREATE_SCRIPT = `
|
|
130
|
+
redis.call('SETEX', KEYS[1], ARGV[2], ARGV[1])
|
|
131
|
+
redis.call('SETEX', KEYS[2], ARGV[2], '0')
|
|
132
|
+
return 1
|
|
133
|
+
`;
|
|
134
|
+
/** Replaces the session only when its version entry still equals the expected one, without decoding the session.
|
|
135
|
+
* KEYS: session, version. ARGV: expected version, json, ttl. Returns 1 saved, 0 on a version mismatch, -1 when gone. */
|
|
136
|
+
export const COMPARE_AND_SET_SCRIPT = `
|
|
137
|
+
local current = redis.call('GET', KEYS[2])
|
|
138
|
+
if not current or redis.call('EXISTS', KEYS[1]) == 0 then return -1 end
|
|
139
|
+
if tonumber(current) ~= tonumber(ARGV[1]) then return 0 end
|
|
140
|
+
redis.call('SETEX', KEYS[1], ARGV[3], ARGV[2])
|
|
141
|
+
redis.call('SETEX', KEYS[2], ARGV[3], tostring(tonumber(ARGV[1]) + 1))
|
|
142
|
+
return 1
|
|
143
|
+
`;
|
|
144
|
+
/** Adds a session to its user's sorted-set index in one step, so concurrent Connects can't each see room under the
|
|
145
|
+
* cap. KEYS: index. ARGV: session id, created-at score, max, index ttl, session key prefix, session key suffix. The
|
|
146
|
+
* session keys it checks and deletes are built from the ids, so they aren't declared in KEYS (fine on one Redis node,
|
|
147
|
+
* not on a cluster). Returns the ids it ended. */
|
|
148
|
+
export const ADD_TO_USER_INDEX_SCRIPT = `
|
|
149
|
+
local function sessionKey(id) return ARGV[5] .. id .. ARGV[6] end
|
|
150
|
+
for _, id in ipairs(redis.call('ZRANGE', KEYS[1], 0, -1)) do
|
|
151
|
+
if redis.call('EXISTS', sessionKey(id)) == 0 then redis.call('ZREM', KEYS[1], id) end
|
|
152
|
+
end
|
|
153
|
+
local ended = {}
|
|
154
|
+
while redis.call('ZCARD', KEYS[1]) >= tonumber(ARGV[3]) do
|
|
155
|
+
local oldest = redis.call('ZRANGE', KEYS[1], 0, 0)[1]
|
|
156
|
+
redis.call('ZREM', KEYS[1], oldest)
|
|
157
|
+
redis.call('DEL', sessionKey(oldest), sessionKey(oldest) .. '.version')
|
|
158
|
+
table.insert(ended, oldest)
|
|
159
|
+
end
|
|
160
|
+
redis.call('ZADD', KEYS[1], ARGV[2], ARGV[1])
|
|
161
|
+
redis.call('EXPIRE', KEYS[1], ARGV[4])
|
|
162
|
+
return ended
|
|
163
|
+
`;
|
|
164
|
+
/** KEYS: lock. ARGV: token, ttl ms. Returns 1 when acquired. */
|
|
165
|
+
export const ACQUIRE_LOCK_SCRIPT = `
|
|
166
|
+
if redis.call('SET', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) then return 1 end
|
|
167
|
+
return 0
|
|
168
|
+
`;
|
|
169
|
+
/** KEYS: lock. ARGV: token. Deletes the lock only while this token still holds it. */
|
|
170
|
+
export const RELEASE_LOCK_SCRIPT = `
|
|
171
|
+
if redis.call('GET', KEYS[1]) == ARGV[1] then redis.call('DEL', KEYS[1]) end
|
|
172
|
+
return 1
|
|
173
|
+
`;
|
|
174
|
+
/** KEYS: lock. ARGV: token, ttl ms. Returns 1 when the token still held the lock and it was extended. */
|
|
175
|
+
export const RENEW_LOCK_SCRIPT = `
|
|
176
|
+
if redis.call('GET', KEYS[1]) == ARGV[1] then redis.call('PEXPIRE', KEYS[1], ARGV[2]) return 1 end
|
|
177
|
+
return 0
|
|
178
|
+
`;
|
|
179
|
+
/** KEYS: user index. ARGV: score, session id. Updates the score of a member that is still present. */
|
|
180
|
+
export const TOUCH_USER_INDEX_SCRIPT = `
|
|
181
|
+
redis.call('ZADD', KEYS[1], 'XX', ARGV[1], ARGV[2])
|
|
182
|
+
return 1
|
|
183
|
+
`;
|
|
184
|
+
/** A `MapiSessionStore` on a node-redis client. Every read goes to Redis, never a per-process copy, so each
|
|
185
|
+
* replica sees the same session. */
|
|
186
|
+
export class RedisMapiSessionStore {
|
|
187
|
+
constructor(client) {
|
|
188
|
+
this.client = client;
|
|
189
|
+
}
|
|
190
|
+
async get(key) {
|
|
191
|
+
return (await this.client.get(key)) ?? undefined;
|
|
192
|
+
}
|
|
193
|
+
async create(key, value, ttlSeconds) {
|
|
194
|
+
await this.client.eval(CREATE_SCRIPT, { keys: [key, versionKey(key)], arguments: [value, String(ttlSeconds)] });
|
|
195
|
+
}
|
|
196
|
+
async compareAndSet(key, expectedVersion, value, ttlSeconds) {
|
|
197
|
+
const result = Number(await this.client.eval(COMPARE_AND_SET_SCRIPT, {
|
|
198
|
+
keys: [key, versionKey(key)],
|
|
199
|
+
arguments: [String(expectedVersion), value, String(ttlSeconds)],
|
|
200
|
+
}));
|
|
201
|
+
return result === 1 ? "saved" : result === 0 ? "conflict" : "missing";
|
|
202
|
+
}
|
|
203
|
+
async delete(key) {
|
|
204
|
+
await this.client.del([key, versionKey(key)]);
|
|
205
|
+
}
|
|
206
|
+
async addToUserIndex(indexKey, sessionId, createdAtMs, max, ttlSeconds) {
|
|
207
|
+
const ended = await this.client.eval(ADD_TO_USER_INDEX_SCRIPT, {
|
|
208
|
+
keys: [indexKey],
|
|
209
|
+
arguments: [sessionId, String(createdAtMs), String(max), String(ttlSeconds), SESSION_KEY_PREFIX, SESSION_KEY_SUFFIX],
|
|
210
|
+
});
|
|
211
|
+
return ended.map(String);
|
|
212
|
+
}
|
|
213
|
+
async acquireLock(key, token, ttlMs) {
|
|
214
|
+
return Number(await this.client.eval(ACQUIRE_LOCK_SCRIPT, { keys: [key], arguments: [token, String(ttlMs)] })) === 1;
|
|
215
|
+
}
|
|
216
|
+
async releaseLock(key, token) {
|
|
217
|
+
await this.client.eval(RELEASE_LOCK_SCRIPT, { keys: [key], arguments: [token] });
|
|
218
|
+
}
|
|
219
|
+
async renewLock(key, token, ttlMs) {
|
|
220
|
+
return Number(await this.client.eval(RENEW_LOCK_SCRIPT, { keys: [key], arguments: [token, String(ttlMs)] })) === 1;
|
|
221
|
+
}
|
|
222
|
+
async touchUserIndex(indexKey, sessionId, score) {
|
|
223
|
+
await this.client.eval(TOUCH_USER_INDEX_SCRIPT, { keys: [indexKey], arguments: [String(score), sessionId] });
|
|
224
|
+
}
|
|
225
|
+
async getValue(key) {
|
|
226
|
+
return (await this.client.get(key)) ?? undefined;
|
|
227
|
+
}
|
|
228
|
+
async putValue(key, value, ttlSeconds) {
|
|
229
|
+
await this.client.setEx(key, ttlSeconds, value);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/** A single-process `MapiSessionStore`. Values are stored as strings so every load hands out an independent copy,
|
|
233
|
+
* exactly like the Redis store. No method awaits between reading and writing, so each one is atomic. */
|
|
234
|
+
export class MemoryMapiSessionStore {
|
|
235
|
+
constructor() {
|
|
236
|
+
this.entries = new Map();
|
|
237
|
+
this.indexes = new Map();
|
|
238
|
+
}
|
|
239
|
+
async get(key) {
|
|
240
|
+
return this.read(key);
|
|
241
|
+
}
|
|
242
|
+
async create(key, value, ttlSeconds) {
|
|
243
|
+
this.sweep();
|
|
244
|
+
this.write(key, value, ttlSeconds);
|
|
245
|
+
this.write(versionKey(key), "0", ttlSeconds);
|
|
246
|
+
}
|
|
247
|
+
async compareAndSet(key, expectedVersion, value, ttlSeconds) {
|
|
248
|
+
const version = this.read(versionKey(key));
|
|
249
|
+
if (version === undefined || this.read(key) === undefined) {
|
|
250
|
+
return "missing";
|
|
251
|
+
}
|
|
252
|
+
if (Number(version) !== expectedVersion) {
|
|
253
|
+
return "conflict";
|
|
254
|
+
}
|
|
255
|
+
this.write(key, value, ttlSeconds);
|
|
256
|
+
this.write(versionKey(key), String(expectedVersion + 1), ttlSeconds);
|
|
257
|
+
return "saved";
|
|
258
|
+
}
|
|
259
|
+
async delete(key) {
|
|
260
|
+
this.entries.delete(key);
|
|
261
|
+
this.entries.delete(versionKey(key));
|
|
262
|
+
}
|
|
263
|
+
async addToUserIndex(indexKey, sessionId, createdAtMs, max) {
|
|
264
|
+
const members = this.indexes.get(indexKey) ?? new Map();
|
|
265
|
+
this.indexes.set(indexKey, members);
|
|
266
|
+
for (const id of [...members.keys()]) {
|
|
267
|
+
if (this.read(SESSION_KEY_PREFIX + id + SESSION_KEY_SUFFIX) === undefined) {
|
|
268
|
+
members.delete(id);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const oldestFirst = [...members.entries()].sort((a, b) => a[1] - b[1]).map(([id]) => id);
|
|
272
|
+
const ended = [];
|
|
273
|
+
while (members.size >= max) {
|
|
274
|
+
const oldest = oldestFirst.shift();
|
|
275
|
+
members.delete(oldest);
|
|
276
|
+
this.entries.delete(SESSION_KEY_PREFIX + oldest + SESSION_KEY_SUFFIX);
|
|
277
|
+
this.entries.delete(versionKey(SESSION_KEY_PREFIX + oldest + SESSION_KEY_SUFFIX));
|
|
278
|
+
ended.push(oldest);
|
|
279
|
+
}
|
|
280
|
+
members.set(sessionId, createdAtMs);
|
|
281
|
+
return ended;
|
|
282
|
+
}
|
|
283
|
+
async acquireLock(key, token, ttlMs) {
|
|
284
|
+
if (this.read(key) !== undefined) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
this.entries.set(key, { value: token, expiresAt: Date.now() + ttlMs });
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
async releaseLock(key, token) {
|
|
291
|
+
if (this.read(key) === token) {
|
|
292
|
+
this.entries.delete(key);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async renewLock(key, token, ttlMs) {
|
|
296
|
+
if (this.read(key) !== token) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
this.entries.set(key, { value: token, expiresAt: Date.now() + ttlMs });
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
async touchUserIndex(indexKey, sessionId, score) {
|
|
303
|
+
const members = this.indexes.get(indexKey);
|
|
304
|
+
if (members?.has(sessionId)) {
|
|
305
|
+
members.set(sessionId, score);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
async getValue(key) {
|
|
309
|
+
return this.read(key);
|
|
310
|
+
}
|
|
311
|
+
async putValue(key, value, ttlSeconds) {
|
|
312
|
+
this.write(key, value, ttlSeconds);
|
|
313
|
+
}
|
|
314
|
+
read(key) {
|
|
315
|
+
const entry = this.entries.get(key);
|
|
316
|
+
if (entry && entry.expiresAt <= Date.now()) {
|
|
317
|
+
this.entries.delete(key);
|
|
318
|
+
return undefined;
|
|
319
|
+
}
|
|
320
|
+
return entry?.value;
|
|
321
|
+
}
|
|
322
|
+
write(key, value, ttlSeconds) {
|
|
323
|
+
this.entries.set(key, { value, expiresAt: Date.now() + ttlSeconds * 1000 });
|
|
324
|
+
}
|
|
325
|
+
sweep() {
|
|
326
|
+
const now = Date.now();
|
|
327
|
+
for (const [key, entry] of this.entries) {
|
|
328
|
+
if (entry.expiresAt <= now) {
|
|
329
|
+
this.entries.delete(key);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// A session's keys put its id in a hash tag, so its JSON, version, lock and last response share one cluster slot.
|
|
335
|
+
const SESSION_KEY_PREFIX = "mapi.session.{";
|
|
336
|
+
const SESSION_KEY_SUFFIX = "}";
|
|
337
|
+
/** The store key of a session's JSON. */
|
|
338
|
+
export function sessionKey(sessionId) {
|
|
339
|
+
return SESSION_KEY_PREFIX + encodeURIComponent(sessionId) + SESSION_KEY_SUFFIX;
|
|
340
|
+
}
|
|
341
|
+
/** The `.last` value marking `requestId` as running. Always serialized the same way, so it can be compared as a string. */
|
|
342
|
+
function inProgressMarker(requestId) {
|
|
343
|
+
return JSON.stringify({ requestId });
|
|
344
|
+
}
|
|
345
|
+
function versionKey(key) {
|
|
346
|
+
return `${key}.version`;
|
|
347
|
+
}
|
|
348
|
+
function userIndexKey(userUid) {
|
|
349
|
+
return `mapi.session.user.${encodeURIComponent(userUid)}`;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Stores/loads `MapiSessionContext`s, keyed by the opaque session id that also becomes the `MapiContext` cookie
|
|
353
|
+
* value.
|
|
354
|
+
*
|
|
355
|
+
* Every load reads the shared store (Redis when a `cache` datastore is configured). An earlier version used
|
|
356
|
+
* `RedisCache`, whose per-process copy served a session without checking Redis, so with several replicas one pod
|
|
357
|
+
* could run ROPs against handles another pod had already changed. Saves are compare-and-set on `version`: when
|
|
358
|
+
* two requests on the same session overlap, the second save reports `"conflict"` instead of overwriting the
|
|
359
|
+
* first request's handles. `Execute` also holds the session's lock (`acquireLock`) while it runs, so an overlapping
|
|
360
|
+
* request is turned away before it has any side effects, and keeps its last response (`storeResponse`) so a retry of
|
|
361
|
+
* the same request is answered again instead of being run twice.
|
|
362
|
+
*/
|
|
363
|
+
export class MapiSessionManager {
|
|
364
|
+
init() {
|
|
365
|
+
this.store = this.redisClient ? new RedisMapiSessionStore(this.redisClient) : new MemoryMapiSessionStore();
|
|
366
|
+
this.handleDataStore = this.redisClient ? new RedisHandleDataStore(this.redisClient) : new MemoryHandleDataStore();
|
|
367
|
+
}
|
|
368
|
+
/** Creates a session for `userUid`, ending that user's least recently used sessions (and their stored handle data)
|
|
369
|
+
* if they already hold `MAX_SESSIONS_PER_USER`. */
|
|
370
|
+
async create(mailboxUid, userUid) {
|
|
371
|
+
const context = new MapiSessionContext({ mailboxUid, userUid });
|
|
372
|
+
await this.store.create(sessionKey(context.uid), JSON.stringify(context), SESSION_TTL_SECONDS);
|
|
373
|
+
const ended = await this.store.addToUserIndex(userIndexKey(userUid), encodeURIComponent(context.uid), Date.now(), MAX_SESSIONS_PER_USER, MAX_SESSION_LIFETIME_MS / 1000);
|
|
374
|
+
for (const id of ended) {
|
|
375
|
+
await this.deleteHandleData(decodeURIComponent(id));
|
|
376
|
+
}
|
|
377
|
+
return context;
|
|
378
|
+
}
|
|
379
|
+
/** Records that `session` was just used, so the per-user cap ends the least recently used session rather than the
|
|
380
|
+
* oldest one. */
|
|
381
|
+
async touch(session) {
|
|
382
|
+
await this.store.touchUserIndex(userIndexKey(session.userUid), encodeURIComponent(session.uid), Date.now());
|
|
383
|
+
}
|
|
384
|
+
/** Loads a session straight from the store. A session past `MAX_SESSION_LIFETIME_MS` is ended and treated as
|
|
385
|
+
* missing. */
|
|
386
|
+
async load(sessionId) {
|
|
387
|
+
const json = await this.store.get(sessionKey(sessionId));
|
|
388
|
+
if (!json) {
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
const session = JSON.parse(json);
|
|
392
|
+
if (Date.now() - Date.parse(session.createdAt) > MAX_SESSION_LIFETIME_MS) {
|
|
393
|
+
await this.destroy(sessionId);
|
|
394
|
+
return undefined;
|
|
395
|
+
}
|
|
396
|
+
return session;
|
|
397
|
+
}
|
|
398
|
+
/** Saves `context` only if nobody else saved it since it was loaded and it is within `MAX_SESSION_BYTES`,
|
|
399
|
+
* bumping its `version` on success. */
|
|
400
|
+
async save(context) {
|
|
401
|
+
const expected = context.version;
|
|
402
|
+
context.version = expected + 1;
|
|
403
|
+
const json = JSON.stringify(context);
|
|
404
|
+
const result = Buffer.byteLength(json) > MAX_SESSION_BYTES
|
|
405
|
+
? "tooBig"
|
|
406
|
+
: await this.store.compareAndSet(sessionKey(context.uid), expected, json, SESSION_TTL_SECONDS);
|
|
407
|
+
if (result !== "saved") {
|
|
408
|
+
context.version = expected;
|
|
409
|
+
}
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
/** Ends a session, deleting its stored handle data too. */
|
|
413
|
+
async destroy(sessionId) {
|
|
414
|
+
await this.store.delete(sessionKey(sessionId));
|
|
415
|
+
await this.deleteHandleData(sessionId);
|
|
416
|
+
}
|
|
417
|
+
/** Deletes every FastTransfer stream and write-stream chunk the session stored. Best effort: they expire anyway. */
|
|
418
|
+
async deleteHandleData(sessionId) {
|
|
419
|
+
await this.handleDataStore.deleteOwnedBy(sessionHandleDataIndex(sessionId)).catch(() => undefined);
|
|
420
|
+
}
|
|
421
|
+
/** Takes the session's `Execute` lock. Returns the token to release it with, or `undefined` while another
|
|
422
|
+
* request holds it. */
|
|
423
|
+
async acquireLock(sessionId) {
|
|
424
|
+
const token = crypto.randomUUID();
|
|
425
|
+
return (await this.store.acquireLock(`${sessionKey(sessionId)}.lock`, token, SESSION_LOCK_TTL_MS)) ? token : undefined;
|
|
426
|
+
}
|
|
427
|
+
async releaseLock(sessionId, token) {
|
|
428
|
+
await this.store.releaseLock(`${sessionKey(sessionId)}.lock`, token);
|
|
429
|
+
}
|
|
430
|
+
/** Extends the session's lock by another `SESSION_LOCK_TTL_MS`. `false` when `token` no longer holds it. */
|
|
431
|
+
async renewLock(sessionId, token) {
|
|
432
|
+
return this.store.renewLock(`${sessionKey(sessionId)}.lock`, token, SESSION_LOCK_TTL_MS);
|
|
433
|
+
}
|
|
434
|
+
/** The response last sent on this session if it answered `requestId`; `"inProgress"` while a request with that id
|
|
435
|
+
* is still running (or ran on a pod that died less than `SESSION_LOCK_TTL_MS` ago); otherwise `undefined`. */
|
|
436
|
+
async storedResponse(sessionId, requestId) {
|
|
437
|
+
const json = await this.store.getValue(`${sessionKey(sessionId)}.last`);
|
|
438
|
+
const stored = json ? JSON.parse(json) : undefined;
|
|
439
|
+
if (stored?.requestId !== requestId) {
|
|
440
|
+
return undefined;
|
|
441
|
+
}
|
|
442
|
+
return stored.body === undefined ? "inProgress" : Buffer.from(stored.body, "base64");
|
|
443
|
+
}
|
|
444
|
+
/** Records that `requestId` is running on this session, for `SESSION_LOCK_TTL_MS` (renewed along with the lock). A
|
|
445
|
+
* retry of it is then answered as busy instead of running a second time. */
|
|
446
|
+
async markInProgress(sessionId, requestId) {
|
|
447
|
+
await this.store.putValue(`${sessionKey(sessionId)}.last`, inProgressMarker(requestId), SESSION_LOCK_TTL_MS / 1000);
|
|
448
|
+
}
|
|
449
|
+
/** Extends the in-progress marker of `requestId` by another `SESSION_LOCK_TTL_MS`, only while it is still that marker:
|
|
450
|
+
* once the request's response (or anything else) has replaced it, nothing is written. `false` when it wasn't there. */
|
|
451
|
+
async renewInProgress(sessionId, requestId) {
|
|
452
|
+
// The lock scripts are exactly "extend/delete only while the value is still this one".
|
|
453
|
+
return this.store.renewLock(`${sessionKey(sessionId)}.last`, inProgressMarker(requestId), SESSION_LOCK_TTL_MS);
|
|
454
|
+
}
|
|
455
|
+
/** Drops the in-progress marker of `requestId` when it is still there (the request ended without storing a
|
|
456
|
+
* response), so a retry runs. Atomic, so it never deletes a response stored meanwhile. */
|
|
457
|
+
async clearInProgress(sessionId, requestId) {
|
|
458
|
+
await this.store.releaseLock(`${sessionKey(sessionId)}.last`, inProgressMarker(requestId));
|
|
459
|
+
}
|
|
460
|
+
/** Remembers `body` as this session's answer to `requestId`. Only the latest request is kept. */
|
|
461
|
+
async storeResponse(sessionId, requestId, body) {
|
|
462
|
+
await this.store.putValue(`${sessionKey(sessionId)}.last`, JSON.stringify({ requestId, body: body.toString("base64") }), SESSION_TTL_SECONDS);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
__decorate([
|
|
466
|
+
Redis("cache", false),
|
|
467
|
+
__metadata("design:type", Object)
|
|
468
|
+
], MapiSessionManager.prototype, "redisClient", void 0);
|
|
469
|
+
__decorate([
|
|
470
|
+
Init,
|
|
471
|
+
__metadata("design:type", Function),
|
|
472
|
+
__metadata("design:paramtypes", []),
|
|
473
|
+
__metadata("design:returntype", void 0)
|
|
474
|
+
], MapiSessionManager.prototype, "init", null);
|
|
475
|
+
//# sourceMappingURL=MapiSessionManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapiSessionManager.js","sourceRoot":"","sources":["../../src/MapiSessionManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { StringUtils } from "@rapidrest/core";
|
|
6
|
+
/**
|
|
7
|
+
* Mirrors `@rapidrest/service-core`'s private `ModelUtils.MAX_PATTERN_LENGTH`: a `regex(...)` query operand
|
|
8
|
+
* longer than this is rejected as a potential ReDoS pattern with `INVALID_REQUEST`. The check runs against the
|
|
9
|
+
* operand AFTER escaping, so a raw client term well under the limit can still exceed it once each regex
|
|
10
|
+
* metacharacter doubles in length.
|
|
11
|
+
*/
|
|
12
|
+
export const MAX_REGEX_PATTERN_LENGTH = 100;
|
|
13
|
+
/**
|
|
14
|
+
* Escapes `value` for a literal-substring `regex(...)` match, truncating the raw term (never mid-escape or
|
|
15
|
+
* mid-code-point) so the escaped result always fits `MAX_REGEX_PATTERN_LENGTH`. Matching on a prefix of an
|
|
16
|
+
* over-long search term still yields a superset of the full term's matches, which is a far better outcome than
|
|
17
|
+
* the whole command failing.
|
|
18
|
+
*/
|
|
19
|
+
export function boundedEscapedPattern(value, maxLength = MAX_REGEX_PATTERN_LENGTH) {
|
|
20
|
+
let pattern = "";
|
|
21
|
+
for (const char of value) {
|
|
22
|
+
const escaped = StringUtils.escapeRegExp(char);
|
|
23
|
+
if (pattern.length + escaped.length > maxLength) {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
pattern += escaped;
|
|
27
|
+
}
|
|
28
|
+
return pattern;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=RegexPatternUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RegexPatternUtils.js","sourceRoot":"","sources":["../../src/RegexPatternUtils.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa,EAAE,YAAoB,wBAAwB;IAC7F,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YAC9C,MAAM;QACV,CAAC;QACD,OAAO,IAAI,OAAO,CAAC;IACvB,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC"}
|