rea-agents 6.3.0 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/bridge/ghidra/ReaGhidraApplySeeds.java +151 -0
- package/bridge/ghidra/ReaGhidraBridge.java +597 -209
- package/bridge/ghidra/ReaGhidraNoReturnFix.java +123 -0
- package/dist/adb/AdbConfiguration.js +88 -0
- package/dist/adb/AdbDeviceOutput.js +186 -0
- package/dist/adb/AdbProvider.js +1190 -0
- package/dist/adb/AdbShellOutput.js +309 -0
- package/dist/android/AndroidTargetSnapshot.js +104 -22
- package/dist/android/JadxConfiguration.js +44 -24
- package/dist/android/JadxProvider.js +51 -19
- package/dist/apktool/ApktoolConfiguration.js +84 -0
- package/dist/apktool/ApktoolDecodeOutput.js +59 -0
- package/dist/apktool/ApktoolProvider.js +506 -0
- package/dist/application/AnalysisProvider.js +8 -2
- package/dist/application/AppBundleExecutable.js +27 -22
- package/dist/application/BinaryTargetResolver.js +22 -2
- package/dist/application/CapabilityInventory.js +11 -1
- package/dist/application/ClientConfigurationDocument.js +70 -0
- package/dist/application/ClientConfigurationFiles.js +91 -0
- package/dist/application/ClientRegistrationEnvironment.js +35 -0
- package/dist/application/ClientRegistrationStatus.js +66 -31
- package/dist/application/DirectAnalysis.js +2 -2
- package/dist/application/DirectAnalysisCleanup.js +1 -1
- package/dist/application/DirectAnalysisStatus.js +1 -1
- package/dist/application/Doctor.js +5 -3
- package/dist/application/DoctorDiagnostics.js +1 -1
- package/dist/application/EvidenceBundleCommands.js +6 -12
- package/dist/application/GeminiClientSettings.js +139 -0
- package/dist/application/HermesClientHome.js +115 -0
- package/dist/application/HopperDownload.js +39 -0
- package/dist/application/InvestigationProviders.js +6 -0
- package/dist/application/JsonFiles.js +6 -5
- package/dist/{cliJsonFile.js → application/JsonInputFile.js} +108 -35
- package/dist/application/LinuxHopper.js +4 -12
- package/dist/application/MacHopper.js +172 -149
- package/dist/application/MipsElfAbiFlags.js +140 -0
- package/dist/application/ProviderOperationExecution.js +31 -0
- package/dist/application/ReconstructionObligationCandidates.js +9 -3
- package/dist/application/ReferenceSourceImport.js +76 -29
- package/dist/application/ReferenceSourceImportEntries.js +18 -9
- package/dist/application/ReferenceSourceImportPolicy.js +99 -23
- package/dist/application/ReferenceSourceImportTypes.js +30 -22
- package/dist/application/ReferenceSourceVcsAdapter.js +145 -30
- package/dist/application/RegularFileRead.js +93 -7
- package/dist/application/Setup.js +54 -6
- package/dist/application/SetupClientConfiguration.js +116 -16
- package/dist/application/SetupHost.js +102 -24
- package/dist/application/SetupPlan.js +5 -8
- package/dist/application/SetupSkill.js +58 -39
- package/dist/application/SupportedClients.js +290 -65
- package/dist/application/Uninstall.js +158 -10
- package/dist/application/UpdateMaintenance.js +17 -21
- package/dist/application/Utf8JsonInput.js +7 -0
- package/dist/application/WebScriptExportService.js +131 -65
- package/dist/application/WebSourceLocationService.js +3 -0
- package/dist/application/adb/AdbDeviceAnalysisPort.js +1 -0
- package/dist/application/adb/AdbDeviceAnalysisService.js +13 -0
- package/dist/application/analysisView/AnalysisViewService.js +40 -2
- package/dist/application/apktool/ApktoolResourceAnalysisPort.js +1 -0
- package/dist/application/apktool/ApktoolResourceAnalysisService.js +13 -0
- package/dist/application/binary/AnalysisClientCleanup.js +0 -24
- package/dist/application/binary/BinarySession.js +2 -1
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +2 -1
- package/dist/application/binaryDiagnostics/PeResourcesPort.js +1 -0
- package/dist/application/binaryDiagnostics/PeResourcesService.js +111 -0
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +2 -1
- package/dist/application/evm/EvmInterfaceService.js +3 -0
- package/dist/application/firmware/FirmwareAnalysisService.js +3 -0
- package/dist/application/investigation/InspectEvidenceBundle.js +18 -0
- package/dist/application/javascript/ElectronBoundaryGraphContext.js +3 -2
- package/dist/application/javascript/ElectronBoundaryGraphIpc.js +2 -2
- package/dist/application/javascript/ElectronBoundaryGraphNative.js +19 -6
- package/dist/application/javascript/ElectronBoundaryGraphWindows.js +3 -3
- package/dist/application/javascript/JavaScriptApplicationService.js +22 -11
- package/dist/application/javascript/JavaScriptApplicationWorkflowEvidence.js +5 -6
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +171 -30
- package/dist/application/javascript/JavaScriptArtifactGraphAccumulator.js +14 -16
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +67 -19
- package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +4 -3
- package/dist/application/javascript/JavaScriptArtifactGraphContext.js +11 -5
- package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +19 -16
- package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +92 -10
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +258 -235
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +115 -26
- package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +4 -1
- package/dist/application/javascript/JavaScriptModuleRelationships.js +6 -4
- package/dist/application/javascript/JavaScriptRecoveryService.js +3 -0
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +9 -3
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +199 -61
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +12 -19
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +4 -1
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -3
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +5 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +19 -8
- package/dist/application/jeb/JebAnalysisPort.js +1 -0
- package/dist/application/jeb/JebAnalysisService.js +13 -0
- package/dist/application/managed/ManagedApplicationGraphService.js +1 -1
- package/dist/application/native/NativeUiActionTrace.js +16 -8
- package/dist/application/native/NativeValueTrace.js +23 -6
- package/dist/application/process/ProcessCli.js +25 -20
- package/dist/artifacts/ArtifactPaths.js +129 -8
- package/dist/artifacts/ArtifactProvider.js +20 -15
- package/dist/artifacts/ArtifactReader.js +23 -0
- package/dist/artifacts/ArtifactResourceScope.js +100 -0
- package/dist/artifacts/AsarArtifactReader.js +176 -102
- package/dist/artifacts/AsarHeader.js +24 -0
- package/dist/artifacts/DirectoryArtifactReader.js +168 -65
- package/dist/artifacts/MachOSliceArtifactReader.js +116 -39
- package/dist/artifacts/NativeDmgArtifactReader.js +29 -22
- package/dist/artifacts/SafeOutputTree.js +245 -70
- package/dist/artifacts/SafeOutputTreeCleanup.js +45 -0
- package/dist/artifacts/SafeOutputTreeCreationFailure.js +20 -0
- package/dist/artifacts/SafeOutputTreeIdentity.js +42 -0
- package/dist/artifacts/SafeOutputTreeReadback.js +33 -0
- package/dist/artifacts/ZipArtifactReader.js +77 -27
- package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +58 -18
- package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +62 -24
- package/dist/artifacts/apple/KeyedArchiveReader.js +32 -13
- package/dist/artifacts/extraction/ArtifactExtraction.js +110 -86
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +110 -43
- package/dist/artifacts/inventory/ArtifactInventory.js +5 -4
- package/dist/artifacts/inventory/classify.js +75 -32
- package/dist/artifacts/inventory/hashStableRootArtifact.js +48 -15
- package/dist/artifacts/inventory/reader.js +13 -5
- package/dist/artifacts/inventory/scanCanonical.js +62 -25
- package/dist/artifacts/inventory/scanReader.js +38 -11
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +15 -9
- package/dist/artifacts/javascript/JavaScriptSourceAnalysis.js +3 -0
- package/dist/browser/BrowserScenarioPartialObservation.js +8 -2
- package/dist/browser/BrowserScenarioSecrets.js +52 -37
- package/dist/browser/CdpBrowserProvider.js +5 -0
- package/dist/browser/CdpCaptureDocuments.js +40 -6
- package/dist/browser/CdpCaptureDomSvg.js +210 -0
- package/dist/browser/CdpCaptureEventBodyShapes.js +4 -8
- package/dist/browser/CdpCaptureEventHandlers.js +26 -9
- package/dist/browser/CdpCaptureEvents.js +4 -9
- package/dist/browser/CdpConnection.js +22 -5
- package/dist/browser/CdpPageCapture.js +1 -1
- package/dist/browser/CdpTargetSession.js +30 -34
- package/dist/browser/CdpWebMcpDiscovery.js +32 -10
- package/dist/browser/ElectronFileScope.js +99 -9
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +60 -4
- package/dist/browser/PlaywrightElectronActiveProvider.js +11 -6
- package/dist/browser/PlaywrightScenarioArtifacts.js +5 -5
- package/dist/browser/PlaywrightScenarioBrowser.js +69 -7
- package/dist/browser/PlaywrightScenarioSession.js +127 -54
- package/dist/browser/PlaywrightScenarioStorage.js +507 -0
- package/dist/browser/PngVisualDiff.js +198 -29
- package/dist/browser/WebSourceMapFetcher.js +3 -3
- package/dist/browser/assets/LocalWebScriptArtifacts.js +3 -1
- package/dist/browser/assets/PublishWebScripts.js +75 -20
- package/dist/browser/assets/WebArtifactReads.js +23 -1
- package/dist/browser/assets/WebSourceLocationArtifacts.js +1 -0
- package/dist/browser/execution/CdpExecutionCapture.js +3 -3
- package/dist/browser/execution/CdpPreciseCoverage.js +5 -8
- package/dist/browser/history/HarCapture.js +14 -0
- package/dist/browser/history/HarCaptureProcess.js +2 -10
- package/dist/browser/history/MitmproxyCaptureAdapter.js +3 -1
- package/dist/browser/modules/WebModuleArtifacts.js +1 -0
- package/dist/cli/adbCommands.js +337 -0
- package/dist/cli/analysisViewCommands.js +39 -1
- package/dist/cli/apktoolCommands.js +53 -0
- package/dist/cli/artifactCommands.js +8 -11
- package/dist/cli/binaryDiagnosticsCommands.js +19 -1
- package/dist/cli/browserAdvancedCommands.js +65 -36
- package/dist/cli/coreBinaryCommands.js +0 -5
- package/dist/cli/coreNativeCommands.js +1 -14
- package/dist/cli/electronCommands.js +6 -1
- package/dist/cli/evmCommands.js +13 -4
- package/dist/cli/firmwareCommands.js +7 -2
- package/dist/cli/javascriptApplicationAnalysis.js +17 -1
- package/dist/cli/javascriptRecoveryCommands.js +22 -15
- package/dist/cli/jebCommands.js +99 -0
- package/dist/cli/jsonOutput.js +11 -4
- package/dist/cli/referenceSourceImportStatus.js +7 -0
- package/dist/cli/setupCommands.js +15 -3
- package/dist/cli/utilityCommands.js +66 -18
- package/dist/cli/webScriptCommands.js +20 -1
- package/dist/cli/webSourceLocationCommands.js +21 -9
- package/dist/cli.js +6 -0
- package/dist/cliBrowserScenarioCommands.js +2 -1
- package/dist/cliCommandNames.js +32 -0
- package/dist/cliJsonInput.js +2 -2
- package/dist/cliObservationOptions.js +3 -0
- package/dist/composition/adb.js +3 -0
- package/dist/composition/apktool.js +3 -0
- package/dist/composition/binaryDiagnostics.js +4 -0
- package/dist/composition/directAnalysis.js +12 -4
- package/dist/composition/javascriptAnalysisWorkerProcess.js +48 -0
- package/dist/composition/jeb.js +6 -0
- package/dist/config/environment.js +10 -0
- package/dist/config/ghidraLanguageOverride.js +9 -0
- package/dist/config/mcpInputSchemaProfile.js +27 -0
- package/dist/config/parseConfig.js +28 -1
- package/dist/contracts/adb/adbToolContracts.js +353 -0
- package/dist/contracts/advertisedInputExamples.js +48 -0
- package/dist/contracts/analysisDetail.js +10 -0
- package/dist/contracts/analysisViewToolContracts.js +17 -2
- package/dist/contracts/apktool/apktoolToolContracts.js +33 -0
- package/dist/contracts/artifactToolContracts.js +8 -5
- package/dist/contracts/browserToolContracts.js +1 -1
- package/dist/contracts/compactInputSchema.js +256 -0
- package/dist/contracts/functionWorkflowToolContracts.js +1 -1
- package/dist/contracts/inputSchemaPresentation.js +10 -10
- package/dist/contracts/javascript/electronToolContracts.js +15 -3
- package/dist/contracts/javascript/javascriptRecoveryToolContracts.js +1 -1
- package/dist/contracts/jeb/jebToolContracts.js +64 -0
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +25 -3
- package/dist/contracts/officialToolContracts.js +5 -5
- package/dist/contracts/sessionToolContracts.js +2 -2
- package/dist/contracts/sessionToolSchemas.js +6 -2
- package/dist/contracts/toolContractExamples.js +6 -0
- package/dist/contracts/toolContractTypes.js +3 -0
- package/dist/contracts/toolContracts.js +6 -0
- package/dist/contracts/toolEffects.js +167 -0
- package/dist/contracts/toolOutputSchemaGroups.js +5 -3
- package/dist/contracts/toolSchemaMetadata.js +82 -7
- package/dist/domain/adb/adbDeviceAnalysis.js +583 -0
- package/dist/domain/analysisErrorCleanup.js +29 -0
- package/dist/domain/analysisErrorPresentation.js +18 -6
- package/dist/domain/analysisErrorProjection.js +4 -1
- package/dist/domain/analysisSnapshot.js +2 -1
- package/dist/domain/analysisView/analysisView.js +52 -2
- package/dist/domain/analysisView/binaryLayoutView.js +2 -0
- package/dist/domain/analysisView/javascriptApplicationView.js +2 -0
- package/dist/domain/analysisView/nativeFunctionView.js +155 -0
- package/dist/domain/android/androidApplication.js +25 -20
- package/dist/domain/apktool/apktoolResourceAnalysis.js +77 -0
- package/dist/domain/apple/appleApplication.js +40 -23
- package/dist/domain/apple/appleBundleAnatomy.js +95 -28
- package/dist/domain/apple/dyldPaths.js +9 -1
- package/dist/domain/apple/dylibResolution.js +2 -2
- package/dist/domain/apple/interfaceBuilderGraph.js +22 -19
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +10 -1
- package/dist/domain/artifactComparison.js +35 -7
- package/dist/domain/artifactGraph.js +5 -3
- package/dist/domain/artifactIdentity.js +30 -2
- package/dist/domain/artifactInspection.js +3 -43
- package/dist/domain/artifactIntegrityPolicy.js +10 -0
- package/dist/domain/artifactInventoryEvidence.js +11 -12
- package/dist/domain/artifactPathSyntax.js +1 -1
- package/dist/domain/binaryTarget.js +16 -0
- package/dist/domain/binaryTargetTypes.js +8 -1
- package/dist/domain/browserObservationSchemas.js +8 -4
- package/dist/domain/canonicalJsonDigestSteps.js +34 -12
- package/dist/domain/compactStringIdentity.js +9 -0
- package/dist/domain/evidence.js +2 -1
- package/dist/domain/evidenceRecordSummary.js +144 -0
- package/dist/domain/inputIssueProjection.js +16 -1
- package/dist/domain/javascript/electronStaticAnalysisBrowser.js +12 -13
- package/dist/domain/javascript/electronStaticAnalysisIpc.js +11 -20
- package/dist/domain/javascript/electronStaticAnalysisNative.js +70 -40
- package/dist/domain/javascript/electronStaticAnalysisValues.js +16 -0
- package/dist/domain/javascript/javascriptAnalysisResourceControls.js +45 -0
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +4 -1
- package/dist/domain/javascript/javascriptApplicationChangeGraph.js +6 -6
- package/dist/domain/javascript/javascriptApplicationGraph.js +79 -18
- package/dist/domain/javascript/javascriptApplicationProjectionResources.js +35 -0
- package/dist/domain/javascript/javascriptApplicationVersionItems.js +28 -12
- package/dist/domain/javascript/javascriptApplicationVersionKeys.js +9 -1
- package/dist/domain/javascript/javascriptAstFingerprint.js +58 -31
- package/dist/domain/javascript/javascriptAstValues.js +32 -0
- package/dist/domain/javascript/javascriptElectronMemberWrites.js +50 -0
- package/dist/domain/javascript/javascriptModuleSemanticIr.js +15 -0
- package/dist/domain/javascript/javascriptNativeHandoff.js +6 -1
- package/dist/domain/javascript/javascriptRpcEndpoints.js +253 -0
- package/dist/domain/javascript/javascriptRuntimeLoadState.js +1 -3
- package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +7 -2
- package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +8 -11
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +190 -33
- package/dist/domain/javascript/javascriptSemanticCallableResults.js +42 -0
- package/dist/domain/javascript/javascriptSemanticCalls.js +8 -1
- package/dist/domain/javascript/javascriptSemanticDerivedAnalysis.js +15 -4
- package/dist/domain/javascript/javascriptSemanticFileProjection.js +1 -0
- package/dist/domain/javascript/javascriptSemanticFingerprints.js +42 -41
- package/dist/domain/javascript/javascriptSemanticGraph.js +69 -23
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +2 -10
- package/dist/domain/javascript/javascriptSemanticIterationSources.js +40 -7
- package/dist/domain/javascript/javascriptSemanticMemberMutations.js +341 -87
- package/dist/domain/javascript/javascriptSemanticMutationValues.js +78 -35
- package/dist/domain/javascript/javascriptSemanticObjectReferences.js +381 -0
- package/dist/domain/javascript/javascriptSemanticObjects.js +7 -1
- package/dist/domain/javascript/javascriptSemanticProjection.js +52 -14
- package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +77 -0
- package/dist/domain/javascript/javascriptSemanticQuery.js +27 -29
- package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +1 -3
- package/dist/domain/javascript/javascriptSemanticReturnedReferences.js +219 -0
- package/dist/domain/javascript/javascriptSemanticReturns.js +13 -23
- package/dist/domain/javascript/javascriptSemanticState.js +22 -2
- package/dist/domain/javascript/javascriptSemanticTraversal.js +19 -1
- package/dist/domain/javascript/javascriptSemanticValues.js +47 -19
- package/dist/domain/javascript/javascriptSourceAnalysis.js +1 -0
- package/dist/domain/javascript/javascriptStaticAnalysis.js +29 -17
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +8 -6
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +49 -5
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +8 -4
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +1 -0
- package/dist/domain/jeb/jebAnalysis.js +114 -0
- package/dist/domain/jsonShape.js +63 -52
- package/dist/domain/jsonValue.js +3 -0
- package/dist/domain/managed/managedApplicationGraph.js +37 -0
- package/dist/domain/managed/managedApplicationGraphCoverage.js +8 -2
- package/dist/domain/managed/managedApplicationGraphNodes.js +32 -22
- package/dist/domain/managed/managedArtifact.js +1 -0
- package/dist/domain/managed/managedInspectionEvidence.js +13 -0
- package/dist/domain/native/nativeAotPe.js +1408 -0
- package/dist/domain/native/nativeInstruction.js +21 -0
- package/dist/domain/native/nativeMetadataRecovery.js +79 -6
- package/dist/domain/native/peResources.js +94 -0
- package/dist/domain/nativeConvention.js +33 -0
- package/dist/domain/process/processCapture.js +91 -1
- package/dist/domain/process/processCaptureExample.js +24 -0
- package/dist/domain/process/processCaptureValidation.js +79 -0
- package/dist/domain/process/processScenario.js +59 -7
- package/dist/domain/propertyListKeys.js +3 -1
- package/dist/domain/referenceSourceGraph.js +25 -16
- package/dist/domain/referenceSourceImportParsing.js +6 -3
- package/dist/domain/referenceSourcePathIdentity.js +22 -0
- package/dist/domain/referenceSourceRequireBindings.js +137 -0
- package/dist/domain/webBundleAnalyzerInspection.js +14 -2
- package/dist/domain/webCaptureDiff.js +102 -4
- package/dist/domain/webScriptExportError.js +10 -4
- package/dist/domain/webScriptExportPlan.js +7 -13
- package/dist/domain/zipPackageFormat.js +4 -1
- package/dist/domain/zodCollectionSteps.js +24 -0
- package/dist/dotnet/ManagedArtifactInspector.js +55 -43
- package/dist/dotnet/ManagedDecodeBudget.js +80 -0
- package/dist/dotnet/ManagedMemberInspector.js +13 -6
- package/dist/dotnet/ManagedMemberInspectorCore.js +2 -2
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +4 -2
- package/dist/dotnet/ManagedMemberRows.js +9 -4
- package/dist/dotnet/ManagedMetadataHeaps.js +15 -5
- package/dist/dotnet/ManagedMetadataInventoryRows.js +20 -11
- package/dist/dotnet/ManagedMetadataLayout.js +10 -4
- package/dist/dotnet/ManagedMethodBodyReader.js +8 -3
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +3 -2
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +49 -34
- package/dist/dotnet/ManagedPeReader.js +41 -25
- package/dist/dotnet/ManagedReaderFailure.js +2 -1
- package/dist/dotnet/ManagedStaticProvider.js +55 -24
- package/dist/evaluation/AgentEvaluationReport.js +9 -5
- package/dist/evaluation/CodexAgentEval.js +43 -13
- package/dist/evm/EvmoleFailures.js +0 -2
- package/dist/evm/EvmoleInterfaceProvider.js +67 -2
- package/dist/filesystem/OwnedDirectoryHandle.js +29 -0
- package/dist/filesystem/OwnedFileHandle.js +36 -0
- package/dist/filesystem/RegularFile.js +33 -1
- package/dist/filesystem/StableFileHash.js +46 -0
- package/dist/filesystem/readFileHandleChunks.js +26 -0
- package/dist/firmware/FirmwareCommand.js +25 -3
- package/dist/firmware/FirmwareFiles.js +23 -8
- package/dist/firmware/FirmwareProvider.js +156 -32
- package/dist/firmware/FirmwarePublication.js +24 -3
- package/dist/firmware/FirmwareRelease.js +1 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +55 -4
- package/dist/ghidra/GhidraAnalysisSeeds.js +211 -0
- package/dist/ghidra/GhidraClient.js +76 -4
- package/dist/ghidra/GhidraDiagnostics.js +11 -8
- package/dist/ghidra/GhidraFunctionValues.js +26 -2
- package/dist/ghidra/GhidraInstallation.js +1 -1
- package/dist/ghidra/GhidraInventoryValues.js +23 -1
- package/dist/ghidra/GhidraLanguageCatalog.js +99 -0
- package/dist/ghidra/GhidraLauncher.js +80 -39
- package/dist/ghidra/GhidraLoadImageAttest.js +49 -2
- package/dist/ghidra/GhidraMipsProfile.js +79 -0
- package/dist/ghidra/GhidraProvider.js +57 -9
- package/dist/ghidra/GhidraProviderCapabilities.js +18 -8
- package/dist/ghidra/GhidraProviderClient.js +282 -21
- package/dist/ghidra/GhidraSessionValues.js +9 -2
- package/dist/hopper/HopperAnalysisProfile.js +2 -0
- package/dist/hopper/HopperClient.js +15 -6
- package/dist/hopper/HopperMachOImage.js +2 -0
- package/dist/hopper/HopperProvider.js +13 -2
- package/dist/ida/IdaOperationRunner.js +8 -2
- package/dist/ida/IdaProvider.js +7 -0
- package/dist/ida/IdaSessionClient.js +3 -1
- package/dist/ida/IdaWorkspace.js +4 -2
- package/dist/javascript/analysis/JavaScriptAnalysisTransfer.js +326 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorker.js +520 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerProtocol.js +63 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerSchemas.js +521 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerServer.js +116 -0
- package/dist/javascript/recovery/RecoveryFiles.js +18 -7
- package/dist/javascript/recovery/WakaruCommand.js +22 -9
- package/dist/javascript/recovery/WakaruExecution.js +11 -7
- package/dist/javascript/recovery/WakaruProvider.js +139 -16
- package/dist/javascript/recovery/WakaruPublication.js +14 -4
- package/dist/javascript/recovery/WakaruRelease.js +10 -3
- package/dist/javascript/recovery/WakaruReport.js +12 -7
- package/dist/javascript/recovery/WakaruVersion.js +24 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +16 -3
- package/dist/javascript/sourceMaps/SourceMapDecoder.js +63 -7
- package/dist/javascript/sourceMaps/SourceMapFormat.js +15 -4
- package/dist/jeb/JebMcpConnection.js +179 -0
- package/dist/jeb/JebMcpEndpoint.js +40 -0
- package/dist/jeb/JebProvider.js +299 -0
- package/dist/mcpDoctor.js +15 -6
- package/dist/native/AppleDispatchCoverage.js +25 -12
- package/dist/native/AppleDispatchMetadata.js +14 -7
- package/dist/native/AppleMachoFixups.js +71 -15
- package/dist/native/AppleMachoSelection.js +23 -3
- package/dist/native/NativeMacOSProvider.js +91 -16
- package/dist/native/NativeMachoInspection.js +11 -7
- package/dist/native/NativeUiHelperRuntime.js +6 -1
- package/dist/native/NativeUiObservation.js +4 -3
- package/dist/native/pe/PeResourceLayout.js +120 -0
- package/dist/native/pe/PeResourceParser.js +286 -0
- package/dist/native/pe/PeResourcesProvider.js +63 -0
- package/dist/process/BoundedFileBytes.js +30 -7
- package/dist/process/DarwinProcessRunTokenReader.js +8 -3
- package/dist/process/OwnedCommand.js +4 -3
- package/dist/process/ProcessOwnership.js +104 -112
- package/dist/process/ProcessOwnershipObservation.js +96 -39
- package/dist/process/ProcessOwnershipProcessTree.js +4 -4
- package/dist/process/ProcessRunTokenObservations.js +48 -0
- package/dist/process/ProviderDiagnosticRedaction.js +17 -0
- package/dist/process/ProviderProcess.js +4 -3
- package/dist/process/capture/FilesystemSnapshot.js +28 -4
- package/dist/process/capture/ProcessCaptureLifecycle.js +350 -59
- package/dist/process/capture/ProcessCaptureProgress.js +62 -0
- package/dist/process/capture/ProcessHarness.js +194 -26
- package/dist/process/capture/ProcessNormalization.js +3 -1
- package/dist/process/capture/ProcessScenarioRuntimeValidation.js +5 -2
- package/dist/process/capture/TerminalRenderer.js +24 -7
- package/dist/reference/ReferenceSourceReader.js +22 -5
- package/dist/reference/ReferenceSourceReaderEntries.js +114 -51
- package/dist/reference/ReferenceSourceReaderErrors.js +12 -0
- package/dist/reference/ReferenceSourceReaderFile.js +50 -10
- package/dist/reference/ReferenceSourceReaderValidate.js +4 -4
- package/dist/server/EvidenceMcpServer.js +36 -1
- package/dist/server/admittedToolOperation.js +9 -0
- package/dist/server/contractToolHandler.js +21 -0
- package/dist/server/createServer.js +97 -25
- package/dist/server/registerAdbTools.js +36 -0
- package/dist/server/registerAnalysisViewTool.js +4 -9
- package/dist/server/registerAndroidTools.js +3 -12
- package/dist/server/registerApktoolTools.js +14 -0
- package/dist/server/registerApplicationTools/compareExportShapes.js +4 -6
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
- package/dist/server/registerApplicationTools/compareVersions.js +3 -2
- package/dist/server/registerApplicationTools/coverage.js +3 -2
- package/dist/server/registerApplicationTools/obligationLedger.js +3 -2
- package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -2
- package/dist/server/registerApplicationTools/traceFeature.js +3 -2
- package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
- package/dist/server/registerArtifactComparisonTool.js +5 -2
- package/dist/server/registerBinaryDiagnosticsTools.js +16 -4
- package/dist/server/registerBrowserScenarioTool.js +10 -7
- package/dist/server/registerBrowserTools.js +12 -9
- package/dist/server/registerBundleComparisonTool.js +16 -2
- package/dist/server/registerCloseLifecycleTool.js +32 -3
- package/dist/server/registerElectronTools.js +28 -10
- package/dist/server/registerEvmTools.js +4 -9
- package/dist/server/registerFirmwareTools.js +3 -11
- package/dist/server/registerFunctionComparisonTool.js +5 -2
- package/dist/server/registerJavaScriptRecoveryTool.js +4 -9
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +9 -6
- package/dist/server/registerJebTools.js +16 -0
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -6
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -2
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +3 -2
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +3 -2
- package/dist/server/registerPeResourcesTool.js +9 -0
- package/dist/server/registerProcessComparisonTool.js +5 -2
- package/dist/server/registerRecordedCrashTools.js +4 -9
- package/dist/server/registerSessionRecordTools.js +2 -1
- package/dist/server/registerSessionTools.js +49 -18
- package/dist/server/registerWebModuleTool.js +4 -9
- package/dist/server/registerWebNetworkCaptureTool.js +4 -9
- package/dist/server/registerWebRuntimeTools.js +6 -5
- package/dist/server/registerWebScriptTool.js +6 -3
- package/dist/server/registerWebSourceLocationTool.js +4 -9
- package/dist/server/toolResult.js +21 -2
- package/dist/windows/WindowsPrivateRuntime.js +12 -5
- package/install.sh +7 -4
- package/licenses/nativeaot-parser-MIT.txt +28 -0
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +33 -5
- package/scripts/rea.mjs +16 -1
- package/skills/reverse-engineer-anything/SKILL.md +52 -51
- package/skills/reverse-engineer-anything/references/connection-and-recovery.md +127 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +92 -13
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +22 -1
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { constants } from "node:fs";
|
|
2
|
-
import { lstat, open, opendir, realpath } from "node:fs/promises";
|
|
2
|
+
import { lstat, open, opendir, realpath, } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, join, relative, sep } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
5
|
import { ArtifactReaderFailure, } from "./ArtifactReader.js";
|
|
6
|
-
|
|
6
|
+
import { OwnedDirectoryHandle } from "../filesystem/OwnedDirectoryHandle.js";
|
|
7
|
+
import { OwnedFileHandle } from "../filesystem/OwnedFileHandle.js";
|
|
8
|
+
import { readFileHandleChunks } from "../filesystem/readFileHandleChunks.js";
|
|
9
|
+
/** Non-symlink-following directory reader. */
|
|
7
10
|
export class DirectoryArtifactReader {
|
|
8
11
|
format = "directory";
|
|
9
12
|
#rootPromise;
|
|
10
13
|
#rootPath;
|
|
14
|
+
#directories = new Set();
|
|
15
|
+
#files = new Map();
|
|
11
16
|
constructor(root) {
|
|
12
17
|
this.#rootPath = root;
|
|
13
|
-
this.#rootPromise = realpath(root);
|
|
14
18
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
19
|
+
/** Enumerate entries, optionally restricting descent while retaining directories. */
|
|
20
|
+
async *entries(signal, descendInto) {
|
|
21
|
+
const root = await this.#resolveRoot();
|
|
19
22
|
const pending = [root];
|
|
20
23
|
while (pending.length > 0) {
|
|
21
24
|
abortIfNeeded(signal);
|
|
@@ -23,74 +26,84 @@ export class DirectoryArtifactReader {
|
|
|
23
26
|
if (directory === undefined)
|
|
24
27
|
break;
|
|
25
28
|
await withDirectoryIoContext("inspect directory", directory, () => assertContainedDirectory(root, directory));
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
throw directoryIoFailure("open directory", directory, cause);
|
|
29
|
-
});
|
|
30
|
-
try {
|
|
31
|
-
for await (const child of handle)
|
|
32
|
-
children.push(child.name);
|
|
33
|
-
}
|
|
34
|
-
catch (cause) {
|
|
35
|
-
throw directoryIoFailure("read directory", directory, cause);
|
|
36
|
-
}
|
|
37
|
-
finally {
|
|
38
|
-
// best-effort cleanup: directory-handle close must not mask traversal.
|
|
39
|
-
await handle.close().catch(() => undefined);
|
|
40
|
-
}
|
|
29
|
+
for await (const entry of this.#readDirectory(directory, pending, signal, descendInto))
|
|
30
|
+
yield entry;
|
|
41
31
|
await withDirectoryIoContext("inspect directory", directory, () => assertContainedDirectory(root, directory));
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async #resolveRoot() {
|
|
35
|
+
return (this.#rootPromise ??= realpath(this.#rootPath)).catch((cause) => {
|
|
36
|
+
throw directoryIoFailure("resolve artifact root", this.#rootPath, cause);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async *#readDirectory(directory, pending, signal, descendInto) {
|
|
40
|
+
const root = await this.#resolveRoot();
|
|
41
|
+
const handle = new OwnedDirectoryHandle(await opendir(directory).catch((cause) => {
|
|
42
|
+
throw directoryIoFailure("open directory", directory, cause);
|
|
43
|
+
}));
|
|
44
|
+
this.#directories.add(handle);
|
|
45
|
+
const childDirectories = [];
|
|
46
|
+
let traversal = {
|
|
47
|
+
kind: "complete",
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
for (;;) {
|
|
51
|
+
const child = await handle.handle.read();
|
|
52
|
+
if (child === null)
|
|
53
|
+
break;
|
|
45
54
|
abortIfNeeded(signal);
|
|
46
|
-
const absolute = join(directory, name);
|
|
55
|
+
const absolute = join(directory, child.name);
|
|
47
56
|
const metadata = await lstat(absolute).catch((cause) => {
|
|
48
57
|
throw directoryIoFailure("inspect entry", absolute, cause);
|
|
49
58
|
});
|
|
50
59
|
const path = relative(root, absolute).split(sep).join("/");
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
: metadata.isDirectory()
|
|
54
|
-
? "directory"
|
|
55
|
-
: metadata.isFile()
|
|
56
|
-
? "file"
|
|
57
|
-
: undefined;
|
|
58
|
-
if (kind === undefined)
|
|
60
|
+
const entry = artifactEntry(path, absolute, metadata);
|
|
61
|
+
if (entry === undefined)
|
|
59
62
|
continue;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
path,
|
|
64
|
-
kind,
|
|
65
|
-
declaredSize: kind === "file" ? metadata.size : null,
|
|
66
|
-
compressedSize: null,
|
|
67
|
-
executable: (metadata.mode & 0o111) !== 0,
|
|
68
|
-
encrypted: false,
|
|
69
|
-
byteOffset: null,
|
|
70
|
-
declaredSha256: null,
|
|
71
|
-
unpacked: false,
|
|
72
|
-
limitations: kind === "symlink"
|
|
73
|
-
? ["Symlink target was not followed or disclosed."]
|
|
74
|
-
: [],
|
|
75
|
-
adapterKey: absolute,
|
|
76
|
-
...(kind === "file"
|
|
77
|
-
? { sourceIdentity: { device: metadata.dev, inode: metadata.ino } }
|
|
78
|
-
: {}),
|
|
79
|
-
};
|
|
63
|
+
yield entry;
|
|
64
|
+
if (entry.kind === "directory" && (descendInto?.(path) ?? true))
|
|
65
|
+
childDirectories.push(absolute);
|
|
80
66
|
}
|
|
81
|
-
|
|
82
|
-
|
|
67
|
+
}
|
|
68
|
+
catch (cause) {
|
|
69
|
+
traversal = {
|
|
70
|
+
kind: "failed",
|
|
71
|
+
cause: cause instanceof ArtifactReaderFailure
|
|
72
|
+
? cause
|
|
73
|
+
: directoryIoFailure("read directory", directory, cause),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
await this.#finishDirectory(handle, directory, traversal);
|
|
78
|
+
}
|
|
79
|
+
if (traversal.kind === "failed")
|
|
80
|
+
throw traversal.cause;
|
|
81
|
+
childDirectories.reverse();
|
|
82
|
+
pending.push(...childDirectories);
|
|
83
|
+
}
|
|
84
|
+
async #finishDirectory(handle, path, traversal) {
|
|
85
|
+
try {
|
|
86
|
+
await handle.close();
|
|
87
|
+
this.#directories.delete(handle);
|
|
88
|
+
}
|
|
89
|
+
catch (cause) {
|
|
90
|
+
const closeFailure = directoryIoFailure("close directory", path, cause);
|
|
91
|
+
if (traversal.kind === "failed")
|
|
92
|
+
throw ArtifactReaderFailure.withCleanup(traversal.cause, ArtifactReaderFailure.cleanupObservation(closeFailure, path));
|
|
93
|
+
throw closeFailure;
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
96
|
async open(entry, signal) {
|
|
86
97
|
abortIfNeeded(signal);
|
|
87
98
|
if (entry.kind !== "file")
|
|
88
99
|
throw new ArtifactReaderFailure("format", "Only regular files can be opened");
|
|
89
|
-
const
|
|
100
|
+
const fileHandle = await open(entry.adapterKey, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK).catch((cause) => {
|
|
90
101
|
throw directoryIoFailure("open entry", entry.adapterKey, cause);
|
|
91
102
|
});
|
|
103
|
+
const owner = new OwnedFileHandle(fileHandle);
|
|
104
|
+
this.#files.set(owner, entry.adapterKey);
|
|
92
105
|
try {
|
|
93
|
-
const observed = await handle.stat().catch((cause) => {
|
|
106
|
+
const observed = await owner.handle.stat().catch((cause) => {
|
|
94
107
|
throw directoryIoFailure("inspect opened entry", entry.adapterKey, cause);
|
|
95
108
|
});
|
|
96
109
|
if (!observed.isFile() ||
|
|
@@ -99,21 +112,95 @@ export class DirectoryArtifactReader {
|
|
|
99
112
|
observed.ino !== entry.sourceIdentity.inode) {
|
|
100
113
|
throw new ArtifactReaderFailure("integrity", `Directory entry changed before open: ${entry.path}`);
|
|
101
114
|
}
|
|
102
|
-
|
|
115
|
+
abortIfNeeded(signal);
|
|
116
|
+
const source = Readable.from(mapFileReadCancellation(owner.handle, signal), { objectMode: false });
|
|
117
|
+
source.once("close", () => {
|
|
118
|
+
void this.#closeFile(owner).catch(() => undefined);
|
|
119
|
+
});
|
|
120
|
+
return source;
|
|
103
121
|
}
|
|
104
122
|
catch (cause) {
|
|
105
|
-
|
|
106
|
-
|
|
123
|
+
try {
|
|
124
|
+
await this.#closeFile(owner);
|
|
125
|
+
}
|
|
126
|
+
catch (closeCause) {
|
|
127
|
+
throw ArtifactReaderFailure.withCleanup(cause, ArtifactReaderFailure.cleanupObservation(directoryIoFailure("close opened entry", entry.adapterKey, closeCause), entry.adapterKey));
|
|
128
|
+
}
|
|
107
129
|
throw cause;
|
|
108
130
|
}
|
|
109
131
|
}
|
|
110
|
-
close() {
|
|
111
|
-
|
|
132
|
+
async close() {
|
|
133
|
+
const failures = [];
|
|
134
|
+
for (const [owner, path] of this.#files) {
|
|
135
|
+
try {
|
|
136
|
+
await this.#closeFile(owner);
|
|
137
|
+
}
|
|
138
|
+
catch (cause) {
|
|
139
|
+
failures.push(directoryIoFailure("close opened entry", path, cause));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
for (const owner of this.#directories) {
|
|
143
|
+
try {
|
|
144
|
+
await owner.close();
|
|
145
|
+
this.#directories.delete(owner);
|
|
146
|
+
}
|
|
147
|
+
catch (cause) {
|
|
148
|
+
failures.push(directoryIoFailure("close directory", owner.handle.path, cause));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (failures.length > 0) {
|
|
152
|
+
const reason = failures.map(failureMessage).join("; ");
|
|
153
|
+
throw new ArtifactReaderFailure("io", `Directory artifact cleanup failed: ${reason}`, {
|
|
154
|
+
cause: new AggregateError(failures),
|
|
155
|
+
cleanup: {
|
|
156
|
+
reason,
|
|
157
|
+
resources: [
|
|
158
|
+
...this.#files.values(),
|
|
159
|
+
...[...this.#directories].map((owner) => owner.handle.path),
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async #closeFile(owner) {
|
|
166
|
+
await owner.close();
|
|
167
|
+
this.#files.delete(owner);
|
|
112
168
|
}
|
|
113
169
|
provenance() {
|
|
114
170
|
return [];
|
|
115
171
|
}
|
|
116
172
|
}
|
|
173
|
+
const artifactEntry = (path, absolute, metadata) => {
|
|
174
|
+
const kind = metadata.isSymbolicLink()
|
|
175
|
+
? "symlink"
|
|
176
|
+
: metadata.isDirectory()
|
|
177
|
+
? "directory"
|
|
178
|
+
: metadata.isFile()
|
|
179
|
+
? "file"
|
|
180
|
+
: undefined;
|
|
181
|
+
if (kind === undefined)
|
|
182
|
+
return undefined;
|
|
183
|
+
return {
|
|
184
|
+
path,
|
|
185
|
+
kind,
|
|
186
|
+
declaredSize: kind === "file" ? metadata.size : null,
|
|
187
|
+
compressedSize: null,
|
|
188
|
+
executable: (metadata.mode & 0o111) !== 0,
|
|
189
|
+
encrypted: false,
|
|
190
|
+
byteOffset: null,
|
|
191
|
+
declaredSha256: null,
|
|
192
|
+
unpacked: false,
|
|
193
|
+
limitations: kind === "symlink"
|
|
194
|
+
? ["Symlink target was not followed or disclosed."]
|
|
195
|
+
: [],
|
|
196
|
+
adapterKey: absolute,
|
|
197
|
+
...(kind === "file"
|
|
198
|
+
? {
|
|
199
|
+
sourceIdentity: { device: metadata.dev, inode: metadata.ino },
|
|
200
|
+
}
|
|
201
|
+
: {}),
|
|
202
|
+
};
|
|
203
|
+
};
|
|
117
204
|
const directoryIoFailure = (operation, path, cause) => {
|
|
118
205
|
if (cause instanceof ArtifactReaderFailure)
|
|
119
206
|
return cause;
|
|
@@ -123,7 +210,23 @@ const directoryIoFailure = (operation, path, cause) => {
|
|
|
123
210
|
typeof cause.code === "string"
|
|
124
211
|
? ` (${cause.code})`
|
|
125
212
|
: "";
|
|
126
|
-
|
|
213
|
+
const detail = failureMessage(cause);
|
|
214
|
+
return new ArtifactReaderFailure("io", `Could not ${operation} at ${path}${code}: ${detail}`, { cause });
|
|
215
|
+
};
|
|
216
|
+
const failureMessage = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
217
|
+
const mapFileReadCancellation = async function* (handle, signal) {
|
|
218
|
+
try {
|
|
219
|
+
for await (const chunk of readFileHandleChunks(handle, { signal })) {
|
|
220
|
+
abortIfNeeded(signal);
|
|
221
|
+
yield chunk;
|
|
222
|
+
}
|
|
223
|
+
abortIfNeeded(signal);
|
|
224
|
+
}
|
|
225
|
+
catch (cause) {
|
|
226
|
+
if (signal?.aborted === true)
|
|
227
|
+
throw new ArtifactReaderFailure("cancelled", "Directory artifact read cancelled", { cause });
|
|
228
|
+
throw cause;
|
|
229
|
+
}
|
|
127
230
|
};
|
|
128
231
|
const withDirectoryIoContext = async (operation, path, action) => {
|
|
129
232
|
try {
|
|
@@ -1,22 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { open as openFile, stat } from "node:fs/promises";
|
|
1
|
+
import { lstat } from "node:fs/promises";
|
|
3
2
|
import { Readable } from "node:stream";
|
|
4
3
|
import { XcrunCommandRunner, } from "../native/CommandRunner.js";
|
|
5
4
|
import { parseLipoArchitectures, } from "../native/parsers/lipo.js";
|
|
5
|
+
import { OwnedFileHandle } from "../filesystem/OwnedFileHandle.js";
|
|
6
6
|
import { readMachoImage } from "./apple/MachoLoadCommandReader.js";
|
|
7
|
-
import { ArtifactReaderFailure, } from "./ArtifactReader.js";
|
|
7
|
+
import { ArtifactReaderFailure, copyArtifactEntry, sameArtifactEntry, } from "./ArtifactReader.js";
|
|
8
8
|
import { streamChunkToBuffer } from "./StreamBytes.js";
|
|
9
|
+
import { NonRegularFileReadError, RegularFileAdmissionFailure, openRegularFile, sameRegularFileState, } from "../filesystem/RegularFile.js";
|
|
10
|
+
import { readFileHandleChunks } from "../filesystem/readFileHandleChunks.js";
|
|
9
11
|
/** Read-only universal Mach-O slice reader backed by native lipo metadata. */
|
|
10
12
|
export class MachOSliceArtifactReader {
|
|
11
13
|
path;
|
|
12
14
|
runner;
|
|
13
15
|
format = "file";
|
|
14
16
|
#command;
|
|
15
|
-
|
|
17
|
+
#source;
|
|
18
|
+
#ownedSource;
|
|
19
|
+
#pendingSource;
|
|
20
|
+
#entries = new Map();
|
|
21
|
+
#ownsSource;
|
|
22
|
+
#closed = false;
|
|
23
|
+
#closePromise;
|
|
24
|
+
constructor(path, environment, runner = new XcrunCommandRunner(environment), source) {
|
|
16
25
|
this.path = path;
|
|
17
26
|
this.runner = runner;
|
|
27
|
+
this.#source = source;
|
|
28
|
+
this.#ownsSource = source === undefined;
|
|
18
29
|
}
|
|
19
30
|
async *entries(signal) {
|
|
31
|
+
this.#entries.clear();
|
|
32
|
+
const source = await this.#ensureSource();
|
|
33
|
+
await this.#verifySource(source);
|
|
20
34
|
const captured = await this.runner.run("lipo", ["-detailed_info", this.path], signal === undefined ? {} : { signal });
|
|
21
35
|
if (!captured.ok)
|
|
22
36
|
throw new ArtifactReaderFailure(captured.error.reason === "cancelled" ? "cancelled" : "unavailable", "lipo could not enumerate universal Mach-O slices", { cause: captured.error });
|
|
@@ -28,9 +42,11 @@ export class MachOSliceArtifactReader {
|
|
|
28
42
|
exit_code: captured.value.exitCode,
|
|
29
43
|
effects: ["read"],
|
|
30
44
|
};
|
|
31
|
-
|
|
45
|
+
await this.#verifySource(source);
|
|
46
|
+
const fileSize = source.initial.size;
|
|
32
47
|
const architectures = parseLipoArchitectures(captured.value.stdout);
|
|
33
|
-
const structural = await readStructuralSlices(
|
|
48
|
+
const structural = await readStructuralSlices(source.handle, fileSize);
|
|
49
|
+
await this.#verifySource(source);
|
|
34
50
|
if (structural.status === "malformed")
|
|
35
51
|
throw new ArtifactReaderFailure("integrity", `Mach-O structural slice index is malformed: ${structural.reason}`);
|
|
36
52
|
if (structural.status === "unsupported")
|
|
@@ -63,7 +79,7 @@ export class MachOSliceArtifactReader {
|
|
|
63
79
|
!Number.isSafeInteger(offset + sliceSize) ||
|
|
64
80
|
offset + sliceSize > fileSize)
|
|
65
81
|
throw new ArtifactReaderFailure("integrity", `lipo reported an out-of-bounds Mach-O slice: ${architecture.name}`);
|
|
66
|
-
|
|
82
|
+
const entry = {
|
|
67
83
|
path: `slices/${architecture.name}`,
|
|
68
84
|
kind: "slice",
|
|
69
85
|
declaredSize: sliceSize,
|
|
@@ -99,33 +115,40 @@ export class MachOSliceArtifactReader {
|
|
|
99
115
|
],
|
|
100
116
|
adapterKey: `${String(offset)}:${String(sliceSize)}`,
|
|
101
117
|
};
|
|
118
|
+
this.#entries.set(entry.adapterKey, copyArtifactEntry(entry));
|
|
119
|
+
yield entry;
|
|
102
120
|
}
|
|
103
121
|
}
|
|
104
122
|
async open(entry, signal) {
|
|
105
123
|
if (signal?.aborted === true)
|
|
106
124
|
return Promise.reject(new ArtifactReaderFailure("cancelled", "Mach-O slice read cancelled"));
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
125
|
+
const produced = this.#entries.get(entry.adapterKey);
|
|
126
|
+
if (produced === undefined || !sameArtifactEntry(entry, produced))
|
|
127
|
+
throw new ArtifactReaderFailure("integrity", "Mach-O slice entry metadata does not match this reader's inventory");
|
|
128
|
+
const offset = produced.byteOffset;
|
|
129
|
+
const size = produced.declaredSize;
|
|
130
|
+
if (offset === null ||
|
|
113
131
|
size === null ||
|
|
132
|
+
!Number.isSafeInteger(offset) ||
|
|
133
|
+
!Number.isSafeInteger(size) ||
|
|
114
134
|
offset < 0 ||
|
|
115
135
|
size <= 0)
|
|
116
136
|
throw new ArtifactReaderFailure("integrity", "Invalid Mach-O slice byte range");
|
|
117
|
-
const
|
|
118
|
-
|
|
137
|
+
const source = await this.#ensureSource();
|
|
138
|
+
await this.#verifySource(source);
|
|
139
|
+
if (!Number.isSafeInteger(offset + size) ||
|
|
140
|
+
offset + size > source.initial.size)
|
|
119
141
|
throw new ArtifactReaderFailure("integrity", `Mach-O slice range is outside the artifact: ${entry.path}`);
|
|
120
|
-
const
|
|
142
|
+
const sourceStream = readFileHandleChunks(source.handle, {
|
|
121
143
|
start: offset,
|
|
122
144
|
end: offset + size - 1,
|
|
123
145
|
...(signal === undefined ? {} : { signal }),
|
|
124
146
|
});
|
|
147
|
+
const verifySource = () => this.#verifySource(source);
|
|
125
148
|
return Readable.from((async function* () {
|
|
126
149
|
let observedBytes = 0;
|
|
127
150
|
try {
|
|
128
|
-
for await (const raw of
|
|
151
|
+
for await (const raw of sourceStream) {
|
|
129
152
|
const chunk = streamChunkToBuffer(raw);
|
|
130
153
|
observedBytes += chunk.byteLength;
|
|
131
154
|
if (observedBytes > size)
|
|
@@ -142,30 +165,90 @@ export class MachOSliceArtifactReader {
|
|
|
142
165
|
}
|
|
143
166
|
if (observedBytes !== size)
|
|
144
167
|
throw new ArtifactReaderFailure("integrity", `Mach-O slice size disagrees with lipo metadata: ${entry.path}`);
|
|
168
|
+
await verifySource();
|
|
145
169
|
})());
|
|
146
170
|
}
|
|
147
171
|
provenance() {
|
|
148
172
|
return this.#command === undefined ? [] : [structuredClone(this.#command)];
|
|
149
173
|
}
|
|
150
|
-
close() {
|
|
151
|
-
|
|
174
|
+
async close() {
|
|
175
|
+
this.#closed = true;
|
|
176
|
+
this.#closePromise ??= this.#closeSource().catch((cause) => {
|
|
177
|
+
this.#closePromise = undefined;
|
|
178
|
+
throw cause;
|
|
179
|
+
});
|
|
180
|
+
return this.#closePromise;
|
|
152
181
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
182
|
+
async #ensureSource() {
|
|
183
|
+
if (this.#closed)
|
|
184
|
+
throw new ArtifactReaderFailure("unavailable", "Universal Mach-O reader is closed");
|
|
185
|
+
if (this.#source !== undefined)
|
|
186
|
+
return this.#source;
|
|
187
|
+
this.#pendingSource ??= this.#acquireSource();
|
|
188
|
+
const source = await this.#pendingSource;
|
|
189
|
+
if (this.#closed)
|
|
190
|
+
throw new ArtifactReaderFailure("unavailable", "Universal Mach-O reader closed during source acquisition");
|
|
191
|
+
return source;
|
|
192
|
+
}
|
|
193
|
+
async #acquireSource() {
|
|
194
|
+
let handle;
|
|
195
|
+
try {
|
|
196
|
+
handle = await openRegularFile(this.path, { symlinks: "reject" });
|
|
197
|
+
}
|
|
198
|
+
catch (cause) {
|
|
199
|
+
if (!(cause instanceof RegularFileAdmissionFailure))
|
|
200
|
+
throw cause;
|
|
201
|
+
this.#ownedSource = cause.owner;
|
|
202
|
+
const primary = cause.cause instanceof NonRegularFileReadError
|
|
203
|
+
? new ArtifactReaderFailure("format", `Universal Mach-O source is not a regular file: ${this.path}`, { cause: cause.cause })
|
|
204
|
+
: cause.cause;
|
|
205
|
+
throw ArtifactReaderFailure.withCleanup(primary, ArtifactReaderFailure.cleanupObservation(cause.cleanupCause, this.path));
|
|
206
|
+
}
|
|
207
|
+
const owner = new OwnedFileHandle(handle);
|
|
208
|
+
this.#ownedSource = owner;
|
|
209
|
+
try {
|
|
210
|
+
const initial = await handle.stat();
|
|
211
|
+
const source = { handle, initial };
|
|
212
|
+
this.#source = source;
|
|
213
|
+
return source;
|
|
214
|
+
}
|
|
215
|
+
catch (cause) {
|
|
216
|
+
try {
|
|
217
|
+
await owner.close();
|
|
218
|
+
this.#ownedSource = undefined;
|
|
219
|
+
}
|
|
220
|
+
catch (cleanupCause) {
|
|
221
|
+
throw ArtifactReaderFailure.withCleanup(cause, ArtifactReaderFailure.cleanupObservation(cleanupCause, this.path));
|
|
222
|
+
}
|
|
223
|
+
throw cause;
|
|
224
|
+
}
|
|
165
225
|
}
|
|
166
|
-
|
|
167
|
-
await
|
|
226
|
+
async #closeSource() {
|
|
227
|
+
await this.#pendingSource?.catch(() => undefined);
|
|
228
|
+
if (!this.#ownsSource || this.#ownedSource === undefined)
|
|
229
|
+
return;
|
|
230
|
+
await this.#ownedSource.close();
|
|
231
|
+
this.#ownedSource = undefined;
|
|
232
|
+
this.#source = undefined;
|
|
168
233
|
}
|
|
234
|
+
async #verifySource(source) {
|
|
235
|
+
const [opened, currentPath] = await Promise.all([
|
|
236
|
+
source.handle.stat(),
|
|
237
|
+
lstat(this.path),
|
|
238
|
+
]);
|
|
239
|
+
if (!sameRegularFileState(source.initial, opened) ||
|
|
240
|
+
!sameRegularFileState(source.initial, currentPath))
|
|
241
|
+
throw new ArtifactReaderFailure("integrity", `Universal Mach-O source changed during inventory: ${this.path}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Compare lipo's independent ranges with structurally parsed slice identity. */
|
|
245
|
+
const readStructuralSlices = async (file, size) => {
|
|
246
|
+
const readAt = async (offset, length) => {
|
|
247
|
+
const bytes = Buffer.alloc(length);
|
|
248
|
+
const { bytesRead } = await file.read(bytes, 0, length, offset);
|
|
249
|
+
return bytes.subarray(0, bytesRead);
|
|
250
|
+
};
|
|
251
|
+
return readMachoImage(readAt, size);
|
|
169
252
|
};
|
|
170
253
|
const lipoMatchesSlice = (reported, observed, structurallyUnique) => {
|
|
171
254
|
const observedCpuType = observed.fat_cpu_type ?? observed.cpu_type;
|
|
@@ -194,9 +277,3 @@ const lipoMatchesSlice = (reported, observed, structurallyUnique) => {
|
|
|
194
277
|
*/
|
|
195
278
|
const lipoNameMatches = (reported, observed) => reported === observed ||
|
|
196
279
|
(observed === "arm64e" && /^arm64e\.[A-Za-z0-9_]+$/u.test(reported));
|
|
197
|
-
const parseSliceKeyInteger = (value) => {
|
|
198
|
-
if (value === undefined || !/^\d+$/u.test(value))
|
|
199
|
-
return null;
|
|
200
|
-
const parsed = Number(value);
|
|
201
|
-
return Number.isSafeInteger(parsed) ? parsed : null;
|
|
202
|
-
};
|
|
@@ -49,9 +49,10 @@ const createSystemHost = (environment) => ({
|
|
|
49
49
|
/** Read-only macOS DMG adapter that owns attachment and reverse-order detach. */
|
|
50
50
|
export class NativeDmgArtifactReader {
|
|
51
51
|
path;
|
|
52
|
-
host;
|
|
53
52
|
format = "file";
|
|
53
|
+
host;
|
|
54
54
|
#provenance = [];
|
|
55
|
+
#initialization;
|
|
55
56
|
#directory;
|
|
56
57
|
#devices = [];
|
|
57
58
|
#inventoryConfirmedDevices = new Set();
|
|
@@ -61,34 +62,41 @@ export class NativeDmgArtifactReader {
|
|
|
61
62
|
#attachOutputReturned = false;
|
|
62
63
|
#attachMayHaveMounted = false;
|
|
63
64
|
#ownershipUncertainty;
|
|
64
|
-
|
|
65
|
+
#closed = false;
|
|
66
|
+
#closePromise;
|
|
67
|
+
constructor(path, environment, host) {
|
|
65
68
|
this.path = path;
|
|
66
|
-
this.host = host;
|
|
67
|
-
}
|
|
68
|
-
/** Verify and attach one image beneath an exclusively owned temporary root. */
|
|
69
|
-
static async create(path, environment, signal, host) {
|
|
70
69
|
if (process.platform !== "darwin" && host === undefined)
|
|
71
70
|
throw new ArtifactReaderFailure("unavailable", "Native DMG traversal is available only on macOS");
|
|
72
|
-
|
|
73
|
-
await reader.attach(signal);
|
|
74
|
-
return reader;
|
|
71
|
+
this.host = host ?? createSystemHost(environment);
|
|
75
72
|
}
|
|
76
73
|
async *entries(signal) {
|
|
74
|
+
await this.#ensureAttached(signal);
|
|
77
75
|
if (this.#directory === undefined)
|
|
78
76
|
throw new ArtifactReaderFailure("unavailable", "DMG is not attached");
|
|
79
77
|
const prefix = basename(this.path);
|
|
80
78
|
for await (const entry of this.#directory.entries(signal))
|
|
81
79
|
yield { ...entry, path: `${prefix}/${entry.path}` };
|
|
82
80
|
}
|
|
83
|
-
open(entry, signal) {
|
|
81
|
+
async open(entry, signal) {
|
|
82
|
+
await this.#ensureAttached(signal);
|
|
84
83
|
if (this.#directory === undefined)
|
|
85
|
-
|
|
84
|
+
throw new ArtifactReaderFailure("unavailable", "DMG is not attached");
|
|
86
85
|
return this.#directory.open(entry, signal);
|
|
87
86
|
}
|
|
88
87
|
provenance() {
|
|
89
88
|
return structuredClone(this.#provenance);
|
|
90
89
|
}
|
|
91
|
-
|
|
90
|
+
close() {
|
|
91
|
+
this.#closed = true;
|
|
92
|
+
this.#closePromise ??= this.#closeOwnedResources().catch((cause) => {
|
|
93
|
+
this.#closePromise = undefined;
|
|
94
|
+
throw cause;
|
|
95
|
+
});
|
|
96
|
+
return this.#closePromise;
|
|
97
|
+
}
|
|
98
|
+
async #closeOwnedResources() {
|
|
99
|
+
await this.#initialization?.catch(() => undefined);
|
|
92
100
|
let detachFailure = await this.#reconcileAttachState();
|
|
93
101
|
let remainingDevices = [];
|
|
94
102
|
for (const device of [...this.#devices].reverse()) {
|
|
@@ -190,7 +198,15 @@ export class NativeDmgArtifactReader {
|
|
|
190
198
|
return true;
|
|
191
199
|
}
|
|
192
200
|
}
|
|
193
|
-
async
|
|
201
|
+
async #ensureAttached(signal) {
|
|
202
|
+
if (this.#closed)
|
|
203
|
+
throw new ArtifactReaderFailure("unavailable", "DMG reader is closed");
|
|
204
|
+
this.#initialization ??= this.#attach(signal);
|
|
205
|
+
await this.#initialization;
|
|
206
|
+
if (this.#closed)
|
|
207
|
+
throw new ArtifactReaderFailure("unavailable", "DMG reader is closed");
|
|
208
|
+
}
|
|
209
|
+
async #attach(signal) {
|
|
194
210
|
await runChecked(this.host, ["verify", this.path], signal);
|
|
195
211
|
this.#provenance.push(command(["verify", this.path], ["read"]));
|
|
196
212
|
const baseline = await this.#readInfo();
|
|
@@ -249,15 +265,6 @@ export class NativeDmgArtifactReader {
|
|
|
249
265
|
this.#attachMayHaveMounted = false;
|
|
250
266
|
this.#ownershipUncertainty = undefined;
|
|
251
267
|
}
|
|
252
|
-
let cleanupFailure;
|
|
253
|
-
try {
|
|
254
|
-
await this.close();
|
|
255
|
-
}
|
|
256
|
-
catch (cleanupCause) {
|
|
257
|
-
cleanupFailure = cleanupCause;
|
|
258
|
-
}
|
|
259
|
-
if (cleanupFailure !== undefined)
|
|
260
|
-
throw ArtifactReaderFailure.withCleanup(cause, ArtifactReaderFailure.cleanupObservation(cleanupFailure, `DMG mount root ${this.#mountRoot ?? this.path}`));
|
|
261
268
|
throw cause;
|
|
262
269
|
}
|
|
263
270
|
}
|