@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,258 @@
|
|
|
1
|
+
import { warn } from '../utility/logging/harper_logger.js';
|
|
2
|
+
import { IterableEventQueue } from './IterableEventQueue.ts';
|
|
3
|
+
import { keyArrayToString } from './Resources.ts';
|
|
4
|
+
import type { Id } from './ResourceInterface.ts';
|
|
5
|
+
|
|
6
|
+
const allSubscriptions = Object.create(null); // using it as a map that doesn't change much
|
|
7
|
+
const allSameThreadSubscriptions = Object.create(null); // using it as a map that doesn't change much
|
|
8
|
+
/**
|
|
9
|
+
* This module/function is responsible for the main work of tracking subscriptions and listening for new transactions
|
|
10
|
+
* that have occurred on any thread, and then reading through the transaction log to notify listeners. This is
|
|
11
|
+
* responsible for cleanup of subscriptions as well.
|
|
12
|
+
* @param table
|
|
13
|
+
* @param key
|
|
14
|
+
* @param listener
|
|
15
|
+
* @param startTime
|
|
16
|
+
* @param options
|
|
17
|
+
*/
|
|
18
|
+
export function addSubscription(table, key, listener?: (key) => any, startTime?: number, options?: any) {
|
|
19
|
+
const path = table.primaryStore.path;
|
|
20
|
+
const tableId = table.primaryStore.tableId;
|
|
21
|
+
// set up the subscriptions map. We want to just use a single map (per table) for efficient delegation
|
|
22
|
+
// (rather than having every subscriber filter every transaction)
|
|
23
|
+
let databaseSubscriptions;
|
|
24
|
+
if (options?.crossThreads === false) {
|
|
25
|
+
// we are only listening for commits on our own thread, so we use a separate subscriber and sequencer tracker
|
|
26
|
+
databaseSubscriptions = allSameThreadSubscriptions[path] || (allSameThreadSubscriptions[path] = []);
|
|
27
|
+
listenToCommits(table.primaryStore, table.auditStore);
|
|
28
|
+
} else {
|
|
29
|
+
databaseSubscriptions = allSubscriptions[path] || (allSubscriptions[path] = []);
|
|
30
|
+
const auditStore = table.auditStore;
|
|
31
|
+
if (!auditStore.hasSubscriptionCommitListener) {
|
|
32
|
+
let auditLogIterator;
|
|
33
|
+
if (auditStore.reusableIterable) {
|
|
34
|
+
// with rocksdb-js iterator we can and should not specify a start time so we just start at the end of the txn log
|
|
35
|
+
// and still match older version numbers that may commit in the future. But we have to start
|
|
36
|
+
// immediately so we are at the right position
|
|
37
|
+
auditLogIterator = auditStore.getRange({});
|
|
38
|
+
}
|
|
39
|
+
auditStore.hasSubscriptionCommitListener = true;
|
|
40
|
+
auditStore.on('committed', () => {
|
|
41
|
+
notifyFromTransactionData(databaseSubscriptions, auditLogIterator);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
databaseSubscriptions.auditStore = table.auditStore;
|
|
46
|
+
if (databaseSubscriptions.lastTxnTime == null) {
|
|
47
|
+
databaseSubscriptions.lastTxnTime = Date.now();
|
|
48
|
+
}
|
|
49
|
+
if (options?.scope === 'full-database') {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
let tableSubscriptions = databaseSubscriptions[tableId];
|
|
53
|
+
if (!tableSubscriptions) {
|
|
54
|
+
tableSubscriptions = databaseSubscriptions[tableId] = new Map();
|
|
55
|
+
tableSubscriptions.envs = databaseSubscriptions;
|
|
56
|
+
tableSubscriptions.tableId = tableId;
|
|
57
|
+
tableSubscriptions.store = table.primaryStore;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
key = keyArrayToString(key);
|
|
61
|
+
const subscription = new Subscription(listener);
|
|
62
|
+
subscription.startTime = startTime;
|
|
63
|
+
let subscriptions: any[] = tableSubscriptions.get(key);
|
|
64
|
+
|
|
65
|
+
if (subscriptions) subscriptions.push(subscription);
|
|
66
|
+
else {
|
|
67
|
+
tableSubscriptions.set(key, (subscriptions = [subscription]));
|
|
68
|
+
subscriptions.tables = tableSubscriptions;
|
|
69
|
+
subscriptions.key = key;
|
|
70
|
+
}
|
|
71
|
+
subscription.subscriptions = subscriptions;
|
|
72
|
+
return subscription;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* This is the class that is returned from subscribe calls and provide the interface to set a callback, end the
|
|
77
|
+
* subscription and get the initial state.
|
|
78
|
+
*/
|
|
79
|
+
class Subscription extends IterableEventQueue {
|
|
80
|
+
listener: (recordId: Id, auditEntry: any, localTime: number, beginTxn: boolean) => void;
|
|
81
|
+
subscriptions: [];
|
|
82
|
+
startTime?: number;
|
|
83
|
+
includeDescendants?: boolean;
|
|
84
|
+
supportsTransactions?: boolean;
|
|
85
|
+
onlyChildren?: boolean;
|
|
86
|
+
constructor(listener) {
|
|
87
|
+
super();
|
|
88
|
+
this.listener = listener;
|
|
89
|
+
this.on('close', () => this.end());
|
|
90
|
+
}
|
|
91
|
+
end() {
|
|
92
|
+
// cleanup
|
|
93
|
+
if (!this.subscriptions) return;
|
|
94
|
+
this.subscriptions.splice(this.subscriptions.indexOf(this), 1);
|
|
95
|
+
if (this.subscriptions.length === 0) {
|
|
96
|
+
const tableSubscriptions = this.subscriptions.tables;
|
|
97
|
+
if (tableSubscriptions) {
|
|
98
|
+
// TODO: Handle cleanup of wildcard
|
|
99
|
+
const key = this.subscriptions.key;
|
|
100
|
+
tableSubscriptions.delete(key);
|
|
101
|
+
if (tableSubscriptions.size === 0) {
|
|
102
|
+
const envSubscriptions = tableSubscriptions.envs;
|
|
103
|
+
const dbi = tableSubscriptions.dbi;
|
|
104
|
+
delete envSubscriptions[dbi];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
this.subscriptions = null;
|
|
109
|
+
}
|
|
110
|
+
toJSON() {
|
|
111
|
+
return { name: 'subscription' };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const ACTIONS_OF_INTEREST = ['put', 'patch', 'delete', 'message', 'invalidate'];
|
|
115
|
+
function notifyFromTransactionData(subscriptions, auditLogIterable) {
|
|
116
|
+
if (!subscriptions) return; // if no subscriptions to this env path, don't need to read anything
|
|
117
|
+
const auditStore = subscriptions.auditStore;
|
|
118
|
+
auditStore.resetReadTxn?.();
|
|
119
|
+
nextTransaction(subscriptions.auditStore);
|
|
120
|
+
let subscribersWithTxns;
|
|
121
|
+
if (!auditLogIterable) {
|
|
122
|
+
// rocksdb will pass this in, but with lmdb, we have to re-create the iterable
|
|
123
|
+
auditLogIterable = auditStore.getRange({
|
|
124
|
+
start: subscriptions.lastTxnTime,
|
|
125
|
+
exclusiveStart: true,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
for (const auditRecord of auditLogIterable) {
|
|
129
|
+
const timestamp: number = auditRecord.localTime ?? auditRecord.version;
|
|
130
|
+
subscriptions.lastTxnTime = timestamp;
|
|
131
|
+
if (!ACTIONS_OF_INTEREST.includes(auditRecord.type)) continue;
|
|
132
|
+
const tableSubscriptions = subscriptions[auditRecord.tableId];
|
|
133
|
+
if (!tableSubscriptions) continue;
|
|
134
|
+
const recordId = auditRecord.recordId;
|
|
135
|
+
// TODO: How to handle invalidation
|
|
136
|
+
let matchingKey = keyArrayToString(recordId);
|
|
137
|
+
let ancestorLevel = 0;
|
|
138
|
+
do {
|
|
139
|
+
// we iterate through the key hierarchy, notifying all subscribers for each key,
|
|
140
|
+
// so for an id like resource/foo/bar, we notify subscribers for resource/foo/bar, resource/foo/, resource/foo, resource/, and resource
|
|
141
|
+
// this allows for efficient subscriptions to children ids/topics
|
|
142
|
+
const keySubscriptions = tableSubscriptions.get(matchingKey);
|
|
143
|
+
if (keySubscriptions) {
|
|
144
|
+
for (const subscription of keySubscriptions) {
|
|
145
|
+
if (
|
|
146
|
+
ancestorLevel > 0 && // only ancestors if the subscription is for ancestors (and apply onlyChildren filtering as necessary)
|
|
147
|
+
!(subscription.includeDescendants && !(subscription.onlyChildren && ancestorLevel > 1))
|
|
148
|
+
)
|
|
149
|
+
continue;
|
|
150
|
+
if (subscription.startTime >= timestamp) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
let beginTxn;
|
|
155
|
+
if (subscription.supportsTransactions && subscription.txnInProgress !== auditRecord.version) {
|
|
156
|
+
// if the subscriber supports transactions, we mark this as the beginning of a new transaction
|
|
157
|
+
// tracking the subscription so that we can delimit the transaction on next transaction
|
|
158
|
+
// (with a beginTxn flag, which may be on an endTxn event)
|
|
159
|
+
beginTxn = true;
|
|
160
|
+
if (!subscription.txnInProgress) {
|
|
161
|
+
// if first txn for subscriber of this cycle, add to the transactional subscribers that we are tracking
|
|
162
|
+
if (!subscribersWithTxns) subscribersWithTxns = [subscription];
|
|
163
|
+
else subscribersWithTxns.push(subscription);
|
|
164
|
+
}
|
|
165
|
+
// the version defines the extent of a transaction, all audit records with the same version
|
|
166
|
+
// are part of the same transaction, and when the version changes, we know it is a new
|
|
167
|
+
// transaction
|
|
168
|
+
subscription.txnInProgress = auditRecord.version;
|
|
169
|
+
}
|
|
170
|
+
subscription.listener(recordId, auditRecord, timestamp, beginTxn);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
warn(error);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (matchingKey == null) break;
|
|
177
|
+
const lastSlash = matchingKey.lastIndexOf?.('/', matchingKey.length - 2);
|
|
178
|
+
if (lastSlash !== matchingKey.length - 1) {
|
|
179
|
+
ancestorLevel++; // don't increase the ancestor level for this going from resource/ to resource
|
|
180
|
+
}
|
|
181
|
+
if (lastSlash > -1) {
|
|
182
|
+
matchingKey = matchingKey.slice(0, lastSlash + 1);
|
|
183
|
+
} else matchingKey = null;
|
|
184
|
+
} while (true);
|
|
185
|
+
}
|
|
186
|
+
if (subscribersWithTxns) {
|
|
187
|
+
// any subscribers with open transactions need to have an event to indicate that their transaction has been ended
|
|
188
|
+
for (const subscription of subscribersWithTxns) {
|
|
189
|
+
subscription.txnInProgress = null; // clean up
|
|
190
|
+
subscription.listener(null, { type: 'end_txn' }, subscriptions.lastTxnTime, true);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Interface with database to listen for commits and traverse the audit log only on the same thread.
|
|
196
|
+
* @param primaryStore
|
|
197
|
+
* @param auditStore
|
|
198
|
+
*/
|
|
199
|
+
export function listenToCommits(primaryStore, auditStore) {
|
|
200
|
+
const store = auditStore || primaryStore;
|
|
201
|
+
const path = primaryStore.path;
|
|
202
|
+
const lmdbEnv = store.env;
|
|
203
|
+
if (!lmdbEnv.hasAfterCommitListener) {
|
|
204
|
+
lmdbEnv.hasAfterCommitListener = true;
|
|
205
|
+
store.on('aftercommit', (logEntries) => {
|
|
206
|
+
const subscriptions = allSameThreadSubscriptions[path]; // there is a different set of subscribers for same-thread subscriptions
|
|
207
|
+
if (!subscriptions) return;
|
|
208
|
+
// With RocksTransactionLog, we actually have direct access to the list of log entries:
|
|
209
|
+
if (Array.isArray(logEntries)) {
|
|
210
|
+
return notifyFromTransactionData(subscriptions, logEntries);
|
|
211
|
+
}
|
|
212
|
+
// we want each thread to do this mutually exclusively so that we don't have multiple threads trying to process the same data (the intended purpose of crossThreads=false)
|
|
213
|
+
const acquiredLock = () => {
|
|
214
|
+
// we have the lock, so we can now read the last sequence/local write time and continue to read the audit log from there
|
|
215
|
+
if (!store.threadLocalWrites)
|
|
216
|
+
// initiate the shared buffer if needed
|
|
217
|
+
store.threadLocalWrites = new Float64Array(
|
|
218
|
+
store.getUserSharedBuffer('last-thread-local-write', new ArrayBuffer(8))
|
|
219
|
+
);
|
|
220
|
+
subscriptions.txnTime = store.threadLocalWrites[0] || Date.now(); // start from last one
|
|
221
|
+
try {
|
|
222
|
+
notifyFromTransactionData(subscriptions);
|
|
223
|
+
} finally {
|
|
224
|
+
store.threadLocalWrites[0] = subscriptions.lastTxnTime; // update shared buffer
|
|
225
|
+
store.unlock('thread-local-writes'); // and release the lock
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
// try to get lock or wait for it
|
|
229
|
+
if (!store.tryLock('thread-local-writes', acquiredLock)) return;
|
|
230
|
+
acquiredLock();
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function nextTransaction(auditStore) {
|
|
235
|
+
auditStore.nextTransaction?.resolve();
|
|
236
|
+
let nextResolve;
|
|
237
|
+
auditStore.nextTransaction = new Promise((resolve) => {
|
|
238
|
+
nextResolve = resolve;
|
|
239
|
+
});
|
|
240
|
+
auditStore.nextTransaction.resolve = nextResolve;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function whenNextTransaction(auditStore) {
|
|
244
|
+
if (!auditStore.nextTransaction) {
|
|
245
|
+
addSubscription(
|
|
246
|
+
{
|
|
247
|
+
primaryStore: auditStore,
|
|
248
|
+
auditStore,
|
|
249
|
+
},
|
|
250
|
+
null,
|
|
251
|
+
null,
|
|
252
|
+
0,
|
|
253
|
+
{ scope: 'full-database' }
|
|
254
|
+
);
|
|
255
|
+
nextTransaction(auditStore);
|
|
256
|
+
}
|
|
257
|
+
return auditStore.nextTransaction;
|
|
258
|
+
}
|
package/security/auth.ts
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { getSuperUser } from './user.ts';
|
|
2
|
+
import { server } from '../server/Server.ts';
|
|
3
|
+
import { resources } from '../resources/Resources.ts';
|
|
4
|
+
import { validateOperationToken, validateRefreshToken } from './tokenAuthentication.ts';
|
|
5
|
+
import { table } from '../resources/databases.ts';
|
|
6
|
+
import { v4 as uuid } from 'uuid';
|
|
7
|
+
import * as env from '../utility/environment/environmentManager.js';
|
|
8
|
+
import { CONFIG_PARAMS, AUTH_AUDIT_STATUS, AUTH_AUDIT_TYPES } from '../utility/hdbTerms.ts';
|
|
9
|
+
import harperLogger from '../utility/logging/harper_logger.js';
|
|
10
|
+
const { forComponent, AuthAuditLog } = harperLogger;
|
|
11
|
+
import serverHandlers from '../server/itc/serverHandlers.js';
|
|
12
|
+
const { user } = serverHandlers;
|
|
13
|
+
import { Headers } from '../server/serverHelpers/Headers.ts';
|
|
14
|
+
import { convertToMS } from '../utility/common_utils.js';
|
|
15
|
+
import { verifyCertificate } from './certificateVerification/index.ts';
|
|
16
|
+
import { serializeMessage } from '../server/serverHelpers/contentTypes.ts';
|
|
17
|
+
const authLogger = forComponent('authentication');
|
|
18
|
+
const { debug } = authLogger;
|
|
19
|
+
const authEventLog = authLogger.withTag('auth-event');
|
|
20
|
+
env.initSync();
|
|
21
|
+
|
|
22
|
+
const appsCorsAccesslist = env.get(CONFIG_PARAMS.HTTP_CORSACCESSLIST);
|
|
23
|
+
const appsCors = env.get(CONFIG_PARAMS.HTTP_CORS);
|
|
24
|
+
const operationsCorsAccesslist = env.get(CONFIG_PARAMS.OPERATIONSAPI_NETWORK_CORSACCESSLIST);
|
|
25
|
+
const operationsCors = env.get(CONFIG_PARAMS.OPERATIONSAPI_NETWORK_CORS);
|
|
26
|
+
|
|
27
|
+
const sessionTable = table({
|
|
28
|
+
table: 'hdb_session',
|
|
29
|
+
database: 'system',
|
|
30
|
+
attributes: [{ name: 'id', isPrimaryKey: true }, { name: 'user' }],
|
|
31
|
+
});
|
|
32
|
+
const ENABLE_SESSIONS = env.get(CONFIG_PARAMS.AUTHENTICATION_ENABLESESSIONS) ?? true;
|
|
33
|
+
// check the environment for a flag to bypass authentication (for testing) since it doesn't necessarily get set on child threads
|
|
34
|
+
let AUTHORIZE_LOCAL =
|
|
35
|
+
process.env.AUTHENTICATION_AUTHORIZELOCAL ??
|
|
36
|
+
env.get(CONFIG_PARAMS.AUTHENTICATION_AUTHORIZELOCAL) ??
|
|
37
|
+
process.env.DEV_MODE;
|
|
38
|
+
const LOG_AUTH_SUCCESSFUL = env.get(CONFIG_PARAMS.LOGGING_AUDITAUTHEVENTS_LOGSUCCESSFUL) ?? false;
|
|
39
|
+
const LOG_AUTH_FAILED = env.get(CONFIG_PARAMS.LOGGING_AUDITAUTHEVENTS_LOGFAILED) ?? false;
|
|
40
|
+
|
|
41
|
+
const DEFAULT_COOKIE_EXPIRES = 'Tue, 01 Oct 8307 19:33:20 GMT';
|
|
42
|
+
|
|
43
|
+
let authorizationCache = new Map();
|
|
44
|
+
server.onInvalidatedUser(() => {
|
|
45
|
+
// TODO: Eventually we probably want to be able to invalidate individual users
|
|
46
|
+
authorizationCache = new Map();
|
|
47
|
+
});
|
|
48
|
+
export function bypassAuth() {
|
|
49
|
+
AUTHORIZE_LOCAL = true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// TODO: Make this not return a promise if it can be fulfilled synchronously (from cache)
|
|
53
|
+
export async function authentication(request, nextHandler) {
|
|
54
|
+
const headers = request.headers.asObject; // we cheat and use the node headers object since it is a little faster
|
|
55
|
+
const authorization = headers.authorization;
|
|
56
|
+
const cookie = headers.cookie;
|
|
57
|
+
let origin = headers.origin;
|
|
58
|
+
let responseHeaders = [];
|
|
59
|
+
try {
|
|
60
|
+
if (origin) {
|
|
61
|
+
const accessList = request.isOperationsServer
|
|
62
|
+
? operationsCors
|
|
63
|
+
? operationsCorsAccesslist
|
|
64
|
+
: []
|
|
65
|
+
: appsCors
|
|
66
|
+
? appsCorsAccesslist
|
|
67
|
+
: [];
|
|
68
|
+
if (accessList.includes(origin) || accessList.includes('*')) {
|
|
69
|
+
if (request.method === 'OPTIONS') {
|
|
70
|
+
const accessControlAllowHeaders =
|
|
71
|
+
env.get(CONFIG_PARAMS.HTTP_CORSACCESSCONTROLALLOWHEADERS) ?? 'Accept, Content-Type, Authorization';
|
|
72
|
+
|
|
73
|
+
// preflight request
|
|
74
|
+
const headers = new Headers([
|
|
75
|
+
['Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, PATCH, OPTIONS'],
|
|
76
|
+
['Access-Control-Allow-Headers', accessControlAllowHeaders],
|
|
77
|
+
['Access-Control-Allow-Origin', origin],
|
|
78
|
+
]);
|
|
79
|
+
if (ENABLE_SESSIONS) headers.set('Access-Control-Allow-Credentials', 'true');
|
|
80
|
+
return {
|
|
81
|
+
status: 200,
|
|
82
|
+
headers,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
responseHeaders.push('Access-Control-Allow-Origin', origin);
|
|
86
|
+
if (ENABLE_SESSIONS) responseHeaders.push('Access-Control-Allow-Credentials', 'true');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
let sessionId;
|
|
90
|
+
let session;
|
|
91
|
+
if (ENABLE_SESSIONS) {
|
|
92
|
+
// we prefix the cookie name with the origin so that we can partition/separate session/authentications
|
|
93
|
+
// host, to protect against CSRF
|
|
94
|
+
if (!origin) origin = headers.host;
|
|
95
|
+
const cookiePrefix = (origin ? origin.replace(/^https?:\/\//, '').replace(/\W/, '_') + '-' : '') + 'hdb-session=';
|
|
96
|
+
const cookies = cookie?.split(/;\s+/) || [];
|
|
97
|
+
for (const cookie of cookies) {
|
|
98
|
+
if (cookie.startsWith(cookiePrefix)) {
|
|
99
|
+
const end = cookie.indexOf(';');
|
|
100
|
+
sessionId = cookie.slice(cookiePrefix.length, end === -1 ? cookie.length : end);
|
|
101
|
+
session = await sessionTable.get(sessionId);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
request.session = session ? { ...session } : (session = {});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const authAuditLog = (username, status, strategy) => {
|
|
109
|
+
const log = new AuthAuditLog(
|
|
110
|
+
username,
|
|
111
|
+
status,
|
|
112
|
+
AUTH_AUDIT_TYPES.AUTHENTICATION,
|
|
113
|
+
headers['x-forwarded-for'] ?? request.ip,
|
|
114
|
+
request.method,
|
|
115
|
+
request.pathname
|
|
116
|
+
);
|
|
117
|
+
log.auth_strategy = strategy;
|
|
118
|
+
if (sessionId) log.session_id = sessionId;
|
|
119
|
+
if (headers['referer']) log.referer = headers['referer'];
|
|
120
|
+
if (headers['origin']) log.origin = headers['origin'];
|
|
121
|
+
|
|
122
|
+
if (status === AUTH_AUDIT_STATUS.SUCCESS) authEventLog.info?.(log);
|
|
123
|
+
else authEventLog.error?.(log);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
if (
|
|
127
|
+
!request.authorized &&
|
|
128
|
+
request.mtlsConfig &&
|
|
129
|
+
request.peerCertificate.subject &&
|
|
130
|
+
request?._nodeRequest?.socket?.authorizationError
|
|
131
|
+
)
|
|
132
|
+
authEventLog.error?.('Authorization error:', request._nodeRequest.socket.authorizationError);
|
|
133
|
+
|
|
134
|
+
if (request.mtlsConfig && request.authorized && request.peerCertificate.subject) {
|
|
135
|
+
const verificationResult = await verifyCertificate(request.peerCertificate, request.mtlsConfig);
|
|
136
|
+
if (!verificationResult.valid) {
|
|
137
|
+
authEventLog.error?.(
|
|
138
|
+
'Certificate verification failed:',
|
|
139
|
+
verificationResult.status,
|
|
140
|
+
'for',
|
|
141
|
+
request.peerCertificate.subject.CN
|
|
142
|
+
);
|
|
143
|
+
return applyResponseHeaders({
|
|
144
|
+
status: 401,
|
|
145
|
+
body: serializeMessage({ error: 'Certificate revoked or verification failed' }, request),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Alternative behavior: Instead of returning 401 above, we could just not set the user
|
|
150
|
+
// and let authentication fall through to other methods (Basic auth, etc.):
|
|
151
|
+
// if (verificationResult.valid) {
|
|
152
|
+
// // Only extract user from certificate if verification passed
|
|
153
|
+
// let username = ...
|
|
154
|
+
// }
|
|
155
|
+
|
|
156
|
+
let username = request.mtlsConfig.user;
|
|
157
|
+
if (username !== null) {
|
|
158
|
+
// null means no user is defined from certificate, need regular authentication as well
|
|
159
|
+
if (username === undefined || username === 'Common Name' || username === 'CN')
|
|
160
|
+
username = request.peerCertificate.subject.CN;
|
|
161
|
+
request.user = await server.getUser(username, null, request);
|
|
162
|
+
authAuditLog(username, AUTH_AUDIT_STATUS.SUCCESS, 'mTLS');
|
|
163
|
+
} else {
|
|
164
|
+
debug('HTTPS/WSS mTLS authorized connection (mTLS did not authorize a user)', 'from', request.ip);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let newUser;
|
|
169
|
+
if (request.user) {
|
|
170
|
+
// already authenticated
|
|
171
|
+
} else if (authorization) {
|
|
172
|
+
const cachedUser = authorizationCache.get(authorization);
|
|
173
|
+
if (cachedUser?.role) {
|
|
174
|
+
// Shallow-clone so verifyPerms's `role.permission = fullRolePerms` reassignment
|
|
175
|
+
// doesn't mutate the cache entry (defense-in-depth; operations and other
|
|
176
|
+
// meta-permission fields are now preserved through translation in permissionsTranslator).
|
|
177
|
+
newUser = { ...cachedUser, role: { ...cachedUser.role, permission: { ...cachedUser.role.permission } } };
|
|
178
|
+
} else if (cachedUser) {
|
|
179
|
+
newUser = cachedUser;
|
|
180
|
+
}
|
|
181
|
+
if (!newUser) {
|
|
182
|
+
const spaceIndex = authorization.indexOf(' ');
|
|
183
|
+
const strategy = authorization.slice(0, spaceIndex);
|
|
184
|
+
const credentials = authorization.slice(spaceIndex + 1);
|
|
185
|
+
let username, password;
|
|
186
|
+
try {
|
|
187
|
+
switch (strategy) {
|
|
188
|
+
case 'Basic':
|
|
189
|
+
const decoded = atob(credentials);
|
|
190
|
+
const colonIndex = decoded.indexOf(':');
|
|
191
|
+
username = decoded.slice(0, colonIndex);
|
|
192
|
+
password = decoded.slice(colonIndex + 1);
|
|
193
|
+
// legacy support for passing in blank username and password to indicate no auth
|
|
194
|
+
newUser = username || password ? await server.getUser(username, password, request) : null;
|
|
195
|
+
break;
|
|
196
|
+
case 'Bearer':
|
|
197
|
+
try {
|
|
198
|
+
newUser = await validateOperationToken(credentials);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
if (error.message === 'invalid token') {
|
|
201
|
+
// see if they provided a refresh token; we can allow that and pass it on to operations API
|
|
202
|
+
try {
|
|
203
|
+
await validateRefreshToken(credentials);
|
|
204
|
+
return applyResponseHeaders({
|
|
205
|
+
// we explicitly declare we don't want to handle this because the operations
|
|
206
|
+
// API has its own logic for handling this
|
|
207
|
+
status: -1,
|
|
208
|
+
});
|
|
209
|
+
} catch {
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
} catch (err) {
|
|
217
|
+
if (LOG_AUTH_FAILED) {
|
|
218
|
+
const failedAttempt = authorizationCache.get(credentials);
|
|
219
|
+
if (!failedAttempt) {
|
|
220
|
+
authorizationCache.set(credentials, credentials);
|
|
221
|
+
authAuditLog(username, AUTH_AUDIT_STATUS.FAILURE, strategy);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return applyResponseHeaders({
|
|
226
|
+
status: 401,
|
|
227
|
+
body: serializeMessage({ error: err.message }, request),
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
authorizationCache.set(authorization, newUser);
|
|
232
|
+
if (LOG_AUTH_SUCCESSFUL) authAuditLog(newUser.username, AUTH_AUDIT_STATUS.SUCCESS, strategy);
|
|
233
|
+
// Shallow-clone so verifyPerms's `role.permission = fullRolePerms` reassignment
|
|
234
|
+
// doesn't mutate the just-stored cache entry (defense-in-depth).
|
|
235
|
+
if (newUser?.role) {
|
|
236
|
+
newUser = { ...newUser, role: { ...newUser.role, permission: { ...newUser.role.permission } } };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
request.user = newUser;
|
|
241
|
+
} else if (session?.user) {
|
|
242
|
+
// or should this be cached in the session?
|
|
243
|
+
request.user = await server.getUser(session.user, null, request);
|
|
244
|
+
} else if (
|
|
245
|
+
(AUTHORIZE_LOCAL && (request.ip?.includes('127.0.0.') || request.ip == '::1')) ||
|
|
246
|
+
(request?._nodeRequest?.socket?.server?._pipeName && request.ip === undefined) // allow socket domain
|
|
247
|
+
) {
|
|
248
|
+
request.user = await getSuperUser();
|
|
249
|
+
}
|
|
250
|
+
if (ENABLE_SESSIONS) {
|
|
251
|
+
request.session.update = function (updatedSession) {
|
|
252
|
+
const expires = env.get(CONFIG_PARAMS.AUTHENTICATION_COOKIE_EXPIRES);
|
|
253
|
+
const useSecure =
|
|
254
|
+
request.protocol === 'https' ||
|
|
255
|
+
headers.host?.startsWith('localhost:') ||
|
|
256
|
+
headers.host?.startsWith('127.0.0.1:') ||
|
|
257
|
+
headers.host?.startsWith('::1');
|
|
258
|
+
if (!sessionId) {
|
|
259
|
+
sessionId = uuid();
|
|
260
|
+
const domains = env.get(CONFIG_PARAMS.AUTHENTICATION_COOKIE_DOMAINS);
|
|
261
|
+
const expiresString = expires
|
|
262
|
+
? new Date(Date.now() + convertToMS(expires)).toUTCString()
|
|
263
|
+
: DEFAULT_COOKIE_EXPIRES;
|
|
264
|
+
const domain =
|
|
265
|
+
headers.host &&
|
|
266
|
+
domains?.find((domain) => {
|
|
267
|
+
// find a domain that matches the host header
|
|
268
|
+
// the configured cookie domain starts with a dot, that indicates a wildcard, so we need to remove it
|
|
269
|
+
if (domain.startsWith('.')) domain = domain.slice(1);
|
|
270
|
+
// host can have a port, so we need to remove it because we are comparing domain names
|
|
271
|
+
const portStart = headers.host.indexOf(':');
|
|
272
|
+
const host = portStart !== -1 ? headers.host.slice(0, portStart) : headers.host;
|
|
273
|
+
return host.endsWith(domain);
|
|
274
|
+
});
|
|
275
|
+
const cookiePrefix =
|
|
276
|
+
(origin ? origin.replace(/^https?:\/\//, '').replace(/\W/, '_') + '-' : '') + 'hdb-session=';
|
|
277
|
+
// "Secure" can work with localhost/127.0.0.1 in certain browsers.
|
|
278
|
+
// https://github.com/httpwg/http-extensions/issues/2605
|
|
279
|
+
let cookie = `${cookiePrefix}${sessionId}; Path=/; Expires=${expiresString}; HttpOnly`;
|
|
280
|
+
if (domain) {
|
|
281
|
+
cookie += `; Domain=${domain}`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (useSecure) {
|
|
285
|
+
cookie += `; SameSite=None; Secure`;
|
|
286
|
+
}
|
|
287
|
+
if (responseHeaders) {
|
|
288
|
+
responseHeaders.push('Set-Cookie', cookie);
|
|
289
|
+
} else if (response?.headers?.set) {
|
|
290
|
+
response.headers.set('Set-Cookie', cookie);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (useSecure) {
|
|
294
|
+
// Indicate that we have successfully updated a session
|
|
295
|
+
// We make sure this is allowed by CORS so that a client can determine if it has
|
|
296
|
+
// a valid cookie-authenticated session (studio needs this)
|
|
297
|
+
if (responseHeaders) {
|
|
298
|
+
if (origin) responseHeaders.push('Access-Control-Expose-Headers', 'X-Hdb-Session');
|
|
299
|
+
responseHeaders.push('X-Hdb-Session', 'Secure');
|
|
300
|
+
} else if (response?.headers?.set) {
|
|
301
|
+
if (origin) response.headers.set('Access-Control-Expose-Headers', 'X-Hdb-Session');
|
|
302
|
+
response.headers.set('X-Hdb-Session', 'Secure');
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
updatedSession.id = sessionId;
|
|
306
|
+
return sessionTable.put(updatedSession, {
|
|
307
|
+
expiresAt: expires ? Date.now() + convertToMS(expires) : undefined,
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
request.login = async function (username: string, password: string) {
|
|
311
|
+
const user: any = (request.user = await server.authenticateUser(username, password, request));
|
|
312
|
+
request.session.update({ user: user && (user.getId?.() ?? user.username) });
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const response = await nextHandler(request);
|
|
316
|
+
if (!response) return response;
|
|
317
|
+
if (response.status === 401) {
|
|
318
|
+
if (
|
|
319
|
+
headers['user-agent']?.startsWith('Mozilla') &&
|
|
320
|
+
headers.accept?.startsWith('text/html') &&
|
|
321
|
+
resources.loginPath
|
|
322
|
+
) {
|
|
323
|
+
// on the web if we have a login page, default to redirecting to it
|
|
324
|
+
response.status = 302;
|
|
325
|
+
response.headers.set('Location', resources.loginPath(request));
|
|
326
|
+
} // the HTTP specified way of indicating HTTP authentication methods supported:
|
|
327
|
+
else response.headers.set('WWW-Authenticate', 'Basic');
|
|
328
|
+
}
|
|
329
|
+
return applyResponseHeaders(response);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
throw applyResponseHeaders(error);
|
|
332
|
+
}
|
|
333
|
+
function applyResponseHeaders(response) {
|
|
334
|
+
const l = responseHeaders.length;
|
|
335
|
+
if (l > 0) {
|
|
336
|
+
let headers = response.headers;
|
|
337
|
+
if (!headers) response.headers = headers = new Headers();
|
|
338
|
+
for (let i = 0; i < l; ) {
|
|
339
|
+
const name = responseHeaders[i++];
|
|
340
|
+
headers.set(name, responseHeaders[i++]);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
responseHeaders = null;
|
|
344
|
+
return response;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
let started;
|
|
348
|
+
export function start({ server, port, securePort }) {
|
|
349
|
+
server.http(authentication, port || securePort ? { port, securePort } : { port: 'all' });
|
|
350
|
+
// keep it cleaned out periodically
|
|
351
|
+
if (!started) {
|
|
352
|
+
started = true;
|
|
353
|
+
setInterval(() => {
|
|
354
|
+
authorizationCache = new Map();
|
|
355
|
+
}, env.get(CONFIG_PARAMS.AUTHENTICATION_CACHETTL)).unref();
|
|
356
|
+
user.addListener(() => {
|
|
357
|
+
authorizationCache = new Map();
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// operations
|
|
362
|
+
export async function login(loginObject) {
|
|
363
|
+
if (!loginObject.baseRequest?.login) throw new Error('No session for login');
|
|
364
|
+
// intercept any attempts to set headers on the standard response object and pass them on to fastify
|
|
365
|
+
loginObject.baseResponse.headers.set = (name, value) => {
|
|
366
|
+
loginObject.fastifyResponse.header(name, value);
|
|
367
|
+
};
|
|
368
|
+
await loginObject.baseRequest.login(loginObject.username, loginObject.password ?? '');
|
|
369
|
+
return 'Login successful';
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export async function logout(logoutObject) {
|
|
373
|
+
if (!logoutObject.baseRequest.session) throw new Error('No session for logout');
|
|
374
|
+
await logoutObject.baseRequest.session.update({ user: null });
|
|
375
|
+
return 'Logout successful';
|
|
376
|
+
}
|