@harperfast/harper 5.0.0-alpha.10 → 5.0.0-beta.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/bin/BinObjects.js +17 -0
- package/bin/cliOperations.js +157 -0
- package/bin/copyDb.ts +280 -0
- package/bin/harper.js +156 -0
- package/bin/install.js +15 -0
- package/bin/lite.js +5 -0
- package/bin/restart.js +201 -0
- package/bin/run.js +409 -0
- package/bin/status.js +65 -0
- package/bin/stop.js +22 -0
- package/bin/upgrade.js +134 -0
- package/components/Application.ts +646 -0
- package/components/ApplicationScope.ts +49 -0
- package/components/Component.ts +53 -0
- package/components/ComponentV1.ts +342 -0
- package/components/DEFAULT_CONFIG.ts +18 -0
- package/components/EntryHandler.ts +227 -0
- package/components/Logger.ts +14 -0
- package/components/OptionsWatcher.ts +354 -0
- package/components/PluginModule.ts +6 -0
- package/components/Scope.ts +329 -0
- package/components/componentLoader.ts +529 -0
- package/components/deriveCommonPatternBase.ts +31 -0
- package/components/deriveGlobOptions.ts +44 -0
- package/components/deriveURLPath.ts +57 -0
- package/components/operations.js +658 -0
- package/components/operationsValidation.js +246 -0
- package/components/packageComponent.ts +39 -0
- package/components/requestRestart.ts +26 -0
- package/components/resolveBaseURLPath.ts +38 -0
- package/components/status/ComponentStatus.ts +110 -0
- package/components/status/ComponentStatusRegistry.ts +251 -0
- package/components/status/api.ts +153 -0
- package/components/status/crossThread.ts +405 -0
- package/components/status/errors.ts +152 -0
- package/components/status/index.ts +44 -0
- package/components/status/internal.ts +65 -0
- package/components/status/registry.ts +12 -0
- package/components/status/types.ts +96 -0
- package/config/RootConfigWatcher.ts +59 -0
- package/config/configHelpers.ts +11 -0
- package/config/configUtils.js +967 -0
- package/config/harperConfigEnvVars.ts +641 -0
- package/dataLayer/CreateAttributeObject.js +25 -0
- package/dataLayer/CreateTableObject.js +11 -0
- package/dataLayer/DataLayerObjects.js +43 -0
- package/dataLayer/DeleteBeforeObject.js +22 -0
- package/dataLayer/DeleteObject.js +25 -0
- package/dataLayer/DropAttributeObject.js +11 -0
- package/dataLayer/GetBackupObject.js +22 -0
- package/dataLayer/InsertObject.js +24 -0
- package/dataLayer/ReadAuditLogObject.js +24 -0
- package/dataLayer/SQLSearch.js +1335 -0
- package/dataLayer/SearchByConditionsObject.js +61 -0
- package/dataLayer/SearchByHashObject.js +21 -0
- package/dataLayer/SearchObject.js +45 -0
- package/dataLayer/SqlSearchObject.js +14 -0
- package/dataLayer/UpdateObject.js +23 -0
- package/dataLayer/UpsertObject.js +23 -0
- package/dataLayer/bulkLoad.js +813 -0
- package/dataLayer/dataObjects/BulkLoadObjects.js +27 -0
- package/dataLayer/dataObjects/UpsertObject.js +23 -0
- package/dataLayer/delete.js +164 -0
- package/dataLayer/export.js +381 -0
- package/dataLayer/getBackup.js +40 -0
- package/dataLayer/harperBridge/BridgeMethods.js +81 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +633 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateReturnObj.js +28 -0
- package/dataLayer/harperBridge/bridgeUtility/insertUpdateValidate.js +88 -0
- package/dataLayer/harperBridge/harperBridge.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/LMDBBridge.js +119 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.js +112 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateRecords.js +67 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateSchema.js +31 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateTable.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteAuditLogsBefore.js +98 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDeleteRecords.js +89 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropAttribute.js +109 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropSchema.js +107 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbDropTable.js +137 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbFlush.js +35 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetBackup.js +111 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByHash.js +28 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbGetDataByValue.js +29 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbReadAuditLog.js +207 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.js +156 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByHash.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.js +30 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbTransaction.js +19 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpdateRecords.js +64 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbUpsertRecords.js +70 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBDeleteTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBInsertTransactionObject.js +22 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBTransactionObject.js +23 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpdateTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBUpsertTransactionObject.js +24 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/TableSizeObject.js +25 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializeHashSearch.js +21 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/initializePaths.js +157 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCheckForNewAttributes.js +94 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbCreateTransactionsAuditEnvironment.js +39 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbGetTableSize.js +34 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbProcessRows.js +100 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbSearch.js +371 -0
- package/dataLayer/harperBridge/lmdbBridge/lmdbUtility/lmdbWriteTransaction.js +109 -0
- package/dataLayer/hdbInfoController.js +254 -0
- package/dataLayer/insert.js +266 -0
- package/dataLayer/readAuditLog.js +59 -0
- package/dataLayer/schema.js +366 -0
- package/dataLayer/schemaDescribe.js +289 -0
- package/dataLayer/search.js +60 -0
- package/dataLayer/transaction.js +17 -0
- package/dataLayer/update.js +124 -0
- package/dist/components/Logger.d.ts +12 -0
- package/dist/components/Logger.js +3 -0
- package/dist/components/Logger.js.map +1 -0
- package/dist/components/Scope.d.ts +14 -4
- package/dist/components/Scope.js +18 -10
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +16 -9
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/operations.js +2 -2
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +1 -1
- package/dist/config/configUtils.js +1 -1
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/CreateTableObject.d.ts +2 -2
- package/dist/dataLayer/CreateTableObject.js +2 -2
- package/dist/dataLayer/CreateTableObject.js.map +1 -1
- package/dist/dataLayer/delete.d.ts +1 -1
- package/dist/dataLayer/schema.js +6 -5
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +1 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resources/DatabaseTransaction.d.ts +1 -1
- package/dist/resources/IterableEventQueue.d.ts +1 -1
- package/dist/resources/LMDBTransaction.d.ts +5 -1
- package/dist/resources/Resource.d.ts +1 -1
- package/dist/resources/RocksIndexStore.d.ts +3 -3
- package/dist/resources/RocksTransactionLogStore.d.ts +6 -3
- package/dist/resources/Table.d.ts +15 -6
- package/dist/resources/Table.js +4 -1
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/read.js +32 -22
- package/dist/resources/analytics/read.js.map +1 -1
- package/dist/resources/analytics/write.js +3 -6
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +3 -3
- package/dist/resources/blob.d.ts +25 -2
- package/dist/resources/databases.d.ts +12 -2
- package/dist/resources/databases.js +22 -19
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/search.js +11 -5
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transaction.d.ts +2 -1
- package/dist/security/auth.js +1 -1
- package/dist/security/auth.js.map +1 -1
- package/dist/security/cryptoHash.d.ts +2 -2
- package/dist/security/jsLoader.js +243 -66
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +4 -5
- package/dist/security/keys.js.map +1 -1
- package/dist/security/user.js +3 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/REST.js +16 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/Server.d.ts +2 -1
- package/dist/server/Server.js.map +1 -1
- package/dist/server/fastifyRoutes/plugins/hdbCore.d.ts +6 -1
- package/dist/server/fastifyRoutes.js +2 -0
- package/dist/server/fastifyRoutes.js.map +1 -1
- package/dist/server/http.js +12 -6
- package/dist/server/http.js.map +1 -1
- package/dist/server/jobs/JobObject.d.ts +3 -3
- package/dist/server/loadRootComponents.js +1 -0
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/operationsServer.js +3 -1
- package/dist/server/operationsServer.js.map +1 -1
- package/dist/server/serverHelpers/JSONStream.d.ts +3 -3
- package/dist/server/serverHelpers/Request.d.ts +5 -5
- package/dist/server/serverHelpers/requestTimePlugin.d.ts +1 -1
- package/dist/server/threads/manageThreads.d.ts +2 -2
- package/dist/server/threads/manageThreads.js +50 -35
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -1
- package/dist/sqlTranslator/deleteTranslator.d.ts +1 -1
- package/dist/utility/AWS/AWSConnector.d.ts +3 -2
- package/dist/utility/common_utils.d.ts +3 -3
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/functions/date/dateFunctions.d.ts +11 -11
- package/dist/utility/globalSchema.d.ts +1 -1
- package/dist/utility/hdbTerms.d.ts +3 -0
- package/dist/utility/hdbTerms.js +3 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/installation.d.ts +2 -4
- package/dist/utility/installation.js.map +1 -1
- package/dist/utility/lmdb/commonUtility.d.ts +1 -0
- package/dist/utility/lmdb/deleteUtility.d.ts +1 -0
- package/dist/utility/lmdb/environmentUtility.d.ts +1 -0
- package/dist/utility/lmdb/searchUtility.d.ts +2 -1
- package/dist/utility/lmdb/writeUtility.d.ts +1 -0
- package/dist/utility/logging/harper_logger.d.ts +6 -6
- package/dist/utility/processManagement/processManagement.d.ts +1 -1
- package/dist/utility/processManagement/servicesConfig.d.ts +12 -6
- package/dist/validation/common_validators.d.ts +4 -3
- package/dist/validation/configValidator.d.ts +3 -2
- package/index.d.ts +56 -0
- package/index.js +41 -0
- package/json/systemSchema.json +373 -0
- package/launchServiceScripts/launchHarperDB.js +3 -0
- package/launchServiceScripts/utility/checkNodeVersion.js +15 -0
- package/package.json +21 -3
- package/resources/DatabaseTransaction.ts +378 -0
- package/resources/ErrorResource.ts +57 -0
- package/resources/IterableEventQueue.ts +94 -0
- package/resources/LMDBTransaction.ts +349 -0
- package/resources/RecordEncoder.ts +702 -0
- package/resources/RequestTarget.ts +134 -0
- package/resources/Resource.ts +789 -0
- package/resources/ResourceInterface.ts +221 -0
- package/resources/ResourceInterfaceV2.ts +53 -0
- package/resources/ResourceV2.ts +67 -0
- package/resources/Resources.ts +162 -0
- package/resources/RocksIndexStore.ts +70 -0
- package/resources/RocksTransactionLogStore.ts +352 -0
- package/resources/Table.ts +4527 -0
- package/resources/analytics/hostnames.ts +72 -0
- package/resources/analytics/metadata.ts +10 -0
- package/resources/analytics/read.ts +252 -0
- package/resources/analytics/write.ts +803 -0
- package/resources/auditStore.ts +556 -0
- package/resources/blob.ts +1268 -0
- package/resources/crdt.ts +125 -0
- package/resources/dataLoader.ts +527 -0
- package/resources/databases.ts +1290 -0
- package/resources/graphql.ts +221 -0
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +638 -0
- package/resources/indexes/customIndexes.ts +7 -0
- package/resources/indexes/vector.ts +38 -0
- package/resources/jsResource.ts +86 -0
- package/resources/loadEnv.ts +22 -0
- package/resources/login.ts +18 -0
- package/resources/openApi.ts +409 -0
- package/resources/registrationDeprecated.ts +8 -0
- package/resources/replayLogs.ts +136 -0
- package/resources/roles.ts +98 -0
- package/resources/search.ts +1301 -0
- package/resources/tracked.ts +584 -0
- package/resources/transaction.ts +89 -0
- package/resources/transactionBroadcast.ts +258 -0
- package/security/auth.ts +376 -0
- package/security/certificateVerification/certificateVerificationSource.ts +84 -0
- package/security/certificateVerification/configValidation.ts +107 -0
- package/security/certificateVerification/crlVerification.ts +623 -0
- package/security/certificateVerification/index.ts +121 -0
- package/security/certificateVerification/ocspVerification.ts +148 -0
- package/security/certificateVerification/pkijs-ed25519-patch.ts +188 -0
- package/security/certificateVerification/types.ts +128 -0
- package/security/certificateVerification/verificationConfig.ts +138 -0
- package/security/certificateVerification/verificationUtils.ts +447 -0
- package/security/cryptoHash.js +42 -0
- package/security/data_objects/PermissionAttributeResponseObject.js +15 -0
- package/security/data_objects/PermissionResponseObject.js +115 -0
- package/security/data_objects/PermissionTableResponseObject.js +20 -0
- package/security/fastifyAuth.js +169 -0
- package/security/impersonation.ts +160 -0
- package/security/jsLoader.ts +716 -0
- package/security/keys.js +948 -0
- package/security/permissionsTranslator.js +300 -0
- package/security/role.js +218 -0
- package/security/tokenAuthentication.ts +228 -0
- package/security/user.ts +449 -0
- package/server/DurableSubscriptionsSession.ts +503 -0
- package/server/REST.ts +407 -0
- package/server/Server.ts +89 -0
- package/server/fastifyRoutes/helpers/getCORSOptions.js +36 -0
- package/server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js +15 -0
- package/server/fastifyRoutes/helpers/getServerOptions.js +33 -0
- package/server/fastifyRoutes/plugins/hdbCore.js +39 -0
- package/server/fastifyRoutes.ts +205 -0
- package/server/graphqlQuerying.ts +700 -0
- package/server/http.ts +640 -0
- package/server/itc/serverHandlers.js +161 -0
- package/server/itc/utility/ITCEventObject.js +10 -0
- package/server/jobs/JobObject.js +24 -0
- package/server/jobs/jobProcess.js +69 -0
- package/server/jobs/jobRunner.js +162 -0
- package/server/jobs/jobs.js +304 -0
- package/server/loadRootComponents.js +44 -0
- package/server/mqtt.ts +485 -0
- package/server/nodeName.ts +75 -0
- package/server/operationsServer.ts +313 -0
- package/server/serverHelpers/Headers.ts +108 -0
- package/server/serverHelpers/JSONStream.ts +269 -0
- package/server/serverHelpers/OperationFunctionObject.ts +13 -0
- package/server/serverHelpers/Request.ts +158 -0
- package/server/serverHelpers/contentTypes.ts +637 -0
- package/server/serverHelpers/requestTimePlugin.js +57 -0
- package/server/serverHelpers/serverHandlers.js +148 -0
- package/server/serverHelpers/serverUtilities.ts +473 -0
- package/server/serverRegistry.ts +8 -0
- package/server/static.ts +187 -0
- package/server/status/definitions.ts +37 -0
- package/server/status/index.ts +125 -0
- package/server/storageReclamation.ts +93 -0
- package/server/threads/itc.js +89 -0
- package/server/threads/manageThreads.js +594 -0
- package/server/threads/socketRouter.ts +360 -0
- package/server/threads/threadServer.js +279 -0
- package/server/throttle.ts +73 -0
- package/sqlTranslator/SelectValidator.js +330 -0
- package/sqlTranslator/alasqlFunctionImporter.js +62 -0
- package/sqlTranslator/deleteTranslator.js +67 -0
- package/sqlTranslator/index.js +242 -0
- package/sqlTranslator/sql_statement_bucket.js +472 -0
- package/static/defaultConfig.yaml +3 -0
- package/studio/web/HDBDogOnly.svg +78 -0
- package/studio/web/assets/PPRadioGrotesk-Bold-DDaUYG8E.woff +0 -0
- package/studio/web/assets/fa-brands-400-CEJbCg16.woff +0 -0
- package/studio/web/assets/fa-brands-400-CSYNqBb_.ttf +0 -0
- package/studio/web/assets/fa-brands-400-DnkPfk3o.eot +0 -0
- package/studio/web/assets/fa-brands-400-UxlILjvJ.woff2 +0 -0
- package/studio/web/assets/fa-brands-400-cH1MgKbP.svg +3717 -0
- package/studio/web/assets/fa-regular-400-BhTwtT8w.eot +0 -0
- package/studio/web/assets/fa-regular-400-D1vz6WBx.ttf +0 -0
- package/studio/web/assets/fa-regular-400-DFnMcJPd.woff +0 -0
- package/studio/web/assets/fa-regular-400-DGzu1beS.woff2 +0 -0
- package/studio/web/assets/fa-regular-400-gwj8Pxq-.svg +801 -0
- package/studio/web/assets/fa-solid-900-B4ZZ7kfP.svg +5034 -0
- package/studio/web/assets/fa-solid-900-B6Axprfb.eot +0 -0
- package/studio/web/assets/fa-solid-900-BUswJgRo.woff2 +0 -0
- package/studio/web/assets/fa-solid-900-DOXgCApm.woff +0 -0
- package/studio/web/assets/fa-solid-900-mxuxnBEa.ttf +0 -0
- package/studio/web/assets/index-BTgXJX9d.js +235 -0
- package/studio/web/assets/index-BTgXJX9d.js.map +1 -0
- package/studio/web/assets/index-C-GXfcup.js +37 -0
- package/studio/web/assets/index-C-GXfcup.js.map +1 -0
- package/studio/web/assets/index-PFlNdimM.js +2 -0
- package/studio/web/assets/index-PFlNdimM.js.map +1 -0
- package/studio/web/assets/index-Y2g_iFpU.css +1 -0
- package/studio/web/assets/index-jiPwkrsB.css +1 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js +266 -0
- package/studio/web/assets/index.lazy-C3TJZJ4o.js.map +1 -0
- package/studio/web/assets/profiler-DotzgiCJ.js +2 -0
- package/studio/web/assets/profiler-DotzgiCJ.js.map +1 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js +6 -0
- package/studio/web/assets/react-redux-VxUEx_mU.js.map +1 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js +3 -0
- package/studio/web/assets/startRecording-B_9J9Csd.js.map +1 -0
- package/studio/web/fabric-signup-background.webp +0 -0
- package/studio/web/fabric-signup-text.png +0 -0
- package/studio/web/favicon_purple.png +0 -0
- package/studio/web/github-icon.svg +15 -0
- package/studio/web/harper-fabric_black.png +0 -0
- package/studio/web/harper-fabric_white.png +0 -0
- package/studio/web/harper-studio_white.png +0 -0
- package/studio/web/index.html +16 -0
- package/studio/web/running.css +148 -0
- package/studio/web/running.html +147 -0
- package/studio/web/running.js +111 -0
- package/upgrade/UpgradeObjects.js +13 -0
- package/upgrade/directives/directivesController.js +90 -0
- package/upgrade/directivesManager.js +139 -0
- package/upgrade/upgradePrompt.js +124 -0
- package/upgrade/upgradeUtilities.js +28 -0
- package/utility/AWS/AWSConnector.js +29 -0
- package/utility/OperationFunctionCaller.js +63 -0
- package/utility/assignCmdEnvVariables.js +62 -0
- package/utility/common_utils.js +867 -0
- package/utility/environment/environmentManager.js +208 -0
- package/utility/environment/systemInformation.js +355 -0
- package/utility/errors/commonErrors.js +267 -0
- package/utility/errors/hdbError.js +146 -0
- package/utility/functions/date/dateFunctions.js +65 -0
- package/utility/functions/geo.js +355 -0
- package/utility/functions/sql/alaSQLExtension.js +104 -0
- package/utility/globalSchema.js +35 -0
- package/utility/hdbTerms.ts +819 -0
- package/utility/install/checkJWTTokensExist.js +62 -0
- package/utility/install/harperdb.conf +15 -0
- package/utility/install/harperdb.service +14 -0
- package/utility/install/installer.js +635 -0
- package/utility/installation.ts +30 -0
- package/utility/lmdb/DBIDefinition.js +20 -0
- package/utility/lmdb/DeleteRecordsResponseObject.js +25 -0
- package/utility/lmdb/InsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/OpenDBIObject.js +31 -0
- package/utility/lmdb/OpenEnvironmentObject.js +41 -0
- package/utility/lmdb/UpdateRecordsResponseObject.js +25 -0
- package/utility/lmdb/UpsertRecordsResponseObject.js +22 -0
- package/utility/lmdb/cleanLMDBMap.js +65 -0
- package/utility/lmdb/commonUtility.js +119 -0
- package/utility/lmdb/deleteUtility.js +128 -0
- package/utility/lmdb/environmentUtility.js +477 -0
- package/utility/lmdb/searchCursorFunctions.js +187 -0
- package/utility/lmdb/searchUtility.js +918 -0
- package/utility/lmdb/terms.js +57 -0
- package/utility/lmdb/writeUtility.js +407 -0
- package/utility/logging/harper_logger.js +876 -0
- package/utility/logging/logRotator.js +157 -0
- package/utility/logging/logger.ts +24 -0
- package/utility/logging/readLog.js +355 -0
- package/utility/logging/transactionLog.js +57 -0
- package/utility/mount_hdb.js +59 -0
- package/utility/npmUtilities.js +102 -0
- package/utility/operationPermissions.ts +112 -0
- package/utility/operation_authorization.js +836 -0
- package/utility/packageUtils.js +55 -0
- package/utility/password.ts +99 -0
- package/utility/processManagement/processManagement.js +187 -0
- package/utility/processManagement/servicesConfig.js +56 -0
- package/utility/scripts/restartHdb.js +24 -0
- package/utility/scripts/user_data.sh +13 -0
- package/utility/signalling.js +36 -0
- package/utility/terms/certificates.js +81 -0
- package/utility/when.ts +20 -0
- package/v1.d.ts +39 -0
- package/v1.js +41 -0
- package/v2.d.ts +39 -0
- package/v2.js +41 -0
- package/validation/bulkDeleteValidator.js +24 -0
- package/validation/check_permissions.js +19 -0
- package/validation/common_validators.js +95 -0
- package/validation/configValidator.js +331 -0
- package/validation/deleteValidator.js +15 -0
- package/validation/fileLoadValidator.js +153 -0
- package/validation/insertValidator.js +40 -0
- package/validation/installValidator.js +37 -0
- package/validation/readLogValidator.js +64 -0
- package/validation/role_validation.js +320 -0
- package/validation/schemaMetadataValidator.js +42 -0
- package/validation/searchValidator.js +166 -0
- package/validation/statusValidator.ts +66 -0
- package/validation/transactionLogValidator.js +33 -0
- package/validation/user_validation.js +55 -0
- package/validation/validationWrapper.js +105 -0
- package/dist/resources/analytics/profile.d.ts +0 -2
- package/dist/resources/analytics/profile.js +0 -144
- package/dist/resources/analytics/profile.js.map +0 -1
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
import { Resource } from '../resources/Resource.ts';
|
|
2
|
+
import { contextStorage, transaction } from '../resources/transaction.ts';
|
|
3
|
+
import { RequestTarget } from '../resources/RequestTarget.ts';
|
|
4
|
+
import { tables, databases } from '../resources/databases.ts';
|
|
5
|
+
import { readFile } from 'node:fs/promises';
|
|
6
|
+
import { dirname, isAbsolute } from 'node:path';
|
|
7
|
+
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
8
|
+
import { SourceTextModule, SyntheticModule, createContext, runInContext } from 'node:vm';
|
|
9
|
+
import { ApplicationScope } from '../components/ApplicationScope.ts';
|
|
10
|
+
import logger from '../utility/logging/harper_logger.js';
|
|
11
|
+
import { createRequire } from 'node:module';
|
|
12
|
+
import * as env from '../utility/environment/environmentManager';
|
|
13
|
+
import * as child_process from 'node:child_process';
|
|
14
|
+
import { CONFIG_PARAMS } from '../utility/hdbTerms.ts';
|
|
15
|
+
import { contentTypes } from '../server/serverHelpers/contentTypes.ts';
|
|
16
|
+
import type { CompartmentOptions } from 'ses';
|
|
17
|
+
import { mkdirSync, readFileSync, writeFileSync, unlinkSync, openSync, closeSync, statSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { EventEmitter } from 'node:events';
|
|
20
|
+
|
|
21
|
+
type Lockdown = 'none' | 'freeze' | 'ses';
|
|
22
|
+
const APPLICATIONS_LOCKDOWN: Lockdown = env.get(CONFIG_PARAMS.APPLICATIONS_LOCKDOWN);
|
|
23
|
+
|
|
24
|
+
let lockedDown = false;
|
|
25
|
+
/**
|
|
26
|
+
* This is the main entry point for loading plugin and application modules that may be executed in a
|
|
27
|
+
* separate top level scope. The scope indicates if we use a different top level scope or a standard import.
|
|
28
|
+
* @param moduleUrl
|
|
29
|
+
* @param scope
|
|
30
|
+
*/
|
|
31
|
+
export async function scopedImport(filePath: string | URL, scope?: ApplicationScope) {
|
|
32
|
+
if (!lockedDown && APPLICATIONS_LOCKDOWN && APPLICATIONS_LOCKDOWN !== 'none') {
|
|
33
|
+
lockedDown = true;
|
|
34
|
+
if (APPLICATIONS_LOCKDOWN === 'ses') {
|
|
35
|
+
require('ses'); // load the lockdown function
|
|
36
|
+
lockdown({
|
|
37
|
+
domainTaming: 'unsafe',
|
|
38
|
+
consoleTaming: 'unsafe',
|
|
39
|
+
errorTaming: 'unsafe',
|
|
40
|
+
errorTrapping: 'none',
|
|
41
|
+
stackFiltering: 'verbose',
|
|
42
|
+
});
|
|
43
|
+
} else {
|
|
44
|
+
preventFunctionConstructor();
|
|
45
|
+
for (let name of Object.getOwnPropertyNames(Object.prototype)) {
|
|
46
|
+
if (name === '__proto__') continue;
|
|
47
|
+
overridableProperty(Object.prototype, name);
|
|
48
|
+
}
|
|
49
|
+
overridableProperty(Promise.prototype, 'then');
|
|
50
|
+
overridableProperty(Date, 'now');
|
|
51
|
+
for (let Intrinsic of [
|
|
52
|
+
Object,
|
|
53
|
+
Array,
|
|
54
|
+
Promise,
|
|
55
|
+
BigInt,
|
|
56
|
+
String,
|
|
57
|
+
Number,
|
|
58
|
+
Boolean,
|
|
59
|
+
Symbol,
|
|
60
|
+
RegExp,
|
|
61
|
+
Date,
|
|
62
|
+
Map,
|
|
63
|
+
Set,
|
|
64
|
+
WeakMap,
|
|
65
|
+
WeakSet,
|
|
66
|
+
Math,
|
|
67
|
+
JSON,
|
|
68
|
+
Reflect,
|
|
69
|
+
Atomics,
|
|
70
|
+
SharedArrayBuffer,
|
|
71
|
+
WeakRef,
|
|
72
|
+
FinalizationRegistry,
|
|
73
|
+
]) {
|
|
74
|
+
Object.freeze(Intrinsic);
|
|
75
|
+
Object.freeze(Intrinsic.prototype);
|
|
76
|
+
}
|
|
77
|
+
Object.freeze(Function);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const moduleUrl = (filePath instanceof URL ? filePath : pathToFileURL(filePath)).toString();
|
|
81
|
+
try {
|
|
82
|
+
const containmentMode = scope?.mode;
|
|
83
|
+
if (scope && containmentMode !== 'none') {
|
|
84
|
+
if (containmentMode === 'compartment') {
|
|
85
|
+
// use SES Compartments
|
|
86
|
+
// note that we use a single compartment per scope and we load it on-demand, only
|
|
87
|
+
// loading if necessary (since it is actually very heavy)
|
|
88
|
+
const globals = getGlobalObject(scope);
|
|
89
|
+
if (!scope.compartment) scope.compartment = getCompartment(scope, globals);
|
|
90
|
+
const result = await (await scope.compartment).import(moduleUrl);
|
|
91
|
+
return result.namespace;
|
|
92
|
+
} // else use standard node:vm module to do containment
|
|
93
|
+
return await loadModuleWithVM(moduleUrl, scope);
|
|
94
|
+
} else {
|
|
95
|
+
// important! we need to await the import, otherwise the error will not be caught
|
|
96
|
+
return await import(moduleUrl);
|
|
97
|
+
}
|
|
98
|
+
} catch (err) {
|
|
99
|
+
try {
|
|
100
|
+
// the actual parse error (internally known as the "arrow message")
|
|
101
|
+
// is hidden behind a private symbol (arrowMessagePrivateSymbol)
|
|
102
|
+
// on the error object and the only way to access it is to use the
|
|
103
|
+
// internal util.decorateErrorStack() function
|
|
104
|
+
const util = await import('internal/util');
|
|
105
|
+
util.default.decorateErrorStack(err);
|
|
106
|
+
} catch {
|
|
107
|
+
// maybe --expose-internals was not set?
|
|
108
|
+
}
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Load a module using Node's vm.Module API with (not really secure) sandboxing
|
|
115
|
+
*/
|
|
116
|
+
async function loadModuleWithVM(moduleUrl: string, scope: ApplicationScope) {
|
|
117
|
+
const moduleCache = new Map<string, SourceTextModule | SyntheticModule>();
|
|
118
|
+
const linkingPromises = new Map<string, Promise<void>>();
|
|
119
|
+
|
|
120
|
+
// Create a secure context with limited globals
|
|
121
|
+
const contextObject = getGlobalObject(scope);
|
|
122
|
+
const context = createContext(contextObject);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Resolve module specifier to absolute URL
|
|
126
|
+
*/
|
|
127
|
+
function resolveModule(specifier: string, referrer: string): string {
|
|
128
|
+
if (specifier === 'harperdb' || specifier === 'harper') return 'harper';
|
|
129
|
+
if (specifier.startsWith('harper/') || specifier.startsWith('harperdb/')) {
|
|
130
|
+
throw new Error(`Module ${specifier} is not allowed, may only access the 'harper' module`);
|
|
131
|
+
}
|
|
132
|
+
if (specifier.startsWith('file://')) {
|
|
133
|
+
return specifier;
|
|
134
|
+
}
|
|
135
|
+
// For relative paths, resolve to absolute file URL
|
|
136
|
+
if (specifier.startsWith('.')) {
|
|
137
|
+
const resolved = createRequire(referrer).resolve(specifier);
|
|
138
|
+
if (isAbsolute(resolved)) {
|
|
139
|
+
return pathToFileURL(resolved).toString();
|
|
140
|
+
}
|
|
141
|
+
return resolved;
|
|
142
|
+
}
|
|
143
|
+
// For package names and node: specifiers, keep as-is for proper require() handling
|
|
144
|
+
return specifier;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Load a CommonJS module in our private context
|
|
149
|
+
*/
|
|
150
|
+
function loadCJS(url: string, source: string): { exports: any } {
|
|
151
|
+
const cjsModule = { exports: {} };
|
|
152
|
+
if (url.endsWith('.json')) {
|
|
153
|
+
cjsModule.exports = JSON.parse(source);
|
|
154
|
+
return cjsModule;
|
|
155
|
+
}
|
|
156
|
+
const require = createRequire(url);
|
|
157
|
+
|
|
158
|
+
const cjsRequire = (spec: string) => {
|
|
159
|
+
const resolvedPath = require.resolve(spec);
|
|
160
|
+
if (isAbsolute(resolvedPath)) {
|
|
161
|
+
const source = readFileSync(resolvedPath, { encoding: 'utf-8' });
|
|
162
|
+
return loadCJS(resolvedPath, source).exports;
|
|
163
|
+
} else {
|
|
164
|
+
return require(spec);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
cjsRequire.resolve = require.resolve;
|
|
168
|
+
|
|
169
|
+
const cjsWrapper = `
|
|
170
|
+
(function(module, exports, require, __filename, __dirname) {
|
|
171
|
+
${source}
|
|
172
|
+
})
|
|
173
|
+
`;
|
|
174
|
+
|
|
175
|
+
const wrappedFn = runInContext(cjsWrapper, contextObject, {
|
|
176
|
+
filename: url,
|
|
177
|
+
async importModuleDynamically(specifier: string, script) {
|
|
178
|
+
const resolvedUrl = resolveModule(specifier, script.sourceURL);
|
|
179
|
+
const useContainment = specifier.startsWith('.') || scope.dependencyContainment;
|
|
180
|
+
const dynamicModule = await loadModuleWithCache(resolvedUrl, useContainment);
|
|
181
|
+
return dynamicModule;
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
wrappedFn(
|
|
185
|
+
cjsModule,
|
|
186
|
+
cjsModule.exports,
|
|
187
|
+
cjsRequire,
|
|
188
|
+
url,
|
|
189
|
+
dirname(url.startsWith('file://') ? fileURLToPath(url) : url)
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
return cjsModule;
|
|
193
|
+
}
|
|
194
|
+
function loadCJSModule(url: string, source: string, usePrivateGlobal: boolean): SyntheticModule {
|
|
195
|
+
const cjsModule = usePrivateGlobal ? loadCJS(url, source) : { exports: require(url) };
|
|
196
|
+
const exportNames = Object.keys(cjsModule.exports);
|
|
197
|
+
const synModule = new SyntheticModule(
|
|
198
|
+
exportNames.length > 0 ? exportNames : ['default'],
|
|
199
|
+
function () {
|
|
200
|
+
if (exportNames.length > 0) {
|
|
201
|
+
for (const key of exportNames) {
|
|
202
|
+
this.setExport(key, cjsModule.exports[key]);
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
this.setExport('default', cjsModule.exports);
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
{ identifier: url, context }
|
|
209
|
+
);
|
|
210
|
+
moduleCache.set(url, synModule);
|
|
211
|
+
return synModule;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Linker function for module resolution during instantiation
|
|
216
|
+
*/
|
|
217
|
+
async function linker(specifier: string, referencingModule: SourceTextModule | SyntheticModule) {
|
|
218
|
+
const resolvedUrl = resolveModule(specifier, referencingModule.identifier);
|
|
219
|
+
|
|
220
|
+
const useContainment = specifier.startsWith('.') || scope.dependencyContainment;
|
|
221
|
+
// Return the module immediately (even if not yet linked) to support circular dependencies
|
|
222
|
+
return await getOrCreateModule(resolvedUrl, useContainment);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async function getOrCreateModule(
|
|
226
|
+
url: string,
|
|
227
|
+
usePrivateGlobal: boolean
|
|
228
|
+
): Promise<SourceTextModule | SyntheticModule> {
|
|
229
|
+
// Check cache first - return cached module immediately (even if not linked yet)
|
|
230
|
+
if (moduleCache.has(url)) {
|
|
231
|
+
return moduleCache.get(url)!;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Create the module and cache it immediately (before linking)
|
|
235
|
+
const module = await createModule(url, usePrivateGlobal);
|
|
236
|
+
moduleCache.set(url, module);
|
|
237
|
+
|
|
238
|
+
return module;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function loadModuleWithCache(
|
|
242
|
+
url: string,
|
|
243
|
+
usePrivateGlobal: boolean
|
|
244
|
+
): Promise<SourceTextModule | SyntheticModule> {
|
|
245
|
+
const module = await getOrCreateModule(url, usePrivateGlobal);
|
|
246
|
+
|
|
247
|
+
// Only link/evaluate once per module
|
|
248
|
+
if (!linkingPromises.has(url)) {
|
|
249
|
+
linkingPromises.set(
|
|
250
|
+
url,
|
|
251
|
+
module.link(linker).then(() => module.evaluate())
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Wait for linking to complete
|
|
256
|
+
await linkingPromises.get(url);
|
|
257
|
+
|
|
258
|
+
return module;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Create a module from URL without linking or evaluating
|
|
262
|
+
*/
|
|
263
|
+
async function createModule(url: string, usePrivateGlobal: boolean): Promise<SourceTextModule | SyntheticModule> {
|
|
264
|
+
let module: SourceTextModule | SyntheticModule;
|
|
265
|
+
|
|
266
|
+
// Handle special built-in modules
|
|
267
|
+
if (url === 'harper' || url === 'harperdb') {
|
|
268
|
+
let harperExports = getHarperExports(scope);
|
|
269
|
+
module = new SyntheticModule(
|
|
270
|
+
Object.keys(harperExports),
|
|
271
|
+
function () {
|
|
272
|
+
for (let key in harperExports) {
|
|
273
|
+
this.setExport(key, harperExports[key]);
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
{ identifier: url, context }
|
|
277
|
+
);
|
|
278
|
+
} else if (url.startsWith('file://')) {
|
|
279
|
+
checkAllowedModulePath(url, scope.verifyPath);
|
|
280
|
+
// Load source text from file
|
|
281
|
+
const source = await readFile(new URL(url), { encoding: 'utf-8' });
|
|
282
|
+
|
|
283
|
+
// Try to parse as ESM first
|
|
284
|
+
try {
|
|
285
|
+
module = new SourceTextModule(source, {
|
|
286
|
+
identifier: url,
|
|
287
|
+
context,
|
|
288
|
+
initializeImportMeta(meta) {
|
|
289
|
+
meta.url = url;
|
|
290
|
+
},
|
|
291
|
+
async importModuleDynamically(specifier: string) {
|
|
292
|
+
const resolvedUrl = resolveModule(specifier, url);
|
|
293
|
+
const dynamicModule = await loadModuleWithCache(resolvedUrl, true);
|
|
294
|
+
return dynamicModule;
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
} catch (err) {
|
|
298
|
+
// If ESM parsing fails, try to load as CommonJS
|
|
299
|
+
if (
|
|
300
|
+
err.message?.includes('require is not defined') ||
|
|
301
|
+
source.includes('module.exports') ||
|
|
302
|
+
source.includes('exports.')
|
|
303
|
+
) {
|
|
304
|
+
module = loadCJSModule(url, source, usePrivateGlobal);
|
|
305
|
+
} else {
|
|
306
|
+
throw err;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
const replacedModule = checkAllowedModulePath(url, scope.verifyPath);
|
|
311
|
+
// For Node.js built-in modules (node:) and npm packages
|
|
312
|
+
// Always try require first to properly handle CJS modules with named exports
|
|
313
|
+
try {
|
|
314
|
+
const cjsExports = replacedModule ?? require(url);
|
|
315
|
+
// It's a CJS module - expose all properties as named exports
|
|
316
|
+
const exportNames = Object.keys(cjsExports);
|
|
317
|
+
module = new SyntheticModule(
|
|
318
|
+
exportNames.length > 0 ? [...exportNames, 'default'] : ['default'],
|
|
319
|
+
function () {
|
|
320
|
+
if (exportNames.length > 0) {
|
|
321
|
+
for (const key of exportNames) {
|
|
322
|
+
this.setExport(key, cjsExports[key]);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
this.setExport('default', cjsExports);
|
|
326
|
+
},
|
|
327
|
+
{ identifier: url, context }
|
|
328
|
+
);
|
|
329
|
+
} catch {
|
|
330
|
+
// Fall back to dynamic import for ESM packages
|
|
331
|
+
const importedModule = await import(url);
|
|
332
|
+
const exportNames = Object.keys(importedModule);
|
|
333
|
+
module = new SyntheticModule(
|
|
334
|
+
exportNames,
|
|
335
|
+
function () {
|
|
336
|
+
for (const key of exportNames) {
|
|
337
|
+
this.setExport(key, importedModule[key]);
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
{ identifier: url, context }
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return module;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Load the entry module
|
|
349
|
+
const entryModule = await loadModuleWithCache(moduleUrl, true);
|
|
350
|
+
|
|
351
|
+
// Return the module namespace (exports)
|
|
352
|
+
return entryModule.namespace;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async function getCompartment(scope: ApplicationScope, globals) {
|
|
356
|
+
const { StaticModuleRecord } = await import('@endo/static-module-record');
|
|
357
|
+
require('ses');
|
|
358
|
+
const compartment: CompartmentOptions = new (Compartment as typeof CompartmentOptions)(
|
|
359
|
+
globals,
|
|
360
|
+
{
|
|
361
|
+
//harperdb: { Resource, tables, databases }
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: 'harper-app',
|
|
365
|
+
resolveHook(moduleSpecifier, moduleReferrer) {
|
|
366
|
+
if (moduleSpecifier === 'harperdb' || moduleSpecifier === 'harper') return 'harper';
|
|
367
|
+
const resolved = createRequire(moduleReferrer).resolve(moduleSpecifier);
|
|
368
|
+
if (isAbsolute(resolved)) {
|
|
369
|
+
const resolvedURL = pathToFileURL(resolved).toString();
|
|
370
|
+
return resolvedURL;
|
|
371
|
+
}
|
|
372
|
+
return moduleSpecifier;
|
|
373
|
+
},
|
|
374
|
+
importHook: async (moduleSpecifier) => {
|
|
375
|
+
if (moduleSpecifier === 'harper') {
|
|
376
|
+
const harperExports = getHarperExports(scope);
|
|
377
|
+
return {
|
|
378
|
+
imports: [],
|
|
379
|
+
exports: Object.keys(harperExports),
|
|
380
|
+
execute(exports) {
|
|
381
|
+
Object.assign(exports, harperExports);
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
} else if (moduleSpecifier.startsWith('file:') && !moduleSpecifier.includes('node_modules')) {
|
|
385
|
+
const moduleText = await readFile(new URL(moduleSpecifier), { encoding: 'utf-8' });
|
|
386
|
+
return new StaticModuleRecord(moduleText, moduleSpecifier);
|
|
387
|
+
} else {
|
|
388
|
+
checkAllowedModulePath(moduleSpecifier, scope.verifyPath);
|
|
389
|
+
const moduleExports = await import(moduleSpecifier);
|
|
390
|
+
return {
|
|
391
|
+
imports: [],
|
|
392
|
+
exports: Object.keys(moduleExports),
|
|
393
|
+
execute(exports) {
|
|
394
|
+
for (const key of Object.keys(moduleExports)) {
|
|
395
|
+
exports[key] = moduleExports[key];
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
}
|
|
402
|
+
);
|
|
403
|
+
return compartment;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* This a constrained fetch. It certainly is not guaranteed to be safe, but requiring https may
|
|
408
|
+
* be a good heuristic for preventing access to unsecured resources within a private network.
|
|
409
|
+
* @param resource
|
|
410
|
+
* @param options
|
|
411
|
+
*/
|
|
412
|
+
function secureOnlyFetch(resource, options) {
|
|
413
|
+
// TODO: or maybe we should constrain by doing a DNS lookup and having disallow list of IP addresses that includes
|
|
414
|
+
// this server
|
|
415
|
+
const url = typeof resource === 'string' || resource.url;
|
|
416
|
+
if (new URL(url).protocol != 'https') throw new Error('Only https is allowed in fetch');
|
|
417
|
+
return fetch(resource, options);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
let defaultJSGlobalNames: string[];
|
|
421
|
+
// get the global variable names that are intrinsically present in a VM context (so we don't override them)
|
|
422
|
+
function getDefaultJSGlobalNames() {
|
|
423
|
+
if (!defaultJSGlobalNames) {
|
|
424
|
+
defaultJSGlobalNames = runInContext(
|
|
425
|
+
'Object.getOwnPropertyNames((function() { return this })())',
|
|
426
|
+
createContext({})
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
return defaultJSGlobalNames;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Get the set of global variables that should be available to modules that run in scoped compartments/contexts.
|
|
434
|
+
*/
|
|
435
|
+
function getGlobalObject(scope: ApplicationScope) {
|
|
436
|
+
const appGlobal = {};
|
|
437
|
+
// create the new global object, assigning all the global variables from this global
|
|
438
|
+
// except those that will be natural intrinsics of the new VM
|
|
439
|
+
for (let name of Object.getOwnPropertyNames(global)) {
|
|
440
|
+
if (getDefaultJSGlobalNames().includes(name)) continue;
|
|
441
|
+
appGlobal[name] = global[name];
|
|
442
|
+
}
|
|
443
|
+
// now assign Harper scope-specific variables
|
|
444
|
+
Object.assign(appGlobal, {
|
|
445
|
+
server: scope.server ?? server,
|
|
446
|
+
logger: scope.logger ?? logger,
|
|
447
|
+
resources: scope.resources,
|
|
448
|
+
config: scope.config ?? {},
|
|
449
|
+
fetch: APPLICATIONS_LOCKDOWN === 'ses' ? secureOnlyFetch : fetch,
|
|
450
|
+
console,
|
|
451
|
+
global: appGlobal,
|
|
452
|
+
harper: getHarperExports(scope),
|
|
453
|
+
});
|
|
454
|
+
return appGlobal;
|
|
455
|
+
}
|
|
456
|
+
function getHarperExports(scope: ApplicationScope) {
|
|
457
|
+
return {
|
|
458
|
+
server: scope.server ?? server,
|
|
459
|
+
logger: scope.logger ?? logger,
|
|
460
|
+
resources: scope.resources,
|
|
461
|
+
config: scope.config ?? {},
|
|
462
|
+
Resource,
|
|
463
|
+
tables,
|
|
464
|
+
databases,
|
|
465
|
+
createBlob,
|
|
466
|
+
RequestTarget,
|
|
467
|
+
getContext,
|
|
468
|
+
transaction,
|
|
469
|
+
getResponse,
|
|
470
|
+
getUser,
|
|
471
|
+
authenticateUser: server.authenticateUser,
|
|
472
|
+
operation: server.operation,
|
|
473
|
+
contentTypes,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
const ALLOWED_NODE_BUILTIN_MODULES = env.get(CONFIG_PARAMS.APPLICATIONS_ALLOWEDBUILTINMODULES)
|
|
477
|
+
? new Set(env.get(CONFIG_PARAMS.APPLICATIONS_ALLOWEDBUILTINMODULES))
|
|
478
|
+
: {
|
|
479
|
+
// if we don't have a list of allowed modules, allow everything
|
|
480
|
+
has() {
|
|
481
|
+
return true;
|
|
482
|
+
},
|
|
483
|
+
};
|
|
484
|
+
const ALLOWED_COMMANDS = new Set(env.get(CONFIG_PARAMS.APPLICATIONS_ALLOWEDSPAWNCOMMANDS) ?? []);
|
|
485
|
+
const REPLACED_BUILTIN_MODULES = {
|
|
486
|
+
child_process: {
|
|
487
|
+
exec: createSpawn(child_process.exec),
|
|
488
|
+
execFile: createSpawn(child_process.execFile),
|
|
489
|
+
fork: createSpawn(child_process.fork, true), // this is launching node, so deemed safe
|
|
490
|
+
spawn: createSpawn(child_process.spawn),
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* Creates a ChildProcess-like object for an existing process
|
|
495
|
+
*/
|
|
496
|
+
class ExistingProcessWrapper extends EventEmitter {
|
|
497
|
+
pid: number;
|
|
498
|
+
private checkInterval: NodeJS.Timeout;
|
|
499
|
+
|
|
500
|
+
constructor(pid: number) {
|
|
501
|
+
super();
|
|
502
|
+
this.pid = pid;
|
|
503
|
+
|
|
504
|
+
// Monitor process and emit exit event when it terminates
|
|
505
|
+
this.checkInterval = setInterval(() => {
|
|
506
|
+
try {
|
|
507
|
+
// Signal 0 checks if process exists without actually killing it
|
|
508
|
+
process.kill(pid, 0);
|
|
509
|
+
} catch {
|
|
510
|
+
// Process no longer exists
|
|
511
|
+
clearInterval(this.checkInterval);
|
|
512
|
+
this.emit('exit', null, null);
|
|
513
|
+
}
|
|
514
|
+
}, 1000);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Kill the process
|
|
518
|
+
kill(signal?: NodeJS.Signals | number) {
|
|
519
|
+
try {
|
|
520
|
+
process.kill(this.pid, signal);
|
|
521
|
+
return true;
|
|
522
|
+
} catch {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Clean up interval when wrapper is no longer needed
|
|
528
|
+
unref() {
|
|
529
|
+
clearInterval(this.checkInterval);
|
|
530
|
+
return this;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Checks if a process with the given PID is running
|
|
536
|
+
*/
|
|
537
|
+
function isProcessRunning(pid: number): boolean {
|
|
538
|
+
try {
|
|
539
|
+
// Signal 0 checks existence without killing
|
|
540
|
+
process.kill(pid, 0);
|
|
541
|
+
return true;
|
|
542
|
+
} catch {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Acquires an exclusive lock using the PID file itself (synchronously with busy-wait)
|
|
549
|
+
* Returns 0 if lock was acquired (need to spawn new process), or the existing PID if process is running
|
|
550
|
+
*/
|
|
551
|
+
function acquirePidFileLock(pidFilePath: string, maxRetries = 100, retryDelay = 5): number {
|
|
552
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
553
|
+
try {
|
|
554
|
+
// Try to open exclusively - 'wx' fails if file exists
|
|
555
|
+
const fd = openSync(pidFilePath, 'wx');
|
|
556
|
+
closeSync(fd);
|
|
557
|
+
return 0; // Successfully acquired lock (file created), caller should spawn process
|
|
558
|
+
} catch (err) {
|
|
559
|
+
if (err.code === 'EEXIST') {
|
|
560
|
+
// File exists - check if it contains a valid running process
|
|
561
|
+
try {
|
|
562
|
+
const pidContent = readFileSync(pidFilePath, 'utf-8');
|
|
563
|
+
const existingPid = parseInt(pidContent.trim(), 10);
|
|
564
|
+
|
|
565
|
+
if (!isNaN(existingPid) && isProcessRunning(existingPid)) {
|
|
566
|
+
// Valid process is running, return its PID immediately
|
|
567
|
+
return existingPid;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Invalid/empty PID - check file age to determine if it's stale or being written
|
|
571
|
+
const stats = statSync(pidFilePath);
|
|
572
|
+
const fileAge = Date.now() - stats.mtimeMs;
|
|
573
|
+
|
|
574
|
+
// If file is very new (less than 100ms) and empty/invalid, another thread is likely still writing to it
|
|
575
|
+
if (fileAge < 100) {
|
|
576
|
+
// Just wait and retry, don't try to remove
|
|
577
|
+
} else {
|
|
578
|
+
// Stale PID file (old and invalid), try to remove it
|
|
579
|
+
try {
|
|
580
|
+
unlinkSync(pidFilePath);
|
|
581
|
+
} catch {
|
|
582
|
+
// Another thread may have removed it, retry
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
} catch {
|
|
586
|
+
// Couldn't read/stat file, another thread might be modifying it, retry
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Wait a bit before retrying
|
|
590
|
+
const start = Date.now();
|
|
591
|
+
while (Date.now() - start < retryDelay) {
|
|
592
|
+
// Busy wait
|
|
593
|
+
}
|
|
594
|
+
} else {
|
|
595
|
+
throw err;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
throw new Error(`Failed to acquire PID file lock after ${maxRetries} attempts`);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function createSpawn(spawnFunction: (...args: any) => child_process.ChildProcess, alwaysAllow?: boolean) {
|
|
604
|
+
const basePath = env.getHdbBasePath();
|
|
605
|
+
return function (command: string, args?: any, options?: any, callback?: (...args: any[]) => void) {
|
|
606
|
+
if (!ALLOWED_COMMANDS.has(command.split(' ')[0]) && !alwaysAllow) {
|
|
607
|
+
throw new Error(`Command ${command} is not allowed`);
|
|
608
|
+
}
|
|
609
|
+
const processName = options?.name;
|
|
610
|
+
if (!processName)
|
|
611
|
+
throw new Error(
|
|
612
|
+
`Calling ${spawnFunction.name} in Harper must have a process "name" in the options to ensure that a single process is started and reused`
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
// Ensure PID directory exists
|
|
616
|
+
const pidDir = join(basePath, 'pids');
|
|
617
|
+
mkdirSync(pidDir, { recursive: true });
|
|
618
|
+
|
|
619
|
+
const pidFilePath = join(pidDir, `${processName}.pid`);
|
|
620
|
+
|
|
621
|
+
// Try to acquire lock - returns 0 if acquired, or existing PID
|
|
622
|
+
const existingPid = acquirePidFileLock(pidFilePath);
|
|
623
|
+
|
|
624
|
+
if (existingPid !== 0) {
|
|
625
|
+
// Existing process is running, return wrapper
|
|
626
|
+
return new ExistingProcessWrapper(existingPid);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// We acquired the lock (file was created), spawn new process
|
|
630
|
+
const childProcess = spawnFunction(command, args, options, callback);
|
|
631
|
+
|
|
632
|
+
// Write PID to the file we just created
|
|
633
|
+
try {
|
|
634
|
+
writeFileSync(pidFilePath, childProcess.pid.toString(), 'utf-8');
|
|
635
|
+
} catch (err) {
|
|
636
|
+
// Failed to write PID, clean up
|
|
637
|
+
try {
|
|
638
|
+
childProcess.kill();
|
|
639
|
+
unlinkSync(pidFilePath);
|
|
640
|
+
} catch {}
|
|
641
|
+
throw err;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// Clean up PID file when process exits
|
|
645
|
+
childProcess.on('exit', () => {
|
|
646
|
+
try {
|
|
647
|
+
unlinkSync(pidFilePath);
|
|
648
|
+
} catch {
|
|
649
|
+
// File may already be removed
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
return childProcess;
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Validates whether a module can be loaded based on security restrictions and returns the module path or replacement.
|
|
659
|
+
* For file URLs, ensures the module is within the containing folder.
|
|
660
|
+
* For node built-in modules, checks against an allowlist and returns any replacements.
|
|
661
|
+
*
|
|
662
|
+
* @param {string} moduleUrl - The URL or identifier of the module to be loaded, which may be a file: URL, node: URL, or bare module specifier.
|
|
663
|
+
* @param {string} containingFolder - The absolute path of the folder that contains the application, used to validate file: URLs are within bounds.
|
|
664
|
+
* @return {any} Returns undefined for allowed file paths, or a replacement module identifier for allowed node built-in modules.
|
|
665
|
+
* @throws {Error} Throws an error if the module is outside the application folder or if the module is not in the allowed list.
|
|
666
|
+
*/
|
|
667
|
+
function checkAllowedModulePath(moduleUrl: string, containingFolder?: string): boolean {
|
|
668
|
+
if (moduleUrl.startsWith('file:')) {
|
|
669
|
+
const path = moduleUrl.slice(7);
|
|
670
|
+
if (!containingFolder || path.startsWith(containingFolder)) {
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
throw new Error(`Can not load module outside of application folder ${containingFolder}`);
|
|
674
|
+
}
|
|
675
|
+
let simpleName = moduleUrl.startsWith('node:') ? moduleUrl.slice(5) : moduleUrl;
|
|
676
|
+
simpleName = simpleName.split('/')[0];
|
|
677
|
+
if (ALLOWED_NODE_BUILTIN_MODULES.has(simpleName)) return REPLACED_BUILTIN_MODULES[simpleName];
|
|
678
|
+
throw new Error(`Module ${moduleUrl} is not allowed to be imported`);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function getContext() {
|
|
682
|
+
return contextStorage.getStore() ?? {};
|
|
683
|
+
}
|
|
684
|
+
function getUser() {
|
|
685
|
+
return contextStorage.getStore()?.user;
|
|
686
|
+
}
|
|
687
|
+
function getResponse() {
|
|
688
|
+
return contextStorage.getStore()?.response;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
export function preventFunctionConstructor() {
|
|
692
|
+
Function.prototype.constructor = function () {}; // prevent this from being used to eval data in a parent context
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* This can redefine a property into a getter/setter that will allow derivatives of a prototype to assign
|
|
697
|
+
* a value to the property without incurring an error from the property being frozen and readonly.
|
|
698
|
+
* @param target
|
|
699
|
+
* @param name
|
|
700
|
+
* @param value
|
|
701
|
+
*/
|
|
702
|
+
function overridableProperty(target, name, value = target[name]) {
|
|
703
|
+
Object.defineProperty(target, name, {
|
|
704
|
+
get() {
|
|
705
|
+
return value;
|
|
706
|
+
},
|
|
707
|
+
set(value) {
|
|
708
|
+
Object.defineProperty(this, name, {
|
|
709
|
+
value,
|
|
710
|
+
configurable: true,
|
|
711
|
+
enumerable: true,
|
|
712
|
+
writable: true,
|
|
713
|
+
});
|
|
714
|
+
},
|
|
715
|
+
});
|
|
716
|
+
}
|