@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,228 @@
|
|
|
1
|
+
import jwt, { type Algorithm, type JwtPayload, type Secret, type SignOptions } from 'jsonwebtoken';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import Joi from 'joi';
|
|
5
|
+
import { validateBySchema } from '../validation/validationWrapper.js';
|
|
6
|
+
import {
|
|
7
|
+
CONFIG_PARAMS,
|
|
8
|
+
JWT_ENUM,
|
|
9
|
+
LICENSE_KEY_DIR_NAME,
|
|
10
|
+
SYSTEM_SCHEMA_NAME,
|
|
11
|
+
SYSTEM_TABLE_NAMES,
|
|
12
|
+
} from '../utility/hdbTerms.ts';
|
|
13
|
+
import { ClientError, hdbErrors } from '../utility/errors/hdbError.js';
|
|
14
|
+
const { HTTP_STATUS_CODES, AUTHENTICATION_ERROR_MSGS } = hdbErrors;
|
|
15
|
+
import logger from '../utility/logging/harper_logger.js';
|
|
16
|
+
import * as password from '../utility/password.ts';
|
|
17
|
+
import { findAndValidateUser, type User } from './user.ts';
|
|
18
|
+
import { update } from '../dataLayer/insert.js';
|
|
19
|
+
import UpdateObject from '../dataLayer/UpdateObject.js';
|
|
20
|
+
import signalling from '../utility/signalling.js';
|
|
21
|
+
import { UserEventMsg } from '../server/threads/itc.js';
|
|
22
|
+
import env from '../utility/environment/environmentManager.js';
|
|
23
|
+
env.initSync();
|
|
24
|
+
|
|
25
|
+
type StringValue = SignOptions['expiresIn'];
|
|
26
|
+
const OPERATION_TOKEN_TIMEOUT: StringValue = env.get(CONFIG_PARAMS.AUTHENTICATION_OPERATIONTOKENTIMEOUT) || '1d';
|
|
27
|
+
const REFRESH_TOKEN_TIMEOUT: StringValue = env.get(CONFIG_PARAMS.AUTHENTICATION_REFRESHTOKENTIMEOUT) || '30d';
|
|
28
|
+
const RSA_ALGORITHM: Algorithm = 'RS256';
|
|
29
|
+
|
|
30
|
+
const TOKEN_TYPE = {
|
|
31
|
+
OPERATION: 'operation',
|
|
32
|
+
REFRESH: 'refresh',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
interface JWTRSAKeys {
|
|
36
|
+
publicKey: string;
|
|
37
|
+
privateKey: string;
|
|
38
|
+
passphrase: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface AuthObject {
|
|
42
|
+
username?: string;
|
|
43
|
+
password?: string;
|
|
44
|
+
role?: string;
|
|
45
|
+
expires_in?: string | number;
|
|
46
|
+
bypass_auth?: boolean;
|
|
47
|
+
hdb_user?: User;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface TokenObject {
|
|
51
|
+
refresh_token: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface JWTTokens {
|
|
55
|
+
operation_token: string;
|
|
56
|
+
refresh_token?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* fetches the rsa keys from cache var or disk
|
|
61
|
+
* @returns {Promise<JWTRSAKeys>}
|
|
62
|
+
*/
|
|
63
|
+
let rsaKeys: JWTRSAKeys | undefined = undefined;
|
|
64
|
+
export async function getJWTRSAKeys(): Promise<JWTRSAKeys> {
|
|
65
|
+
if (rsaKeys) return rsaKeys;
|
|
66
|
+
try {
|
|
67
|
+
const keysDir: string = path.join(env.getHdbBasePath(), LICENSE_KEY_DIR_NAME);
|
|
68
|
+
const passphrase: string = await fs.readFile(path.join(keysDir, JWT_ENUM.JWT_PASSPHRASE_NAME), 'utf8');
|
|
69
|
+
const privateKey: string = await fs.readFile(path.join(keysDir, JWT_ENUM.JWT_PRIVATE_KEY_NAME), 'utf8');
|
|
70
|
+
const publicKey: string = await fs.readFile(path.join(keysDir, JWT_ENUM.JWT_PUBLIC_KEY_NAME), 'utf8');
|
|
71
|
+
rsaKeys = { publicKey, privateKey, passphrase };
|
|
72
|
+
return rsaKeys;
|
|
73
|
+
} catch (err) {
|
|
74
|
+
logger.error(err);
|
|
75
|
+
throw new ClientError(AUTHENTICATION_ERROR_MSGS.NO_ENCRYPTION_KEYS, HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Creates a new operation token and refresh token.
|
|
81
|
+
* If there is no username and password, the hdb_user making the request is used in the token.
|
|
82
|
+
* An optional role can be provided which will be saved in the token payload.
|
|
83
|
+
* The token expires in the time specified in the expires_in field or the default time.
|
|
84
|
+
* @param authObj
|
|
85
|
+
*/
|
|
86
|
+
export async function createTokens(authObj: AuthObject): Promise<JWTTokens> {
|
|
87
|
+
const validation: any = validateBySchema(
|
|
88
|
+
authObj,
|
|
89
|
+
Joi.object({
|
|
90
|
+
username: Joi.string().optional(),
|
|
91
|
+
password: Joi.string().optional(),
|
|
92
|
+
role: Joi.string().optional(),
|
|
93
|
+
expires_in: Joi.alternatives(Joi.string(), Joi.number()).optional(),
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
if (validation) throw new ClientError(validation.message);
|
|
97
|
+
|
|
98
|
+
let user: any;
|
|
99
|
+
try {
|
|
100
|
+
// bypassAuth will be set to true if this is called from a component
|
|
101
|
+
let validatePassword: boolean = authObj.bypass_auth !== true;
|
|
102
|
+
if (!authObj.username && !authObj.password) {
|
|
103
|
+
// if the username and password are not provided, use the hdb_user making the request.
|
|
104
|
+
authObj.username = authObj.hdb_user?.username;
|
|
105
|
+
// the password would have been checked by authHandler before getting here
|
|
106
|
+
validatePassword = false;
|
|
107
|
+
}
|
|
108
|
+
user = await findAndValidateUser(authObj.username, authObj.password, validatePassword);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
logger.error(err);
|
|
111
|
+
throw new ClientError(AUTHENTICATION_ERROR_MSGS.INVALID_CREDENTIALS, HTTP_STATUS_CODES.UNAUTHORIZED);
|
|
112
|
+
}
|
|
113
|
+
if (!user) throw new ClientError(AUTHENTICATION_ERROR_MSGS.INVALID_CREDENTIALS, HTTP_STATUS_CODES.UNAUTHORIZED);
|
|
114
|
+
|
|
115
|
+
let superUser: boolean = false;
|
|
116
|
+
if (user.role?.permission) {
|
|
117
|
+
superUser = user.role.permission.super_user === true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const payload: {
|
|
121
|
+
username: string;
|
|
122
|
+
super_user: boolean;
|
|
123
|
+
role?: any;
|
|
124
|
+
} = { username: authObj.username, super_user: superUser };
|
|
125
|
+
if (authObj.role) payload.role = authObj.role;
|
|
126
|
+
|
|
127
|
+
const keys: JWTRSAKeys = await getJWTRSAKeys();
|
|
128
|
+
const operationToken = jwt.sign(
|
|
129
|
+
payload,
|
|
130
|
+
{ key: keys.privateKey, passphrase: keys.passphrase } satisfies Secret,
|
|
131
|
+
{
|
|
132
|
+
expiresIn: (authObj.expires_in ?? OPERATION_TOKEN_TIMEOUT) as StringValue,
|
|
133
|
+
algorithm: RSA_ALGORITHM,
|
|
134
|
+
subject: TOKEN_TYPE.OPERATION,
|
|
135
|
+
} satisfies SignOptions
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const refreshToken = jwt.sign(
|
|
139
|
+
payload,
|
|
140
|
+
{ key: keys.privateKey, passphrase: keys.passphrase } satisfies Secret,
|
|
141
|
+
{
|
|
142
|
+
expiresIn: REFRESH_TOKEN_TIMEOUT,
|
|
143
|
+
algorithm: RSA_ALGORITHM,
|
|
144
|
+
subject: TOKEN_TYPE.REFRESH,
|
|
145
|
+
} satisfies SignOptions
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
// update the user refresh token
|
|
149
|
+
const hashedToken: string | Promise<string> = password.hash(refreshToken, password.HASH_FUNCTION.SHA256);
|
|
150
|
+
const updateResult: any = await update(
|
|
151
|
+
new UpdateObject(SYSTEM_SCHEMA_NAME, SYSTEM_TABLE_NAMES.USER_TABLE_NAME, [
|
|
152
|
+
{ username: authObj.username, refresh_token: hashedToken },
|
|
153
|
+
])
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
if (updateResult.skipped_hashes.length > 0)
|
|
157
|
+
throw new ClientError(AUTHENTICATION_ERROR_MSGS.REFRESH_TOKEN_SAVE_FAILED, HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR);
|
|
158
|
+
|
|
159
|
+
signalling.signalUserChange(new UserEventMsg(process.pid));
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
operation_token: operationToken,
|
|
163
|
+
refresh_token: refreshToken,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Refreshes the operation token using the refresh token.
|
|
169
|
+
* @param tokenObj
|
|
170
|
+
*/
|
|
171
|
+
export async function refreshOperationToken(tokenObj: TokenObject): Promise<JWTTokens> {
|
|
172
|
+
const validation: any = validateBySchema(tokenObj, Joi.object({ refresh_token: Joi.string().required() }).required());
|
|
173
|
+
if (validation) throw new ClientError(validation.message);
|
|
174
|
+
const { refresh_token } = tokenObj;
|
|
175
|
+
await validateRefreshToken(refresh_token);
|
|
176
|
+
|
|
177
|
+
const keys: JWTRSAKeys = await getJWTRSAKeys();
|
|
178
|
+
const decodedJWT = jwt.decode(refresh_token, { json: true });
|
|
179
|
+
const operationToken = jwt.sign(
|
|
180
|
+
{ username: decodedJWT.username, super_user: decodedJWT.super_user },
|
|
181
|
+
{ key: keys.privateKey, passphrase: keys.passphrase } satisfies Secret,
|
|
182
|
+
{
|
|
183
|
+
expiresIn: OPERATION_TOKEN_TIMEOUT as StringValue,
|
|
184
|
+
algorithm: RSA_ALGORITHM,
|
|
185
|
+
subject: TOKEN_TYPE.OPERATION,
|
|
186
|
+
} satisfies SignOptions
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return { operation_token: operationToken };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export async function validateOperationToken(token: string): Promise<any> {
|
|
193
|
+
return validateToken(token, TOKEN_TYPE.OPERATION);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function validateRefreshToken(token: string): Promise<any> {
|
|
197
|
+
return validateToken(token, TOKEN_TYPE.REFRESH);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function validateToken(token: string, tokenType: string): Promise<any> {
|
|
201
|
+
try {
|
|
202
|
+
const keys: JWTRSAKeys = await getJWTRSAKeys();
|
|
203
|
+
const tokenVerified = jwt.verify(token, keys.publicKey, {
|
|
204
|
+
algorithms: [RSA_ALGORITHM],
|
|
205
|
+
subject: tokenType,
|
|
206
|
+
}) as JwtPayload;
|
|
207
|
+
|
|
208
|
+
// If a role is present, it means the token is not an operation token. The validation of
|
|
209
|
+
// the token will happen in the respective function/component that uses the token.
|
|
210
|
+
if (tokenVerified.role) {
|
|
211
|
+
throw new Error('Invalid token');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const user: any = await findAndValidateUser(tokenVerified.username, undefined, false);
|
|
215
|
+
if (tokenType === TOKEN_TYPE.REFRESH && !password.validate(user.refresh_token, token)) {
|
|
216
|
+
throw new Error('Invalid token');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return user;
|
|
220
|
+
} catch (err) {
|
|
221
|
+
logger.warn(err);
|
|
222
|
+
if (err?.name === 'TokenExpiredError') {
|
|
223
|
+
throw new ClientError(AUTHENTICATION_ERROR_MSGS.TOKEN_EXPIRED, HTTP_STATUS_CODES.FORBIDDEN);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
throw new ClientError(AUTHENTICATION_ERROR_MSGS.INVALID_TOKEN, HTTP_STATUS_CODES.UNAUTHORIZED);
|
|
227
|
+
}
|
|
228
|
+
}
|
package/security/user.ts
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const USERNAME_REQUIRED = 'username is required';
|
|
4
|
+
const ALTERUSER_NOTHING_TO_UPDATE = 'nothing to update, must supply active, role or password to update';
|
|
5
|
+
const EMPTY_PASSWORD = 'password cannot be an empty string';
|
|
6
|
+
const EMPTY_ROLE = 'If role is specified, it cannot be empty.';
|
|
7
|
+
const ACTIVE_BOOLEAN = 'active must be true or false';
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
addUser,
|
|
11
|
+
alterUser,
|
|
12
|
+
dropUser,
|
|
13
|
+
getSuperUser,
|
|
14
|
+
userInfo,
|
|
15
|
+
listUsers,
|
|
16
|
+
listUsersExternal,
|
|
17
|
+
setUsersWithRolesCache,
|
|
18
|
+
findAndValidateUser,
|
|
19
|
+
getUsersWithRolesCache,
|
|
20
|
+
USERNAME_REQUIRED,
|
|
21
|
+
ALTERUSER_NOTHING_TO_UPDATE,
|
|
22
|
+
EMPTY_PASSWORD,
|
|
23
|
+
EMPTY_ROLE,
|
|
24
|
+
ACTIVE_BOOLEAN,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export interface User {
|
|
28
|
+
active?: boolean;
|
|
29
|
+
username: string;
|
|
30
|
+
role?: UserRole;
|
|
31
|
+
__updatedtime__?: number;
|
|
32
|
+
__createdtime__?: number;
|
|
33
|
+
[other: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface UserRole {
|
|
37
|
+
permission: UserRoleNamedPermissions & UserRoleDatabasePermissions;
|
|
38
|
+
role: string;
|
|
39
|
+
id: string;
|
|
40
|
+
__updatedtime__: number;
|
|
41
|
+
__createdtime__: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface UserRoleNamedPermissions extends Partial<CRUDPermissions> {
|
|
45
|
+
super_user?: boolean;
|
|
46
|
+
cluster_user?: boolean;
|
|
47
|
+
structure_user?: boolean | string[];
|
|
48
|
+
operations?: string[];
|
|
49
|
+
/** Pre-expanded Set built from operations at cache-load time. Not persisted. */
|
|
50
|
+
_expandedOperations?: Set<string>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface UserRoleDatabasePermissions {
|
|
54
|
+
[databaseName: string]: UserRoleSchemaRecord;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface UserRoleSchemaRecord extends Partial<CRUDPermissions> {
|
|
58
|
+
tables: Record<string, UserRolePermissionTable | UserLegacyRolePermissionTable>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface UserRolePermissionTable extends CRUDPermissions {
|
|
62
|
+
attribute_permissions: UserRoleAttributePermissionTable[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface UserRoleAttributePermissionTable extends Omit<CRUDPermissions, 'delete'> {
|
|
66
|
+
attribute_name: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface UserLegacyRolePermissionTable extends CRUDPermissions {
|
|
70
|
+
attribute_restrictions: UserLegacyRoleAttributePermissionTable[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface UserLegacyRoleAttributePermissionTable extends CRUDPermissions {
|
|
74
|
+
attribute_name: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface CRUDPermissions {
|
|
78
|
+
read: boolean;
|
|
79
|
+
insert: boolean;
|
|
80
|
+
update: boolean;
|
|
81
|
+
delete: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//requires must be declared after module.exports to avoid cyclical dependency
|
|
85
|
+
const insert = require('../dataLayer/insert.js');
|
|
86
|
+
const delete_ = require('../dataLayer/delete.js');
|
|
87
|
+
const validation = require('../validation/user_validation.js');
|
|
88
|
+
const search = require('../dataLayer/search.js');
|
|
89
|
+
const signalling = require('../utility/signalling.js');
|
|
90
|
+
const hdbUtility = require('../utility/common_utils.js');
|
|
91
|
+
const validate = require('validate.js');
|
|
92
|
+
const logger = require('../utility/logging/harper_logger.js');
|
|
93
|
+
const { promisify } = require('util');
|
|
94
|
+
const env = require('../utility/environment/environmentManager.js');
|
|
95
|
+
const systemSchema = require('../json/systemSchema.json');
|
|
96
|
+
const { hdbErrors, ClientError } = require('../utility/errors/hdbError.js');
|
|
97
|
+
const { HTTP_STATUS_CODES, AUTHENTICATION_ERROR_MSGS, HDB_ERROR_MSGS } = hdbErrors;
|
|
98
|
+
const { UserEventMsg } = require('../server/threads/itc.js');
|
|
99
|
+
const _ = require('lodash');
|
|
100
|
+
const harperLogger = require('../utility/logging/harper_logger.js');
|
|
101
|
+
|
|
102
|
+
// Need to use `.js` even for other TS files since TS compiler won't replace requires.
|
|
103
|
+
// Whenever we can fix the cyclical dependency issue in this file (and switch to imports) we can use the correct file extensions.
|
|
104
|
+
const password = require('../utility/password.js');
|
|
105
|
+
const { server } = require('../server/Server.js');
|
|
106
|
+
const terms = require('../utility/hdbTerms.js');
|
|
107
|
+
const { expandOperationsPerms } = require('../utility/operationPermissions.js');
|
|
108
|
+
|
|
109
|
+
server.getUser = (username: string, password?: string | null): Promise<User> => {
|
|
110
|
+
return findAndValidateUser(username, password, password != null);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
server.authenticateUser = (username: string, password?: string | null): Promise<User> => {
|
|
114
|
+
return findAndValidateUser(username, password);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const USER_ATTRIBUTE_ALLOWLIST = {
|
|
118
|
+
username: true,
|
|
119
|
+
active: true,
|
|
120
|
+
role: true,
|
|
121
|
+
password: true,
|
|
122
|
+
};
|
|
123
|
+
const passwordHashCache = new Map();
|
|
124
|
+
const promiseDelete = promisify(delete_.delete);
|
|
125
|
+
const configuredHashFunction =
|
|
126
|
+
env.get(terms.CONFIG_PARAMS.AUTHENTICATION_HASHFUNCTION) ?? password.HASH_FUNCTION.SHA256;
|
|
127
|
+
let usersWithRolesMap;
|
|
128
|
+
|
|
129
|
+
async function addUser(user: User | any): Promise<string> {
|
|
130
|
+
let cleanUser = validate.cleanAttributes(user, USER_ATTRIBUTE_ALLOWLIST);
|
|
131
|
+
let validationResp = validation.addUserValidation(cleanUser);
|
|
132
|
+
if (validationResp) throw new ClientError(validationResp.message);
|
|
133
|
+
|
|
134
|
+
let searchRole = await search.searchByValue({
|
|
135
|
+
schema: 'system',
|
|
136
|
+
table: 'hdb_role',
|
|
137
|
+
attribute: 'role',
|
|
138
|
+
value: cleanUser.role,
|
|
139
|
+
get_attributes: ['id', 'permission', 'role'],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (!searchRole || searchRole.length < 1) {
|
|
143
|
+
throw new ClientError(HDB_ERROR_MSGS.ROLE_NAME_NOT_FOUND(cleanUser.role), HTTP_STATUS_CODES.NOT_FOUND);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (searchRole.length > 1) {
|
|
147
|
+
throw new ClientError(HDB_ERROR_MSGS.DUP_ROLES_FOUND(cleanUser.role), HTTP_STATUS_CODES.CONFLICT);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
cleanUser.password = await password.hash(cleanUser.password, configuredHashFunction);
|
|
151
|
+
cleanUser.hash_function = configuredHashFunction;
|
|
152
|
+
cleanUser.role = searchRole[0].id;
|
|
153
|
+
|
|
154
|
+
const insertResponse = await insert.insert({
|
|
155
|
+
operation: 'insert',
|
|
156
|
+
schema: 'system',
|
|
157
|
+
table: 'hdb_user',
|
|
158
|
+
records: [cleanUser],
|
|
159
|
+
});
|
|
160
|
+
logger.debug(insertResponse);
|
|
161
|
+
|
|
162
|
+
await setUsersWithRolesCache();
|
|
163
|
+
|
|
164
|
+
if (insertResponse.skipped_hashes.length === 1) {
|
|
165
|
+
throw new ClientError(HDB_ERROR_MSGS.USER_ALREADY_EXISTS(cleanUser.username), HTTP_STATUS_CODES.CONFLICT);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
await signalling.signalUserChange(new UserEventMsg(process.pid));
|
|
169
|
+
return `${cleanUser.username} successfully added`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function alterUser(jsonMessage) {
|
|
173
|
+
let cleanUser = validate.cleanAttributes(jsonMessage, USER_ATTRIBUTE_ALLOWLIST);
|
|
174
|
+
|
|
175
|
+
if (hdbUtility.isEmptyOrZeroLength(cleanUser.username)) {
|
|
176
|
+
throw new Error(USERNAME_REQUIRED);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (
|
|
180
|
+
hdbUtility.isEmptyOrZeroLength(cleanUser.password) &&
|
|
181
|
+
hdbUtility.isEmptyOrZeroLength(cleanUser.role) &&
|
|
182
|
+
hdbUtility.isEmptyOrZeroLength(cleanUser.active)
|
|
183
|
+
) {
|
|
184
|
+
throw new Error(ALTERUSER_NOTHING_TO_UPDATE);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!hdbUtility.isEmpty(cleanUser.password) && hdbUtility.isEmptyOrZeroLength(cleanUser.password.trim())) {
|
|
188
|
+
throw new Error(EMPTY_PASSWORD);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (!hdbUtility.isEmpty(cleanUser.active) && !hdbUtility.isBoolean(cleanUser.active)) {
|
|
192
|
+
throw new Error(ACTIVE_BOOLEAN);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!hdbUtility.isEmpty(cleanUser.password) && !hdbUtility.isEmptyOrZeroLength(cleanUser.password.trim())) {
|
|
196
|
+
cleanUser.password = await password.hash(cleanUser.password, configuredHashFunction);
|
|
197
|
+
cleanUser.hash_function = configuredHashFunction;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// the not operator will consider an empty string as undefined, so we need to check for an empty string explicitly
|
|
201
|
+
if (cleanUser.role === '') {
|
|
202
|
+
throw new Error(EMPTY_ROLE);
|
|
203
|
+
}
|
|
204
|
+
// Invalid roles will be found in the role search
|
|
205
|
+
if (cleanUser.role) {
|
|
206
|
+
const roleData = await search.searchByValue({
|
|
207
|
+
schema: 'system',
|
|
208
|
+
table: 'hdb_role',
|
|
209
|
+
attribute: 'role',
|
|
210
|
+
value: cleanUser.role,
|
|
211
|
+
get_attributes: ['*'],
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
if (!roleData || roleData.length === 0)
|
|
215
|
+
throw new ClientError(HDB_ERROR_MSGS.ALTER_USER_ROLE_NOT_FOUND(cleanUser.role), HTTP_STATUS_CODES.NOT_FOUND);
|
|
216
|
+
|
|
217
|
+
if (roleData.length > 1)
|
|
218
|
+
throw new ClientError(HDB_ERROR_MSGS.DUP_ROLES_FOUND(cleanUser.role), HTTP_STATUS_CODES.CONFLICT);
|
|
219
|
+
|
|
220
|
+
cleanUser.role = roleData[0].id;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const updateResponse = await insert.update({
|
|
224
|
+
operation: 'update',
|
|
225
|
+
schema: 'system',
|
|
226
|
+
table: 'hdb_user',
|
|
227
|
+
records: [cleanUser],
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
await setUsersWithRolesCache();
|
|
231
|
+
await signalling.signalUserChange(new UserEventMsg(process.pid));
|
|
232
|
+
|
|
233
|
+
return updateResponse;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function dropUser(user: User | any): Promise<string> {
|
|
237
|
+
const validationResp = validation.dropUserValidation(user);
|
|
238
|
+
if (validationResp) throw new ClientError(validationResp.message);
|
|
239
|
+
|
|
240
|
+
if (usersWithRolesMap.get(user.username) === undefined)
|
|
241
|
+
throw new ClientError(HDB_ERROR_MSGS.USER_NOT_EXIST(user.username), HTTP_STATUS_CODES.NOT_FOUND);
|
|
242
|
+
|
|
243
|
+
const deleteResponse = await promiseDelete({
|
|
244
|
+
table: 'hdb_user',
|
|
245
|
+
schema: 'system',
|
|
246
|
+
hash_values: [user.username],
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
logger.debug(deleteResponse);
|
|
250
|
+
await setUsersWithRolesCache();
|
|
251
|
+
await signalling.signalUserChange(new UserEventMsg(process.pid));
|
|
252
|
+
return `${user.username} successfully deleted`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async function userInfo(body): Promise<string | User> {
|
|
256
|
+
if (!body || !body.hdb_user) {
|
|
257
|
+
return 'There was no user info in the body';
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let user = _.cloneDeep(body.hdb_user);
|
|
261
|
+
let roleData = await search.searchByHash({
|
|
262
|
+
schema: 'system',
|
|
263
|
+
table: 'hdb_role',
|
|
264
|
+
hash_values: [user.role.id],
|
|
265
|
+
get_attributes: ['*'],
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
user.role = roleData[0];
|
|
269
|
+
delete user.password;
|
|
270
|
+
delete user.refresh_token;
|
|
271
|
+
delete user.hash;
|
|
272
|
+
delete user.hash_function;
|
|
273
|
+
|
|
274
|
+
return user;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* This function should be called by chooseOperation as it scrubs sensitive information before returning
|
|
279
|
+
* the results of list users.
|
|
280
|
+
*/
|
|
281
|
+
async function listUsersExternal(): Promise<User[]> {
|
|
282
|
+
const userData = await listUsers();
|
|
283
|
+
userData.forEach((user) => {
|
|
284
|
+
delete user.password;
|
|
285
|
+
delete user.hash;
|
|
286
|
+
delete user.refresh_token;
|
|
287
|
+
delete user.hash_function;
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return [...userData.values()];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Queries system table for user records, adds role-based perms, scrubs list based on licensed role allowance and returns
|
|
295
|
+
* data in a Map with the username as the key for the entry
|
|
296
|
+
*/
|
|
297
|
+
async function listUsers(): Promise<Map<string, User>> {
|
|
298
|
+
const roles = await search.searchByValue({
|
|
299
|
+
schema: 'system',
|
|
300
|
+
table: 'hdb_role',
|
|
301
|
+
value: '*',
|
|
302
|
+
attribute: 'role',
|
|
303
|
+
get_attributes: ['*'],
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const roleMapObj = {};
|
|
307
|
+
for (let role of roles) {
|
|
308
|
+
roleMapObj[role.id] = _.cloneDeep(role);
|
|
309
|
+
}
|
|
310
|
+
if (Object.keys(roleMapObj).length === 0) return null;
|
|
311
|
+
|
|
312
|
+
const users = await search.searchByValue({
|
|
313
|
+
schema: 'system',
|
|
314
|
+
table: 'hdb_user',
|
|
315
|
+
value: '*',
|
|
316
|
+
attribute: 'username',
|
|
317
|
+
get_attributes: ['*'],
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const userMap: Map<string, User> = new Map();
|
|
321
|
+
for (let user of users) {
|
|
322
|
+
user = _.cloneDeep(user);
|
|
323
|
+
user.role = roleMapObj[user.role];
|
|
324
|
+
appendSystemTablesToRole(user.role);
|
|
325
|
+
cacheExpandedOperationsPerms(user.role);
|
|
326
|
+
userMap.set(user.username, user);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return userMap;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* adds system table permissions to a role. This is used to protect system tables by leveraging operationAuthorization.
|
|
334
|
+
* @param userRole - Role of the user found during auth.
|
|
335
|
+
*/
|
|
336
|
+
function appendSystemTablesToRole(userRole: UserRole) {
|
|
337
|
+
if (!userRole) {
|
|
338
|
+
logger.error(`invalid user role found.`);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (!userRole.permission.system) {
|
|
342
|
+
userRole.permission.system = {
|
|
343
|
+
tables: {},
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
if (!userRole.permission.system.tables) {
|
|
347
|
+
userRole.permission.system.tables = {};
|
|
348
|
+
}
|
|
349
|
+
for (let table of Object.keys(systemSchema)) {
|
|
350
|
+
let newProp = {
|
|
351
|
+
read: !!userRole.permission.super_user,
|
|
352
|
+
insert: false,
|
|
353
|
+
update: false,
|
|
354
|
+
delete: false,
|
|
355
|
+
attribute_permissions: [],
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
userRole.permission.system.tables[table] = newProp;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Pre-expands operations into a Set at cache-load time so verifyPerms can do an O(1) lookup
|
|
364
|
+
* instead of allocating and expanding on every request.
|
|
365
|
+
* @param userRole - Role of the user found during auth.
|
|
366
|
+
*/
|
|
367
|
+
function cacheExpandedOperationsPerms(userRole: UserRole) {
|
|
368
|
+
if (!userRole?.permission?.operations) return;
|
|
369
|
+
userRole.permission._expandedOperations = expandOperationsPerms(userRole.permission.operations);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async function setUsersWithRolesCache(cache = undefined) {
|
|
373
|
+
if (cache) usersWithRolesMap = cache;
|
|
374
|
+
else usersWithRolesMap = await listUsers();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
async function getUsersWithRolesCache() {
|
|
378
|
+
if (!usersWithRolesMap) await setUsersWithRolesCache();
|
|
379
|
+
return usersWithRolesMap;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* iterates global.hdb_users to find and validate the username & optionally the password as well as if they are active.
|
|
384
|
+
* @param {string} username
|
|
385
|
+
* @param {string} pw
|
|
386
|
+
* @param {boolean} validatePassword
|
|
387
|
+
*/
|
|
388
|
+
async function findAndValidateUser(username: string, pw?: string | null, validatePassword = true): Promise<User> {
|
|
389
|
+
if (!usersWithRolesMap) {
|
|
390
|
+
await setUsersWithRolesCache();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const userTmp = usersWithRolesMap.get(username);
|
|
394
|
+
if (!userTmp) {
|
|
395
|
+
if (!validatePassword) return { username };
|
|
396
|
+
throw new ClientError(AUTHENTICATION_ERROR_MSGS.GENERIC_AUTH_FAIL, HTTP_STATUS_CODES.UNAUTHORIZED);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (userTmp && !userTmp.active)
|
|
400
|
+
throw new ClientError(AUTHENTICATION_ERROR_MSGS.USER_INACTIVE, HTTP_STATUS_CODES.UNAUTHORIZED);
|
|
401
|
+
|
|
402
|
+
const user: User = {
|
|
403
|
+
active: userTmp.active,
|
|
404
|
+
username: userTmp.username,
|
|
405
|
+
};
|
|
406
|
+
if (userTmp.refresh_token) user.refresh_token = userTmp.refresh_token;
|
|
407
|
+
// Shallow-clone the role and its permission so that verifyPerms can replace
|
|
408
|
+
// requestJson.hdb_user.role.permission with translated perms without mutating the cache.
|
|
409
|
+
// The _expandedOperations Set and operations array are shared by reference (read-only).
|
|
410
|
+
if (userTmp.role) user.role = { ...userTmp.role, permission: { ...userTmp.role.permission } };
|
|
411
|
+
|
|
412
|
+
if (validatePassword === true) {
|
|
413
|
+
// if matches the cached hash immediately return (the fast path)
|
|
414
|
+
if (passwordHashCache.get(pw) === userTmp.password) return user;
|
|
415
|
+
// if validates, cache the password
|
|
416
|
+
else {
|
|
417
|
+
let validated = password.validate(userTmp.password, pw, userTmp.hash_function || password.HASH_FUNCTION.MD5); // if no hashFunction default to legacy MD5
|
|
418
|
+
// argon2id hash validation is async so await it if it is a promise
|
|
419
|
+
if (validated?.then) validated = await validated;
|
|
420
|
+
if (validated === true) passwordHashCache.set(pw, userTmp.password);
|
|
421
|
+
else throw new ClientError(AUTHENTICATION_ERROR_MSGS.GENERIC_AUTH_FAIL, HTTP_STATUS_CODES.UNAUTHORIZED);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return user;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async function getSuperUser(): Promise<User | undefined> {
|
|
428
|
+
if (!usersWithRolesMap) {
|
|
429
|
+
await setUsersWithRolesCache();
|
|
430
|
+
}
|
|
431
|
+
for (let [, user] of usersWithRolesMap) {
|
|
432
|
+
if (user.role.role === 'super_user') return user;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
let invalidateCallbacks = [];
|
|
437
|
+
server.invalidateUser = function (user: User | any) {
|
|
438
|
+
for (let callback of invalidateCallbacks) {
|
|
439
|
+
try {
|
|
440
|
+
callback(user);
|
|
441
|
+
} catch (error) {
|
|
442
|
+
harperLogger.error('Error invalidating user', error);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
server.onInvalidatedUser = function (callback) {
|
|
448
|
+
invalidateCallbacks.push(callback);
|
|
449
|
+
};
|