@cyberstrike-io/cyberstrike 1.1.17-beta.2 → 1.1.17-beta.4
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/hackbrowser-worker.js +501 -249
- package/package.json +12 -12
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-10_concurrent-session-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-11(1)_pattern-hiding-displays/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-11_device-lock/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-12(1)_user-initiated-logouts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-12(2)_termination-message/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-12(3)_timeout-warning-message/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-12_session-termination/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-13_supervision-and-review-access-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-14(1)_necessary-uses/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-14_permitted-actions-without-identification-or-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-15_automated-marking/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(1)_dynamic-attribute-association/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(10)_attribute-configuration-by-authorized-individuals/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(2)_attribute-value-changes-by-authorized-individuals/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(3)_maintenance-of-attribute-associations-by-system/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(4)_association-of-attributes-by-authorized-individuals/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(5)_attribute-displays-on-objects-to-be-output/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(6)_maintenance-of-attribute-association/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(7)_consistent-attribute-interpretation/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(8)_association-techniques-and-technologies/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16(9)_attribute-reassignment-regrading-mechanisms/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-16_security-and-privacy-attributes/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(1)_monitoring-and-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(10)_authenticate-remote-commands/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(2)_protection-of-confidentiality-and-integrity-using-encryption/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(3)_managed-access-control-points/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(4)_privileged-commands-and-access/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(5)_monitoring-for-unauthorized-connections/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(6)_protection-of-mechanism-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(7)_additional-protection-for-security-function-access/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(8)_disable-nonsecure-network-protocols/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17(9)_disconnect-or-disable-access/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-17_remote-access/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-18(1)_authentication-and-encryption/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-18(2)_monitoring-unauthorized-connections/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-18(3)_disable-wireless-networking/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-18(4)_restrict-configurations-by-users/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-18(5)_antennas-and-transmission-power-levels/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-18_wireless-access/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-19(1)_use-of-writable-and-portable-storage-devices/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-19(2)_use-of-personally-owned-portable-storage-devices/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-19(3)_use-of-portable-storage-devices-with-no-identifiable-owner/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-19(4)_restrictions-for-classified-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-19(5)_full-device-or-container-based-encryption/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-19_access-control-for-mobile-devices/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-1_policy-and-procedures/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(1)_automated-system-account-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(10)_shared-and-group-account-credential-change/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(11)_usage-conditions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(12)_account-monitoring-for-atypical-usage/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(13)_disable-accounts-for-high-risk-individuals/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(2)_automated-temporary-and-emergency-account-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(3)_disable-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(4)_automated-audit-actions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(5)_inactivity-logout/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(6)_dynamic-privilege-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(7)_privileged-user-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(8)_dynamic-account-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2(9)_restrictions-on-use-of-shared-and-group-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-20(1)_limits-on-authorized-use/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-20(2)_portable-storage-devices-restricted-use/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-20(3)_non-organizationally-owned-systems-restricted-use/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-20(4)_network-accessible-storage-devices-prohibited-use/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-20(5)_portable-storage-devices-prohibited-use/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-20_use-of-external-systems/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-21(1)_automated-decision-support/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-21(2)_information-search-and-retrieval/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-21_information-sharing/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-22_publicly-accessible-content/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-23_data-mining-protection/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-24(1)_transmit-access-authorization-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-24(2)_no-user-or-process-identity/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-24_access-control-decisions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-25_reference-monitor/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-2_account-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(1)_restricted-access-to-privileged-functions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(10)_audited-override-of-access-control-mechanisms/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(11)_restrict-access-to-specific-information-types/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(12)_assert-and-enforce-application-access/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(13)_attribute-based-access-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(14)_individual-access/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(15)_discretionary-and-mandatory-access-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(2)_dual-authorization/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(3)_mandatory-access-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(4)_discretionary-access-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(5)_security-relevant-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(6)_protection-of-user-and-system-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(7)_role-based-access-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(8)_revocation-of-access-authorizations/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3(9)_controlled-release/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-3_access-enforcement/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(1)_object-security-and-privacy-attributes/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(10)_enable-and-disable-security-or-privacy-policy-filters/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(11)_configuration-of-security-or-privacy-policy-filters/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(12)_data-type-identifiers/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(13)_decomposition-into-policy-relevant-subcomponents/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(14)_security-or-privacy-policy-filter-constraints/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(15)_detection-of-unsanctioned-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(16)_information-transfers-on-interconnected-systems/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(17)_domain-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(18)_security-attribute-binding/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(19)_validation-of-metadata/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(2)_processing-domains/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(20)_approved-solutions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(21)_physical-or-logical-separation-of-information-flows/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(22)_access-only/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(23)_modify-non-releasable-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(24)_internal-normalized-format/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(25)_data-sanitization/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(26)_audit-filtering-actions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(27)_redundantindependent-filtering-mechanisms/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(28)_linear-filter-pipelines/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(29)_filter-orchestration-engines/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(3)_dynamic-information-flow-control/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(30)_filter-mechanisms-using-multiple-processes/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(31)_failed-content-transfer-prevention/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(32)_process-requirements-for-information-transfer/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(4)_flow-control-of-encrypted-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(5)_embedded-data-types/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(6)_metadata/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(7)_one-way-flow-mechanisms/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(8)_security-and-privacy-policy-filters/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4(9)_human-reviews/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-4_information-flow-enforcement/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-5_separation-of-duties/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(1)_authorize-access-to-security-functions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(10)_prohibit-non-privileged-users-from-executing-privileged-func/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(2)_non-privileged-access-for-nonsecurity-functions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(3)_network-access-to-privileged-commands/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(4)_separate-processing-domains/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(5)_privileged-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(6)_privileged-access-by-non-organizational-users/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(7)_review-of-user-privileges/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(8)_privilege-levels-for-code-execution/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6(9)_log-use-of-privileged-functions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-6_least-privilege/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-7(1)_automatic-account-lock/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-7(2)_purge-or-wipe-mobile-device/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-7(3)_biometric-attempt-limiting/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-7(4)_use-of-alternate-authentication-factor/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-7_unsuccessful-logon-attempts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-8_system-use-notification/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-9(1)_unsuccessful-logons/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-9(2)_successful-and-unsuccessful-logons/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-9(3)_notification-of-account-changes/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-9(4)_additional-logon-information/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/AC_access-control/AC-9_previous-logon-notification/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-10_adaptive-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-11_re-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-12(1)_supervisor-authorization/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-12(2)_identity-evidence/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-12(3)_identity-evidence-validation-and-verification/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-12(4)_in-person-validation-and-verification/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-12(5)_address-confirmation/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-12(6)_accept-externally-proofed-identities/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-12_identity-proofing/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-13(1)_protection-of-cryptographic-keys/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-13(2)_verification-of-identity-assertions-and-access-tokens/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-13(3)_token-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-13_identity-providers-and-authorization-servers/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-1_policy-and-procedures/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(1)_multi-factor-authentication-to-privileged-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(10)_single-sign-on/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(11)_remote-access-separate-device/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(12)_acceptance-of-piv-credentials/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(13)_out-of-band-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(2)_multi-factor-authentication-to-non-privileged-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(3)_local-access-to-privileged-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(4)_local-access-to-non-privileged-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(5)_individual-authentication-with-group-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(6)_access-to-accounts-separate-device/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(7)_network-access-to-non-privileged-accounts-separate-device/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(8)_access-to-accounts-replay-resistant/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2(9)_network-access-to-non-privileged-accounts-replay-resistant/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-2_identification-and-authentication-organizational-users/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-3(1)_cryptographic-bidirectional-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-3(2)_cryptographic-bidirectional-network-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-3(3)_dynamic-address-allocation/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-3(4)_device-attestation/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-3_device-identification-and-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(1)_prohibit-account-identifiers-as-public-identifiers/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(2)_supervisor-authorization/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(3)_multiple-forms-of-certification/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(4)_identify-user-status/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(5)_dynamic-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(6)_cross-organization-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(7)_in-person-registration/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(8)_pairwise-pseudonymous-identifiers/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4(9)_attribute-maintenance-and-protection/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-4_identifier-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(1)_password-based-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(10)_dynamic-credential-binding/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(11)_hardware-token-based-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(12)_biometric-authentication-performance/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(13)_expiration-of-cached-authenticators/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(14)_managing-content-of-pki-trust-stores/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(15)_gsa-approved-products-and-services/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(16)_in-person-or-trusted-external-party-authenticator-issuance/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(17)_presentation-attack-detection-for-biometric-authenticators/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(18)_password-managers/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(2)_public-key-based-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(3)_in-person-or-trusted-external-party-registration/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(4)_automated-support-for-password-strength-determination/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(5)_change-authenticators-prior-to-delivery/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(6)_protection-of-authenticators/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(7)_no-embedded-unencrypted-static-authenticators/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(8)_multiple-system-accounts/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5(9)_federated-credential-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-5_authenticator-management/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-6_authentication-feedback/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-7_cryptographic-module-authentication/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-8(1)_acceptance-of-piv-credentials-from-other-agencies/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-8(2)_acceptance-of-external-authenticators/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-8(3)_use-of-ficam-approved-products/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-8(4)_use-of-defined-profiles/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-8(5)_acceptance-of-piv-i-credentials/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-8(6)_disassociability/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-8_identification-and-authentication-non-organizational-users/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-9(1)_information-exchange/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-9(2)_transmission-of-decisions/SKILL.md +1 -1
- package/skill/NIST/SP800-53_rev5/IA_identification-and-authentication/IA-9_service-identification-and-authentication/SKILL.md +1 -1
- package/skill/NIST/generate_sp800_53.py +2 -2
- package/skill/SKILL_GUIDE.md +1 -1
package/hackbrowser-worker.js
CHANGED
|
@@ -106258,20 +106258,22 @@ import { chromium as chromium2 } from "playwright";
|
|
|
106258
106258
|
// ../hackbrowser/src/stealth.ts
|
|
106259
106259
|
import { existsSync as existsSync2 } from "fs";
|
|
106260
106260
|
import { chromium } from "playwright";
|
|
106261
|
+
var PLATFORM_ARGS = process.platform === "linux" ? ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", "--no-zygote"] : [];
|
|
106261
106262
|
var LAUNCH_ARGS = [
|
|
106262
106263
|
"--disable-blink-features=AutomationControlled",
|
|
106263
106264
|
"--disable-features=IsolateOrigins,site-per-process",
|
|
106264
|
-
"--no-sandbox",
|
|
106265
|
-
"--disable-setuid-sandbox",
|
|
106266
|
-
"--disable-dev-shm-usage",
|
|
106267
106265
|
"--no-first-run",
|
|
106268
|
-
"--
|
|
106266
|
+
"--disable-backgrounding-occluded-windows",
|
|
106267
|
+
"--disable-renderer-backgrounding",
|
|
106268
|
+
"--disable-background-timer-throttling",
|
|
106269
|
+
"--disable-hang-monitor",
|
|
106270
|
+
"--disable-ipc-flooding-protection",
|
|
106271
|
+
"--disable-component-update",
|
|
106272
|
+
...PLATFORM_ARGS
|
|
106269
106273
|
];
|
|
106270
106274
|
function launchOptions(headless) {
|
|
106271
|
-
|
|
106272
|
-
}
|
|
106273
|
-
function userAgent(version3) {
|
|
106274
|
-
return `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version3} Safari/537.36`;
|
|
106275
|
+
const args = headless ? LAUNCH_ARGS : [...LAUNCH_ARGS, "--start-maximized"];
|
|
106276
|
+
return { headless, args };
|
|
106275
106277
|
}
|
|
106276
106278
|
function findSystemChrome() {
|
|
106277
106279
|
const candidates = process.platform === "darwin" ? ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"] : process.platform === "win32" ? [
|
|
@@ -106289,10 +106291,9 @@ async function connect(opts) {
|
|
|
106289
106291
|
return chromium.launch({ ...launchOptions(opts.headless), executablePath: chrome });
|
|
106290
106292
|
return chromium.launch(launchOptions(opts.headless));
|
|
106291
106293
|
}
|
|
106292
|
-
function contextOptions(
|
|
106294
|
+
function contextOptions(headless = true) {
|
|
106293
106295
|
return {
|
|
106294
|
-
|
|
106295
|
-
viewport: { width: 1920, height: 1080 },
|
|
106296
|
+
viewport: headless ? { width: 1920, height: 1080 } : null,
|
|
106296
106297
|
screen: { width: 1920, height: 1080 },
|
|
106297
106298
|
locale: "en-US",
|
|
106298
106299
|
timezoneId: "America/New_York",
|
|
@@ -106341,34 +106342,24 @@ Object.defineProperty(screen, 'availWidth', { get: () => 1920 });
|
|
|
106341
106342
|
Object.defineProperty(screen, 'availHeight', { get: () => 1040 });
|
|
106342
106343
|
Object.defineProperty(screen, 'colorDepth', { get: () => 24 });
|
|
106343
106344
|
Object.defineProperty(screen, 'pixelDepth', { get: () => 24 });
|
|
106344
|
-
window.outerWidth
|
|
106345
|
-
window
|
|
106346
|
-
|
|
106347
|
-
|
|
106348
|
-
|
|
106349
|
-
|
|
106350
|
-
|
|
106351
|
-
|
|
106352
|
-
|
|
106353
|
-
|
|
106354
|
-
|
|
106355
|
-
|
|
106356
|
-
|
|
106357
|
-
|
|
106358
|
-
|
|
106359
|
-
|
|
106360
|
-
|
|
106361
|
-
|
|
106362
|
-
const origToDataURL = HTMLCanvasElement.prototype.toDataURL;
|
|
106363
|
-
HTMLCanvasElement.prototype.toDataURL = function(type, quality) {
|
|
106364
|
-
const ctx = this.getContext('2d');
|
|
106365
|
-
if (ctx) {
|
|
106366
|
-
const pixel = ctx.getImageData(0, 0, 1, 1);
|
|
106367
|
-
pixel.data[3] = pixel.data[3] ^ 1;
|
|
106368
|
-
ctx.putImageData(pixel, 0, 0);
|
|
106369
|
-
}
|
|
106370
|
-
return origToDataURL.call(this, type, quality);
|
|
106371
|
-
};
|
|
106345
|
+
// NOTE: window.inner/outerWidth/Height are intentionally NOT spoofed. They must reflect
|
|
106346
|
+
// the REAL window so (a) the crawler's own geometry stays correct — scanner occlusion /
|
|
106347
|
+
// offscreen / scroll and the injected panel/login-bar clamp all read innerWidth — and
|
|
106348
|
+
// (b) they stay consistent with the actual rendered viewport (a faked 1920 over a smaller
|
|
106349
|
+
// real window is itself a detectable fingerprint mismatch). Monitor size is spoofed via
|
|
106350
|
+
// screen.* above; the window is launched at 1920x1080 (launchOptions/contextOptions) so on
|
|
106351
|
+
// a normal host innerWidth is already ~1920 with no spoof needed.
|
|
106352
|
+
|
|
106353
|
+
// NOTE: WebGL vendor/renderer are intentionally NOT spoofed. The real GPU string is a
|
|
106354
|
+
// genuine, self-consistent value; a faked 'Intel Iris OpenGL Engine' (an old macOS GPU
|
|
106355
|
+
// name, in the outdated non-ANGLE format) contradicts both the platform and modern Chrome's
|
|
106356
|
+
// 'ANGLE (...)' renderer format, which is more detectable than reporting the truth.
|
|
106357
|
+
|
|
106358
|
+
// NOTE: canvas toDataURL is intentionally NOT perturbed. The previous per-call XOR of one
|
|
106359
|
+
// pixel's alpha mutated the canvas on every read, so the same canvas hashed differently each
|
|
106360
|
+
// time — an unstable canvas is itself a bot signal (a real canvas is stable). Canvas-noise is
|
|
106361
|
+
// an anti-TRACKING measure, not anti-bot-detection (not what cleared #76); reporting the real,
|
|
106362
|
+
// stable canvas is the consistent choice, matching the UA/WebGL/window decisions above.
|
|
106372
106363
|
|
|
106373
106364
|
const origQuery = window.Permissions?.prototype?.query;
|
|
106374
106365
|
if (origQuery) {
|
|
@@ -116220,12 +116211,16 @@ function normalizeUrl(url3) {
|
|
|
116220
116211
|
u.searchParams.sort();
|
|
116221
116212
|
let path4 = u.pathname.replace(/\/+$/, "") || "/";
|
|
116222
116213
|
let hash4 = u.hash;
|
|
116223
|
-
|
|
116224
|
-
|
|
116225
|
-
|
|
116226
|
-
|
|
116227
|
-
|
|
116214
|
+
const routeLike = hash4.startsWith("#/") || hash4.startsWith("#!") || hash4.includes("=") || hash4.includes("&");
|
|
116215
|
+
if (routeLike) {
|
|
116216
|
+
if (hash4.startsWith("#/") || hash4.startsWith("#!/")) {
|
|
116217
|
+
hash4 = hash4.replace(/\/+$/, "");
|
|
116218
|
+
if (hash4 === "#")
|
|
116219
|
+
hash4 = "";
|
|
116220
|
+
}
|
|
116221
|
+
} else {
|
|
116228
116222
|
hash4 = "";
|
|
116223
|
+
}
|
|
116229
116224
|
return u.origin + path4 + u.search + hash4;
|
|
116230
116225
|
} catch {
|
|
116231
116226
|
return url3;
|
|
@@ -117202,9 +117197,10 @@ var PANEL_CSS = `
|
|
|
117202
117197
|
|
|
117203
117198
|
/* =========================== Card base =========================== */
|
|
117204
117199
|
.card {
|
|
117205
|
-
position:
|
|
117200
|
+
position: fixed;
|
|
117206
117201
|
bottom: 16px; right: 16px;
|
|
117207
117202
|
width: 360px;
|
|
117203
|
+
max-width: calc(100vw - 32px);
|
|
117208
117204
|
background: #0b0f14;
|
|
117209
117205
|
border: 1px solid #1f2937;
|
|
117210
117206
|
/* Non-blocking HUD: the agent's own observability overlay must NEVER intercept
|
|
@@ -118045,6 +118041,20 @@ function handle(ev) {
|
|
|
118045
118041
|
}
|
|
118046
118042
|
}
|
|
118047
118043
|
|
|
118044
|
+
// ---------- keep card inside viewport on resize ----------
|
|
118045
|
+
function clampCard() {
|
|
118046
|
+
var vv = window.visualViewport;
|
|
118047
|
+
var vw = vv ? vv.width : (document.documentElement.clientWidth || window.innerWidth);
|
|
118048
|
+
var vh = vv ? vv.height : (document.documentElement.clientHeight || window.innerHeight);
|
|
118049
|
+
var w = card.offsetWidth;
|
|
118050
|
+
var h = card.offsetHeight;
|
|
118051
|
+
card.style.right = Math.max(0, Math.min(16, vw - w - 16)) + 'px';
|
|
118052
|
+
card.style.bottom = Math.max(0, Math.min(16, vh - h - 16)) + 'px';
|
|
118053
|
+
}
|
|
118054
|
+
window.addEventListener('resize', clampCard);
|
|
118055
|
+
if (window.visualViewport) window.visualViewport.addEventListener('resize', clampCard);
|
|
118056
|
+
clampCard();
|
|
118057
|
+
|
|
118048
118058
|
// ---------- render restored state ----------
|
|
118049
118059
|
setHeader();
|
|
118050
118060
|
setCounters();
|
|
@@ -128174,8 +128184,60 @@ var OVERLAY_ESCAPE_WAIT = 400;
|
|
|
128174
128184
|
var OVERLAY_CLEAR_WAIT = 800;
|
|
128175
128185
|
var SPA_RENDER_RETRY_WAIT = 600;
|
|
128176
128186
|
var POST_GOTO_WAIT = 400;
|
|
128187
|
+
var NETWORK_IDLE_TIMEOUT = 1500;
|
|
128177
128188
|
var MAX_INLINE_DEPTH = 2;
|
|
128178
128189
|
var LOGIN_SUCCESS_PATTERN = /POST\s+.*\/(login|signin|authenticate)\S*\s+\[200\]/i;
|
|
128190
|
+
async function stabilizeAfterGoto(page) {
|
|
128191
|
+
await page.waitForTimeout(POST_GOTO_WAIT);
|
|
128192
|
+
await page.waitForLoadState("networkidle", { timeout: NETWORK_IDLE_TIMEOUT }).catch(() => {});
|
|
128193
|
+
}
|
|
128194
|
+
function createBrowserHealth() {
|
|
128195
|
+
return { dead: false, reason: "" };
|
|
128196
|
+
}
|
|
128197
|
+
function attachLifecycleHandlers(browser, page, health) {
|
|
128198
|
+
browser.on("disconnected", () => {
|
|
128199
|
+
health.dead = true;
|
|
128200
|
+
health.reason = "browser process disconnected";
|
|
128201
|
+
log7.error("browser disconnected — crawl will terminate");
|
|
128202
|
+
});
|
|
128203
|
+
page.on("close", () => {
|
|
128204
|
+
health.dead = true;
|
|
128205
|
+
health.reason = "page closed unexpectedly";
|
|
128206
|
+
log7.error("page closed — crawl will terminate");
|
|
128207
|
+
});
|
|
128208
|
+
page.on("crash", () => {
|
|
128209
|
+
health.dead = true;
|
|
128210
|
+
health.reason = "page renderer crashed";
|
|
128211
|
+
log7.error("page crashed — crawl will terminate");
|
|
128212
|
+
});
|
|
128213
|
+
}
|
|
128214
|
+
function isBrowserDead(health) {
|
|
128215
|
+
return health.dead;
|
|
128216
|
+
}
|
|
128217
|
+
var BROWSER_WAIT_TIMEOUT = 30 * 60 * 1000;
|
|
128218
|
+
function waitForBrowserClose(browser, signal) {
|
|
128219
|
+
return new Promise((resolve4) => {
|
|
128220
|
+
let resolved = false;
|
|
128221
|
+
const done = () => {
|
|
128222
|
+
if (resolved)
|
|
128223
|
+
return;
|
|
128224
|
+
resolved = true;
|
|
128225
|
+
clearTimeout(timer);
|
|
128226
|
+
resolve4();
|
|
128227
|
+
};
|
|
128228
|
+
const timer = setTimeout(done, BROWSER_WAIT_TIMEOUT);
|
|
128229
|
+
browser.on("disconnected", done);
|
|
128230
|
+
if (signal) {
|
|
128231
|
+
if (signal.aborted) {
|
|
128232
|
+
done();
|
|
128233
|
+
return;
|
|
128234
|
+
}
|
|
128235
|
+
signal.addEventListener("abort", done, { once: true });
|
|
128236
|
+
}
|
|
128237
|
+
if (!browser.isConnected())
|
|
128238
|
+
done();
|
|
128239
|
+
});
|
|
128240
|
+
}
|
|
128179
128241
|
function triggerReDiscovery(globalState) {
|
|
128180
128242
|
if (globalState.authPhase === "authenticated")
|
|
128181
128243
|
return;
|
|
@@ -128537,6 +128599,7 @@ async function explorePageWithAI(page, pageUrl, interceptor, model, globalState,
|
|
|
128537
128599
|
const taskQueue = [...plan.tasks];
|
|
128538
128600
|
const seenKeys = new Set(elements.map((e2) => `${e2.role}::${e2.label}`));
|
|
128539
128601
|
let steps = 0;
|
|
128602
|
+
let lastRevealingClick = null;
|
|
128540
128603
|
while (taskQueue.length > 0 && steps < MAX_STEPS_PER_PAGE) {
|
|
128541
128604
|
steps++;
|
|
128542
128605
|
const task = taskQueue.shift();
|
|
@@ -128559,16 +128622,18 @@ async function explorePageWithAI(page, pageUrl, interceptor, model, globalState,
|
|
|
128559
128622
|
if (task.type === "form") {
|
|
128560
128623
|
await executeFormTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav);
|
|
128561
128624
|
} else {
|
|
128562
|
-
await executeClickTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav);
|
|
128625
|
+
await executeClickTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav, lastRevealingClick);
|
|
128563
128626
|
}
|
|
128564
128627
|
const postActionElements = filterVisitedLinks(await collectElements(page), pageUrl, globalState.visitedPages);
|
|
128565
128628
|
if (task.type === "click" && task.role === "combobox") {
|
|
128566
|
-
const optionTasks =
|
|
128629
|
+
const optionTasks = await collectComboboxOptions(page, postActionElements, seenKeys, pageUrl, globalState.visitedPages);
|
|
128567
128630
|
if (optionTasks.length > 0) {
|
|
128568
128631
|
taskQueue.unshift(...optionTasks);
|
|
128569
128632
|
}
|
|
128570
128633
|
}
|
|
128571
128634
|
const hasNewElements = discoverNewElements(postActionElements, seenKeys);
|
|
128635
|
+
if (task.type === "click" && hasNewElements)
|
|
128636
|
+
lastRevealingClick = task;
|
|
128572
128637
|
const hasStaleTargets = queueHasStaleTargets(taskQueue, postActionElements);
|
|
128573
128638
|
if (hasNewElements || hasStaleTargets || occ.pending.length > 0) {
|
|
128574
128639
|
const freshElements = filterVisitedLinks(await collectElements(page), pageUrl, globalState.visitedPages);
|
|
@@ -128681,15 +128746,17 @@ async function explorePageWithAI(page, pageUrl, interceptor, model, globalState,
|
|
|
128681
128746
|
if (task.type === "form") {
|
|
128682
128747
|
await executeFormTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav);
|
|
128683
128748
|
} else {
|
|
128684
|
-
await executeClickTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav);
|
|
128749
|
+
await executeClickTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav, lastRevealingClick);
|
|
128685
128750
|
}
|
|
128686
128751
|
const postActionElements = filterVisitedLinks(await collectElements(page), pageUrl, globalState.visitedPages);
|
|
128687
128752
|
if (task.type === "click" && task.role === "combobox") {
|
|
128688
|
-
const optionTasks =
|
|
128753
|
+
const optionTasks = await collectComboboxOptions(page, postActionElements, seenKeys, pageUrl, globalState.visitedPages);
|
|
128689
128754
|
if (optionTasks.length > 0)
|
|
128690
128755
|
additionalQueue.unshift(...optionTasks);
|
|
128691
128756
|
}
|
|
128692
128757
|
const hasNewElements = discoverNewElements(postActionElements, seenKeys);
|
|
128758
|
+
if (task.type === "click" && hasNewElements)
|
|
128759
|
+
lastRevealingClick = task;
|
|
128693
128760
|
const hasStaleTargets = queueHasStaleTargets(additionalQueue, postActionElements);
|
|
128694
128761
|
if (hasNewElements || hasStaleTargets || occ.pending.length > 0) {
|
|
128695
128762
|
const freshElements = filterVisitedLinks(await collectElements(page), pageUrl, globalState.visitedPages);
|
|
@@ -128754,6 +128821,25 @@ async function recoverFromOcclusion(page, el, original, retry) {
|
|
|
128754
128821
|
await page.waitForTimeout(OVERLAY_CLEAR_WAIT);
|
|
128755
128822
|
return retry();
|
|
128756
128823
|
}
|
|
128824
|
+
async function recoverFromClosedContainer(page, el, original, opener, interceptor, retry) {
|
|
128825
|
+
if (original.success || !opener)
|
|
128826
|
+
return original;
|
|
128827
|
+
if (opener.role === el.role && opener.label === el.label)
|
|
128828
|
+
return original;
|
|
128829
|
+
if ((await probeClickPoint(page, el.selector)).status !== "offscreen")
|
|
128830
|
+
return original;
|
|
128831
|
+
const fresh = await collectElements(page);
|
|
128832
|
+
const openerEl = resolveElement(fresh, opener.role, opener.label);
|
|
128833
|
+
if (!openerEl)
|
|
128834
|
+
return original;
|
|
128835
|
+
log7.debug("target offscreen — re-opening its container via opener, retrying once", {
|
|
128836
|
+
target: el.label,
|
|
128837
|
+
opener: opener.label
|
|
128838
|
+
});
|
|
128839
|
+
await execute(page, openerEl, "click", undefined, interceptor.setPendingUI, fresh.length);
|
|
128840
|
+
await page.waitForTimeout(POST_GOTO_WAIT);
|
|
128841
|
+
return retry();
|
|
128842
|
+
}
|
|
128757
128843
|
async function diagnoseOcclusion(page, el, occ) {
|
|
128758
128844
|
const probe = await probeClickPoint(page, el.selector);
|
|
128759
128845
|
if (probe.status === "occluded" && !occ.signaled.has(probe.occluder.text)) {
|
|
@@ -128779,8 +128865,7 @@ async function handleNavigation(page, parentUrl, linksToEnqueue, inScope, global
|
|
|
128779
128865
|
}
|
|
128780
128866
|
}
|
|
128781
128867
|
await page.goto(parentUrl, { waitUntil: "domcontentloaded", timeout: 15000 }).catch(() => {});
|
|
128782
|
-
await page
|
|
128783
|
-
await page.waitForLoadState("domcontentloaded", { timeout: 5000 }).catch(() => {});
|
|
128868
|
+
await stabilizeAfterGoto(page);
|
|
128784
128869
|
}
|
|
128785
128870
|
async function executeFormTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav) {
|
|
128786
128871
|
for (const field of task.fields) {
|
|
@@ -128846,7 +128931,7 @@ async function executeFormTask(task, page, elements, interceptor, semanticAction
|
|
|
128846
128931
|
if (result.navigated)
|
|
128847
128932
|
await handleNavigation(page, pageUrl, linksToEnqueue, inScope, globalState, nav);
|
|
128848
128933
|
}
|
|
128849
|
-
async function executeClickTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav) {
|
|
128934
|
+
async function executeClickTask(task, page, elements, interceptor, semanticActionsDone, globalState, credentialId, linksToEnqueue, pageUrl, inScope, occ, nav, opener) {
|
|
128850
128935
|
const el = resolveElement(elements, task.role, task.label);
|
|
128851
128936
|
if (!el) {
|
|
128852
128937
|
log7.debug("click target not found", { role: task.role, label: task.label });
|
|
@@ -128866,6 +128951,7 @@ async function executeClickTask(task, page, elements, interceptor, semanticActio
|
|
|
128866
128951
|
});
|
|
128867
128952
|
let result = await execute(page, el, "click", undefined, interceptor.setPendingUI, elements.length);
|
|
128868
128953
|
result = await recoverFromOcclusion(page, el, result, () => execute(page, el, "click", undefined, interceptor.setPendingUI, elements.length));
|
|
128954
|
+
result = await recoverFromClosedContainer(page, el, result, opener, interceptor, () => execute(page, el, "click", undefined, interceptor.setPendingUI, elements.length));
|
|
128869
128955
|
const occluded = !result.success && await diagnoseOcclusion(page, el, occ);
|
|
128870
128956
|
interceptor.clearPendingTrigger();
|
|
128871
128957
|
trackResult(result, interceptor, globalState, credentialId, task.triggersMutation, page);
|
|
@@ -128901,6 +128987,24 @@ function collectOptionTasks(elements, seenKeys) {
|
|
|
128901
128987
|
}
|
|
128902
128988
|
return tasks.slice(0, 1);
|
|
128903
128989
|
}
|
|
128990
|
+
var COMBOBOX_PROBES = ["e", "a", "2", "0", " "];
|
|
128991
|
+
async function collectComboboxOptions(page, elements, seenKeys, pageUrl, visitedPages) {
|
|
128992
|
+
const inline = collectOptionTasks(elements, seenKeys);
|
|
128993
|
+
if (inline.length > 0)
|
|
128994
|
+
return inline;
|
|
128995
|
+
const search = page.locator(":focus");
|
|
128996
|
+
const typeable = await search.evaluate((el) => !!el && (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.isContentEditable)).catch(() => false);
|
|
128997
|
+
if (!typeable)
|
|
128998
|
+
return inline;
|
|
128999
|
+
for (const probe of COMBOBOX_PROBES) {
|
|
129000
|
+
await search.fill(probe).catch(() => {});
|
|
129001
|
+
await page.waitForTimeout(200);
|
|
129002
|
+
if (await page.locator("[role=option]:visible").count() > 0)
|
|
129003
|
+
break;
|
|
129004
|
+
}
|
|
129005
|
+
const revealed = filterVisitedLinks(await collectElements(page), pageUrl, visitedPages);
|
|
129006
|
+
return collectOptionTasks(revealed, seenKeys);
|
|
129007
|
+
}
|
|
128904
129008
|
function discoverNewElements(elements, seenKeys) {
|
|
128905
129009
|
let found = false;
|
|
128906
129010
|
for (const el of elements) {
|
|
@@ -129190,6 +129294,12 @@ async function runMultiCredential(config3, credentials) {
|
|
|
129190
129294
|
throw new Error(`AI model required: ${String(err)}`);
|
|
129191
129295
|
}
|
|
129192
129296
|
const browser = await connect({ cdp: config3.cdp, headless: config3.headless ?? false });
|
|
129297
|
+
const health = createBrowserHealth();
|
|
129298
|
+
browser.on("disconnected", () => {
|
|
129299
|
+
health.dead = true;
|
|
129300
|
+
health.reason = "browser process disconnected";
|
|
129301
|
+
log7.error("browser disconnected — multi-credential crawl will terminate");
|
|
129302
|
+
});
|
|
129193
129303
|
let sessionId = config3.cyberstrike.sessionID ?? "";
|
|
129194
129304
|
if (!dryRun && !sessionId) {
|
|
129195
129305
|
const created = await initSession(serverUrl, targetUrl, undefined);
|
|
@@ -129203,14 +129313,46 @@ async function runMultiCredential(config3, credentials) {
|
|
|
129203
129313
|
const captureQueues = new Map;
|
|
129204
129314
|
const lastAuthHeaders = new Map;
|
|
129205
129315
|
for (const [credIndex, cred] of credentials.entries()) {
|
|
129206
|
-
const browserContext = await browser.newContext(contextOptions(
|
|
129316
|
+
const browserContext = await browser.newContext(contextOptions(config3.headless ?? false));
|
|
129207
129317
|
await browserContext.addInitScript(INIT_SCRIPT);
|
|
129208
129318
|
if (panelOn)
|
|
129209
129319
|
await browserContext.addInitScript(PANEL_INIT_SCRIPT);
|
|
129210
129320
|
const page = await browserContext.newPage();
|
|
129321
|
+
page.on("close", () => {
|
|
129322
|
+
health.dead = true;
|
|
129323
|
+
health.reason = `page closed (credential: ${cred.id})`;
|
|
129324
|
+
log7.error("page closed — multi-credential crawl will terminate", { credential: cred.id });
|
|
129325
|
+
});
|
|
129326
|
+
page.on("crash", () => {
|
|
129327
|
+
health.dead = true;
|
|
129328
|
+
health.reason = `page crashed (credential: ${cred.id})`;
|
|
129329
|
+
log7.error("page crashed — multi-credential crawl will terminate", { credential: cred.id });
|
|
129330
|
+
});
|
|
129211
129331
|
attachDialogAutoAccept(page);
|
|
129212
129332
|
attachFileChooserAutoFill(page);
|
|
129213
|
-
await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 30000 });
|
|
129333
|
+
const mcInitNavErr = await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 30000 }).then(() => null).catch((e2) => e2);
|
|
129334
|
+
if (mcInitNavErr) {
|
|
129335
|
+
log7.warn("initial navigation failed", {
|
|
129336
|
+
credential: cred.id,
|
|
129337
|
+
url: targetUrl,
|
|
129338
|
+
err: mcInitNavErr.message.split(`
|
|
129339
|
+
`)[0]
|
|
129340
|
+
});
|
|
129341
|
+
if (!config3.headless && browser.isConnected()) {
|
|
129342
|
+
log7.info("browser stays open — navigate manually or close the window to finish");
|
|
129343
|
+
await waitForBrowserClose(browser, config3.signal);
|
|
129344
|
+
} else {
|
|
129345
|
+
await browser.close().catch(() => {});
|
|
129346
|
+
}
|
|
129347
|
+
return {
|
|
129348
|
+
sessionID: dryRun ? "" : sessionId,
|
|
129349
|
+
capturedEndpoints: 0,
|
|
129350
|
+
pagesExplored: 0,
|
|
129351
|
+
totalSteps: 0,
|
|
129352
|
+
errors: [`Initial navigation failed (credential: ${cred.id}): ${mcInitNavErr.message}`],
|
|
129353
|
+
usage: usageAcc
|
|
129354
|
+
};
|
|
129355
|
+
}
|
|
129214
129356
|
csEmit(page, {
|
|
129215
129357
|
type: "init",
|
|
129216
129358
|
target: targetUrl,
|
|
@@ -129276,6 +129418,14 @@ async function runMultiCredential(config3, credentials) {
|
|
|
129276
129418
|
globalState.authPhase = "authenticated";
|
|
129277
129419
|
let pagesExplored = 0;
|
|
129278
129420
|
while (pageQueue.length > 0 && pagesExplored < maxPages) {
|
|
129421
|
+
if (isBrowserDead(health)) {
|
|
129422
|
+
log7.error("browser died, terminating multi-credential crawl", {
|
|
129423
|
+
reason: health.reason,
|
|
129424
|
+
pagesExplored,
|
|
129425
|
+
captured: globalState.capturedEndpoints.size
|
|
129426
|
+
});
|
|
129427
|
+
break;
|
|
129428
|
+
}
|
|
129279
129429
|
if (config3.signal?.aborted) {
|
|
129280
129430
|
log7.info("multi-credential crawl cancelled by signal", { pagesExplored, queued: pageQueue.length });
|
|
129281
129431
|
break;
|
|
@@ -129292,8 +129442,7 @@ async function runMultiCredential(config3, credentials) {
|
|
|
129292
129442
|
const navigateResults = await Promise.all(activeContexts.map(async (ctx) => {
|
|
129293
129443
|
try {
|
|
129294
129444
|
await ctx.page.goto(entry.url, { waitUntil: "domcontentloaded", timeout: 15000 });
|
|
129295
|
-
await ctx.page
|
|
129296
|
-
await ctx.page.waitForLoadState("domcontentloaded", { timeout: 5000 }).catch(() => {});
|
|
129445
|
+
await stabilizeAfterGoto(ctx.page);
|
|
129297
129446
|
return { ctx, success: true, redirected: normalizeUrl(ctx.page.url()) !== normalizeUrl(entry.url) };
|
|
129298
129447
|
} catch (err) {
|
|
129299
129448
|
log7.warn("navigation failed", { credential: ctx.id, url: entry.url, err: String(err) });
|
|
@@ -129364,15 +129513,31 @@ async function runMultiCredential(config3, credentials) {
|
|
|
129364
129513
|
});
|
|
129365
129514
|
}
|
|
129366
129515
|
for (const ctx of visitableContexts) {
|
|
129516
|
+
if (isBrowserDead(health))
|
|
129517
|
+
break;
|
|
129367
129518
|
log7.info("exploring", { credential: ctx.id, url: entry.url });
|
|
129368
129519
|
const exploreInline = async (p, url3, depth) => {
|
|
129520
|
+
if (isBrowserDead(health))
|
|
129521
|
+
return;
|
|
129369
129522
|
const found = await explorePageWithAI(p, url3, ctx.interceptor, model, globalState, inScope, ctx.id, maxPages, usageAcc, { explore: exploreInline, depth });
|
|
129370
129523
|
for (const u of found)
|
|
129371
129524
|
enqueueWithContext(u, ctx.id, pageQueue, visitedPages, inScope, pathPatternCounts);
|
|
129372
129525
|
};
|
|
129373
|
-
|
|
129374
|
-
|
|
129375
|
-
|
|
129526
|
+
try {
|
|
129527
|
+
const discovered = await explorePageWithAI(ctx.page, entry.url, ctx.interceptor, model, globalState, inScope, ctx.id, maxPages, usageAcc, { explore: exploreInline, depth: 0 });
|
|
129528
|
+
for (const url3 of discovered) {
|
|
129529
|
+
enqueueWithContext(url3, ctx.id, pageQueue, visitedPages, inScope, pathPatternCounts);
|
|
129530
|
+
}
|
|
129531
|
+
} catch (err) {
|
|
129532
|
+
if (isBrowserDead(health)) {
|
|
129533
|
+
log7.error("exploration aborted — browser died mid-page", {
|
|
129534
|
+
credential: ctx.id,
|
|
129535
|
+
url: entry.url,
|
|
129536
|
+
reason: health.reason
|
|
129537
|
+
});
|
|
129538
|
+
break;
|
|
129539
|
+
}
|
|
129540
|
+
log7.warn("exploration error", { credential: ctx.id, url: entry.url, err: String(err) });
|
|
129376
129541
|
}
|
|
129377
129542
|
}
|
|
129378
129543
|
for (const ctx of visitableContexts) {
|
|
@@ -129385,36 +129550,50 @@ async function runMultiCredential(config3, credentials) {
|
|
|
129385
129550
|
await drainPageCaptures(captureQueues, captureHandlers, availability, entry.url, visitedBy);
|
|
129386
129551
|
await visitableContexts[0]?.page.waitForTimeout(300);
|
|
129387
129552
|
}
|
|
129388
|
-
|
|
129389
|
-
|
|
129553
|
+
const browserDied = isBrowserDead(health);
|
|
129554
|
+
log7.info(browserDied ? "browser died, draining captured requests" : "multi-credential exploration complete, draining remaining requests", {
|
|
129555
|
+
pagesExplored,
|
|
129556
|
+
captured: globalState.capturedEndpoints.size,
|
|
129557
|
+
...browserDied ? { reason: health.reason } : {}
|
|
129558
|
+
});
|
|
129559
|
+
if (!browserDied)
|
|
129560
|
+
await contexts[0]?.page.waitForTimeout(2000).catch(() => {});
|
|
129390
129561
|
await drainPageCaptures(captureQueues, captureHandlers, new Map, null, null);
|
|
129391
129562
|
log7.info("multi-credential crawl done", {
|
|
129392
129563
|
pagesExplored,
|
|
129393
129564
|
credentials: contexts.map((c) => c.id),
|
|
129394
129565
|
totalSteps: globalState.totalSteps,
|
|
129395
|
-
capturedEndpoints: globalState.capturedEndpoints.size
|
|
129566
|
+
capturedEndpoints: globalState.capturedEndpoints.size,
|
|
129567
|
+
browserDied
|
|
129396
129568
|
});
|
|
129397
|
-
|
|
129398
|
-
|
|
129399
|
-
|
|
129400
|
-
|
|
129401
|
-
|
|
129402
|
-
|
|
129403
|
-
|
|
129404
|
-
|
|
129405
|
-
|
|
129406
|
-
|
|
129407
|
-
|
|
129408
|
-
|
|
129569
|
+
if (!browserDied) {
|
|
129570
|
+
const mutationCount = [...globalState.capturedEndpoints].filter((e2) => /^(POST|PUT|PATCH|DELETE)\s/.test(e2)).length;
|
|
129571
|
+
const credentialIds = contexts.map((c) => c.id);
|
|
129572
|
+
for (const ctx of contexts) {
|
|
129573
|
+
csEmit(ctx.page, {
|
|
129574
|
+
type: "crawl-done",
|
|
129575
|
+
summary: {
|
|
129576
|
+
pagesExplored,
|
|
129577
|
+
capturedEndpoints: globalState.capturedEndpoints.size,
|
|
129578
|
+
mutations: mutationCount,
|
|
129579
|
+
credentials: credentialIds
|
|
129580
|
+
}
|
|
129581
|
+
});
|
|
129582
|
+
}
|
|
129583
|
+
await contexts[0]?.page.waitForTimeout(600).catch(() => {});
|
|
129584
|
+
}
|
|
129585
|
+
if (!config3.headless && browser.isConnected()) {
|
|
129586
|
+
log7.info("crawl complete — browser stays open, close the window to finish");
|
|
129587
|
+
await waitForBrowserClose(browser, config3.signal);
|
|
129588
|
+
} else if (!browserDied) {
|
|
129589
|
+
await browser.close().catch(() => {});
|
|
129409
129590
|
}
|
|
129410
|
-
await contexts[0]?.page.waitForTimeout(600).catch(() => {});
|
|
129411
|
-
await browser.close();
|
|
129412
129591
|
return {
|
|
129413
129592
|
sessionID: dryRun ? "" : sessionId,
|
|
129414
129593
|
capturedEndpoints: globalState.capturedEndpoints.size,
|
|
129415
129594
|
pagesExplored,
|
|
129416
129595
|
totalSteps: globalState.totalSteps,
|
|
129417
|
-
errors: [],
|
|
129596
|
+
errors: browserDied ? [`Browser died: ${health.reason}. Captured ${globalState.capturedEndpoints.size} endpoints before failure.`] : [],
|
|
129418
129597
|
usage: usageAcc
|
|
129419
129598
|
};
|
|
129420
129599
|
}
|
|
@@ -129456,11 +129635,13 @@ async function run(config3) {
|
|
|
129456
129635
|
sessionID = created;
|
|
129457
129636
|
}
|
|
129458
129637
|
const browser = await connect({ cdp: config3.cdp, headless: config3.headless ?? false });
|
|
129459
|
-
const
|
|
129638
|
+
const health = createBrowserHealth();
|
|
129639
|
+
const context = await browser.newContext(contextOptions(config3.headless ?? false));
|
|
129460
129640
|
await context.addInitScript(INIT_SCRIPT);
|
|
129461
129641
|
if (panelOn)
|
|
129462
129642
|
await context.addInitScript(PANEL_INIT_SCRIPT);
|
|
129463
129643
|
const page = await context.newPage();
|
|
129644
|
+
attachLifecycleHandlers(browser, page, health);
|
|
129464
129645
|
attachDialogAutoAccept(page);
|
|
129465
129646
|
attachFileChooserAutoFill(page);
|
|
129466
129647
|
if (config3.auth.sessionFile) {
|
|
@@ -129485,191 +129666,258 @@ async function run(config3) {
|
|
|
129485
129666
|
await handleCapture(captured);
|
|
129486
129667
|
}
|
|
129487
129668
|
}, 500);
|
|
129488
|
-
|
|
129489
|
-
|
|
129490
|
-
|
|
129491
|
-
|
|
129492
|
-
|
|
129493
|
-
|
|
129494
|
-
|
|
129495
|
-
|
|
129496
|
-
|
|
129497
|
-
|
|
129498
|
-
await waitForManualLogin(page);
|
|
129499
|
-
if (!dryRun && credentialId) {
|
|
129500
|
-
const registeredId = await registerCredential(serverUrl, sessionID, credentialId);
|
|
129501
|
-
if (registeredId) {
|
|
129502
|
-
credentialId = registeredId;
|
|
129503
|
-
handleCapture = createIngestHandler(serverUrl, sessionID, credentialId);
|
|
129504
|
-
}
|
|
129505
|
-
}
|
|
129506
|
-
} else if (config3.auth.credentials) {
|
|
129507
|
-
await autoLogin(page, config3.auth.credentials);
|
|
129508
|
-
} else {
|
|
129509
|
-
await handle2FA(page);
|
|
129510
|
-
}
|
|
129511
|
-
const globalState = createGlobalState({ outOfScope: config3.outOfScope });
|
|
129512
|
-
if (config3.outOfScope?.length) {
|
|
129513
|
-
log7.info("out-of-scope labels", { count: config3.outOfScope.length, labels: config3.outOfScope });
|
|
129514
|
-
}
|
|
129515
|
-
if (isAuthenticated) {
|
|
129516
|
-
globalState.authPhase = "authenticated";
|
|
129517
|
-
}
|
|
129518
|
-
globalState.visitedPages.add(normalizeUrl(page.url()));
|
|
129519
|
-
globalState.pageQueue.push(page.url());
|
|
129520
|
-
page.on("response", (response) => {
|
|
129521
|
-
if (globalState.authPhase === "authenticated")
|
|
129522
|
-
return;
|
|
129523
|
-
const req = response.request();
|
|
129524
|
-
const method = req.method();
|
|
129525
|
-
const status = response.status();
|
|
129526
|
-
try {
|
|
129527
|
-
const pathname = new URL(req.url()).pathname;
|
|
129528
|
-
if (LOGIN_SUCCESS_PATTERN.test(`${method} ${pathname} [${status}]`)) {
|
|
129529
|
-
log7.info("login success detected via HTTP response");
|
|
129530
|
-
triggerReDiscovery(globalState);
|
|
129669
|
+
try {
|
|
129670
|
+
const initNavErr = await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 30000 }).then(() => null).catch((e2) => e2);
|
|
129671
|
+
if (initNavErr) {
|
|
129672
|
+
log7.warn("initial navigation failed", { url: targetUrl, err: initNavErr.message.split(`
|
|
129673
|
+
`)[0] });
|
|
129674
|
+
if (!config3.headless && browser.isConnected()) {
|
|
129675
|
+
log7.info("browser stays open — navigate manually or close the window to finish");
|
|
129676
|
+
await waitForBrowserClose(browser, config3.signal);
|
|
129677
|
+
} else {
|
|
129678
|
+
await browser.close().catch(() => {});
|
|
129531
129679
|
}
|
|
129532
|
-
|
|
129533
|
-
|
|
129534
|
-
|
|
129535
|
-
|
|
129536
|
-
|
|
129537
|
-
|
|
129538
|
-
|
|
129680
|
+
return {
|
|
129681
|
+
sessionID: dryRun ? "" : sessionID,
|
|
129682
|
+
capturedEndpoints: 0,
|
|
129683
|
+
pagesExplored: 0,
|
|
129684
|
+
totalSteps: 0,
|
|
129685
|
+
errors: [`Initial navigation failed: ${initNavErr.message}`],
|
|
129686
|
+
usage: usageAcc
|
|
129687
|
+
};
|
|
129539
129688
|
}
|
|
129540
|
-
|
|
129541
|
-
|
|
129542
|
-
|
|
129543
|
-
|
|
129544
|
-
|
|
129545
|
-
|
|
129546
|
-
|
|
129547
|
-
|
|
129689
|
+
csEmit(page, {
|
|
129690
|
+
type: "init",
|
|
129691
|
+
target: targetUrl,
|
|
129692
|
+
credentials: [],
|
|
129693
|
+
maxPages,
|
|
129694
|
+
startedAt: Date.now()
|
|
129695
|
+
});
|
|
129696
|
+
const isAuthenticated = config3.auth.authenticated || !!config3.auth.credentials;
|
|
129697
|
+
if (config3.auth.authenticated) {
|
|
129698
|
+
await waitForManualLogin(page);
|
|
129699
|
+
if (!dryRun && credentialId) {
|
|
129700
|
+
const registeredId = await registerCredential(serverUrl, sessionID, credentialId);
|
|
129701
|
+
if (registeredId) {
|
|
129702
|
+
credentialId = registeredId;
|
|
129703
|
+
handleCapture = createIngestHandler(serverUrl, sessionID, credentialId);
|
|
129704
|
+
}
|
|
129548
129705
|
}
|
|
129549
|
-
|
|
129550
|
-
await page
|
|
129706
|
+
} else if (config3.auth.credentials) {
|
|
129707
|
+
await autoLogin(page, config3.auth.credentials);
|
|
129708
|
+
} else {
|
|
129709
|
+
await handle2FA(page);
|
|
129551
129710
|
}
|
|
129552
|
-
|
|
129553
|
-
|
|
129554
|
-
|
|
129555
|
-
continue;
|
|
129711
|
+
const globalState = createGlobalState({ outOfScope: config3.outOfScope });
|
|
129712
|
+
if (config3.outOfScope?.length) {
|
|
129713
|
+
log7.info("out-of-scope labels", { count: config3.outOfScope.length, labels: config3.outOfScope });
|
|
129556
129714
|
}
|
|
129557
|
-
|
|
129558
|
-
|
|
129559
|
-
log7.info("redirect to already-explored page, skipping", { requested: normalizeUrl(nextUrl), landed: currentUrl });
|
|
129560
|
-
continue;
|
|
129715
|
+
if (isAuthenticated) {
|
|
129716
|
+
globalState.authPhase = "authenticated";
|
|
129561
129717
|
}
|
|
129562
|
-
globalState.visitedPages.add(
|
|
129563
|
-
|
|
129564
|
-
|
|
129565
|
-
|
|
129566
|
-
|
|
129567
|
-
|
|
129568
|
-
|
|
129569
|
-
|
|
129570
|
-
|
|
129571
|
-
|
|
129718
|
+
globalState.visitedPages.add(normalizeUrl(page.url()));
|
|
129719
|
+
globalState.pageQueue.push(page.url());
|
|
129720
|
+
page.on("response", (response) => {
|
|
129721
|
+
if (globalState.authPhase === "authenticated")
|
|
129722
|
+
return;
|
|
129723
|
+
const req = response.request();
|
|
129724
|
+
const method = req.method();
|
|
129725
|
+
const status = response.status();
|
|
129726
|
+
try {
|
|
129727
|
+
const pathname = new URL(req.url()).pathname;
|
|
129728
|
+
if (LOGIN_SUCCESS_PATTERN.test(`${method} ${pathname} [${status}]`)) {
|
|
129729
|
+
log7.info("login success detected via HTTP response");
|
|
129730
|
+
triggerReDiscovery(globalState);
|
|
129572
129731
|
}
|
|
129573
|
-
}
|
|
129574
|
-
|
|
129575
|
-
|
|
129576
|
-
|
|
129577
|
-
|
|
129578
|
-
|
|
129579
|
-
|
|
129580
|
-
|
|
129581
|
-
|
|
129582
|
-
|
|
129583
|
-
|
|
129584
|
-
|
|
129585
|
-
|
|
129586
|
-
|
|
129587
|
-
|
|
129588
|
-
|
|
129589
|
-
|
|
129590
|
-
|
|
129591
|
-
|
|
129592
|
-
|
|
129593
|
-
|
|
129594
|
-
|
|
129595
|
-
|
|
129596
|
-
|
|
129597
|
-
|
|
129598
|
-
|
|
129599
|
-
|
|
129600
|
-
|
|
129601
|
-
|
|
129602
|
-
|
|
129603
|
-
const domLinks = await collectDOMLinks(page, currentUrl, inScope);
|
|
129604
|
-
for (const url3 of domLinks) {
|
|
129605
|
-
enqueueUrl(url3, globalState, inScope);
|
|
129606
|
-
}
|
|
129607
|
-
intel.pageFingerprints.set(currentUrl, newFingerprint);
|
|
129608
|
-
await page.waitForTimeout(300);
|
|
129732
|
+
} catch {}
|
|
129733
|
+
});
|
|
129734
|
+
let pagesExplored = 0;
|
|
129735
|
+
while (globalState.pageQueue.length > 0 && pagesExplored < maxPages) {
|
|
129736
|
+
if (isBrowserDead(health)) {
|
|
129737
|
+
log7.error("browser died, terminating crawl", {
|
|
129738
|
+
reason: health.reason,
|
|
129739
|
+
pagesExplored,
|
|
129740
|
+
captured: globalState.capturedEndpoints.size
|
|
129741
|
+
});
|
|
129742
|
+
break;
|
|
129743
|
+
}
|
|
129744
|
+
if (config3.signal?.aborted) {
|
|
129745
|
+
log7.info("crawl cancelled by signal", { pagesExplored, queued: globalState.pageQueue.length });
|
|
129746
|
+
break;
|
|
129747
|
+
}
|
|
129748
|
+
const nextUrl = globalState.pageQueue.shift();
|
|
129749
|
+
pagesExplored++;
|
|
129750
|
+
if (page.url() !== nextUrl) {
|
|
129751
|
+
const navErr = await page.goto(nextUrl, { waitUntil: "domcontentloaded", timeout: 15000 }).then(() => null).catch((e2) => e2);
|
|
129752
|
+
if (navErr) {
|
|
129753
|
+
log7.warn("navigation failed", { url: nextUrl, err: navErr.message.split(`
|
|
129754
|
+
`)[0] });
|
|
129755
|
+
continue;
|
|
129756
|
+
}
|
|
129757
|
+
await stabilizeAfterGoto(page);
|
|
129758
|
+
}
|
|
129759
|
+
if (!isInScope(page.url(), inScope)) {
|
|
129760
|
+
log7.info("off-host redirect, skipping", { url: page.url() });
|
|
129761
|
+
await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 15000 }).catch(() => {});
|
|
129609
129762
|
continue;
|
|
129610
129763
|
}
|
|
129611
|
-
|
|
129612
|
-
|
|
129613
|
-
|
|
129614
|
-
|
|
129615
|
-
|
|
129616
|
-
|
|
129617
|
-
|
|
129618
|
-
|
|
129619
|
-
|
|
129620
|
-
|
|
129621
|
-
|
|
129622
|
-
newEnqueued++;
|
|
129623
|
-
}
|
|
129624
|
-
if (discovered.length > 0) {
|
|
129625
|
-
log7.debug("discovered links", {
|
|
129626
|
-
found: discovered.length,
|
|
129627
|
-
enqueued: newEnqueued,
|
|
129628
|
-
queueSize: globalState.pageQueue.length
|
|
129629
|
-
});
|
|
129630
|
-
}
|
|
129631
|
-
flushReDiscovery(globalState);
|
|
129632
|
-
await page.waitForTimeout(300);
|
|
129633
|
-
if (globalState.pageQueue.length === 0 && globalState.deferredAuthPages.length > 0) {
|
|
129634
|
-
log7.debug("queue empty, processing auth phase", {
|
|
129764
|
+
const currentUrl = normalizeUrl(page.url());
|
|
129765
|
+
if (currentUrl !== normalizeUrl(nextUrl) && globalState.visitedPages.has(currentUrl)) {
|
|
129766
|
+
log7.info("redirect to already-explored page, skipping", {
|
|
129767
|
+
requested: normalizeUrl(nextUrl),
|
|
129768
|
+
landed: currentUrl
|
|
129769
|
+
});
|
|
129770
|
+
continue;
|
|
129771
|
+
}
|
|
129772
|
+
globalState.visitedPages.add(currentUrl);
|
|
129773
|
+
log7.info("exploring page", { page: `${pagesExplored}/${maxPages}`, url: currentUrl });
|
|
129774
|
+
log7.debug("state", {
|
|
129635
129775
|
phase: globalState.authPhase,
|
|
129636
|
-
|
|
129776
|
+
queueSize: globalState.pageQueue.length,
|
|
129777
|
+
queue: globalState.pageQueue.slice(0, 5).map((u) => {
|
|
129778
|
+
try {
|
|
129779
|
+
return new URL(u).pathname + new URL(u).hash;
|
|
129780
|
+
} catch {
|
|
129781
|
+
return u;
|
|
129782
|
+
}
|
|
129783
|
+
}),
|
|
129784
|
+
visited: globalState.visitedPages.size,
|
|
129785
|
+
deferred: globalState.deferredAuthPages.map((d) => `${d.type}:${d.url.split("/").pop()}`),
|
|
129786
|
+
endpoints: globalState.capturedEndpoints.size,
|
|
129787
|
+
steps: globalState.totalSteps
|
|
129637
129788
|
});
|
|
129638
|
-
|
|
129789
|
+
await page.keyboard.press("Escape").catch(() => {});
|
|
129790
|
+
await page.waitForTimeout(OVERLAY_ESCAPE_WAIT);
|
|
129791
|
+
if (await isViewportCenterBlocked(page)) {
|
|
129792
|
+
const dims = await page.evaluate(() => ({ w: window.innerWidth, h: window.innerHeight }));
|
|
129793
|
+
await page.mouse.click(dims.w / 2, dims.h / 2).catch(() => {});
|
|
129794
|
+
await page.waitForTimeout(OVERLAY_ESCAPE_WAIT);
|
|
129795
|
+
}
|
|
129796
|
+
await dismissCookieBanner(page);
|
|
129797
|
+
await revealLazyContent(page);
|
|
129798
|
+
await expandDisclosures(page);
|
|
129799
|
+
const intel = getIntelligence(globalState, SINGLE_CRED);
|
|
129800
|
+
const oldFingerprint = intel.pageFingerprints.get(currentUrl);
|
|
129801
|
+
log7.debug("fingerprint check", { url: currentUrl, hasOld: !!oldFingerprint });
|
|
129802
|
+
if (oldFingerprint !== undefined) {
|
|
129803
|
+
const currentElements = await collectElements(page);
|
|
129804
|
+
const newFingerprint = generateFingerprint(currentElements);
|
|
129805
|
+
log7.debug("fingerprint compare", {
|
|
129806
|
+
url: currentUrl,
|
|
129807
|
+
match: newFingerprint === oldFingerprint,
|
|
129808
|
+
oldFp: oldFingerprint.slice(0, 80),
|
|
129809
|
+
newFp: newFingerprint.slice(0, 80)
|
|
129810
|
+
});
|
|
129811
|
+
if (newFingerprint === oldFingerprint) {
|
|
129812
|
+
log7.info("page unchanged after auth, skipping exploration", { url: currentUrl });
|
|
129813
|
+
const domLinks = await collectDOMLinks(page, currentUrl, inScope);
|
|
129814
|
+
for (const url3 of domLinks) {
|
|
129815
|
+
enqueueUrl(url3, globalState, inScope);
|
|
129816
|
+
}
|
|
129817
|
+
intel.pageFingerprints.set(currentUrl, newFingerprint);
|
|
129818
|
+
await page.waitForTimeout(300);
|
|
129819
|
+
continue;
|
|
129820
|
+
}
|
|
129821
|
+
log7.info("page changed after auth, re-exploring", { url: currentUrl });
|
|
129822
|
+
}
|
|
129823
|
+
const exploreInline = async (p, url3, depth) => {
|
|
129824
|
+
if (isBrowserDead(health))
|
|
129825
|
+
return;
|
|
129826
|
+
const found = await explorePageWithAI(p, url3, interceptor, model, globalState, inScope, SINGLE_CRED, maxPages, usageAcc, { explore: exploreInline, depth });
|
|
129827
|
+
for (const u of found)
|
|
129828
|
+
enqueueUrl(u, globalState, inScope);
|
|
129829
|
+
};
|
|
129830
|
+
let discovered = [];
|
|
129831
|
+
try {
|
|
129832
|
+
discovered = await explorePageWithAI(page, currentUrl, interceptor, model, globalState, inScope, SINGLE_CRED, maxPages, usageAcc, { explore: exploreInline, depth: 0 });
|
|
129833
|
+
} catch (err) {
|
|
129834
|
+
if (isBrowserDead(health)) {
|
|
129835
|
+
log7.error("exploration aborted — browser died mid-page", { url: currentUrl, reason: health.reason });
|
|
129836
|
+
break;
|
|
129837
|
+
}
|
|
129838
|
+
log7.warn("exploration error", { url: currentUrl, err: String(err) });
|
|
129839
|
+
}
|
|
129840
|
+
let newEnqueued = 0;
|
|
129841
|
+
for (const url3 of discovered) {
|
|
129842
|
+
if (enqueueUrl(url3, globalState, inScope))
|
|
129843
|
+
newEnqueued++;
|
|
129844
|
+
}
|
|
129845
|
+
if (discovered.length > 0) {
|
|
129846
|
+
log7.debug("discovered links", {
|
|
129847
|
+
found: discovered.length,
|
|
129848
|
+
enqueued: newEnqueued,
|
|
129849
|
+
queueSize: globalState.pageQueue.length
|
|
129850
|
+
});
|
|
129851
|
+
}
|
|
129852
|
+
flushReDiscovery(globalState);
|
|
129853
|
+
await page.waitForTimeout(300);
|
|
129854
|
+
if (globalState.pageQueue.length === 0 && globalState.deferredAuthPages.length > 0) {
|
|
129855
|
+
log7.debug("queue empty, processing auth phase", {
|
|
129856
|
+
phase: globalState.authPhase,
|
|
129857
|
+
deferred: globalState.deferredAuthPages.map((d) => d.type)
|
|
129858
|
+
});
|
|
129859
|
+
processAuthPhase(globalState);
|
|
129860
|
+
}
|
|
129639
129861
|
}
|
|
129640
|
-
|
|
129641
|
-
|
|
129642
|
-
|
|
129643
|
-
|
|
129644
|
-
|
|
129645
|
-
|
|
129646
|
-
|
|
129647
|
-
|
|
129648
|
-
|
|
129649
|
-
|
|
129650
|
-
|
|
129651
|
-
|
|
129652
|
-
|
|
129653
|
-
});
|
|
129654
|
-
csEmit(page, {
|
|
129655
|
-
type: "crawl-done",
|
|
129656
|
-
summary: {
|
|
129862
|
+
const browserDied = isBrowserDead(health);
|
|
129863
|
+
log7.info(browserDied ? "browser died, draining captured requests" : "exploration complete, draining remaining requests", {
|
|
129864
|
+
pagesExplored,
|
|
129865
|
+
captured: globalState.capturedEndpoints.size,
|
|
129866
|
+
...browserDied ? { reason: health.reason } : {}
|
|
129867
|
+
});
|
|
129868
|
+
if (!browserDied)
|
|
129869
|
+
await page.waitForTimeout(2000).catch(() => {});
|
|
129870
|
+
while (captureQueue.length > 0) {
|
|
129871
|
+
const captured = captureQueue.shift();
|
|
129872
|
+
await handleCapture(captured);
|
|
129873
|
+
}
|
|
129874
|
+
log7.info("done", {
|
|
129657
129875
|
pagesExplored,
|
|
129876
|
+
totalSteps: globalState.totalSteps,
|
|
129658
129877
|
capturedEndpoints: globalState.capturedEndpoints.size,
|
|
129659
|
-
|
|
129660
|
-
|
|
129878
|
+
sessionID: dryRun ? undefined : sessionID,
|
|
129879
|
+
browserDied
|
|
129880
|
+
});
|
|
129881
|
+
if (!browserDied) {
|
|
129882
|
+
csEmit(page, {
|
|
129883
|
+
type: "crawl-done",
|
|
129884
|
+
summary: {
|
|
129885
|
+
pagesExplored,
|
|
129886
|
+
capturedEndpoints: globalState.capturedEndpoints.size,
|
|
129887
|
+
mutations: [...globalState.capturedEndpoints].filter((e2) => /^(POST|PUT|PATCH|DELETE)\s/.test(e2)).length,
|
|
129888
|
+
credentials: [SINGLE_CRED]
|
|
129889
|
+
}
|
|
129890
|
+
});
|
|
129891
|
+
await page.waitForTimeout(600).catch(() => {});
|
|
129892
|
+
while (captureQueue.length > 0) {
|
|
129893
|
+
const captured = captureQueue.shift();
|
|
129894
|
+
await handleCapture(captured);
|
|
129895
|
+
}
|
|
129896
|
+
}
|
|
129897
|
+
if (!config3.headless && browser.isConnected()) {
|
|
129898
|
+
log7.info("crawl complete — browser stays open, close the window to finish");
|
|
129899
|
+
const postCrawlDrain = setInterval(async () => {
|
|
129900
|
+
while (captureQueue.length > 0) {
|
|
129901
|
+
const captured = captureQueue.shift();
|
|
129902
|
+
await handleCapture(captured);
|
|
129903
|
+
}
|
|
129904
|
+
}, 500);
|
|
129905
|
+
await waitForBrowserClose(browser, config3.signal);
|
|
129906
|
+
clearInterval(postCrawlDrain);
|
|
129907
|
+
} else if (!browserDied) {
|
|
129908
|
+
await browser.close().catch(() => {});
|
|
129661
129909
|
}
|
|
129662
|
-
|
|
129663
|
-
|
|
129664
|
-
|
|
129665
|
-
|
|
129666
|
-
|
|
129667
|
-
|
|
129668
|
-
|
|
129669
|
-
|
|
129670
|
-
|
|
129671
|
-
|
|
129672
|
-
}
|
|
129910
|
+
return {
|
|
129911
|
+
sessionID: dryRun ? "" : sessionID,
|
|
129912
|
+
capturedEndpoints: globalState.capturedEndpoints.size,
|
|
129913
|
+
pagesExplored,
|
|
129914
|
+
totalSteps: globalState.totalSteps,
|
|
129915
|
+
errors: browserDied ? [`Browser died: ${health.reason}. Captured ${globalState.capturedEndpoints.size} endpoints before failure.`] : [],
|
|
129916
|
+
usage: usageAcc
|
|
129917
|
+
};
|
|
129918
|
+
} finally {
|
|
129919
|
+
clearInterval(drainInterval);
|
|
129920
|
+
}
|
|
129673
129921
|
}
|
|
129674
129922
|
|
|
129675
129923
|
// ../hackbrowser/src/api.ts
|
|
@@ -129962,7 +130210,11 @@ async function main() {
|
|
|
129962
130210
|
});
|
|
129963
130211
|
}
|
|
129964
130212
|
});
|
|
129965
|
-
await new Promise((resolve4) => rl.once("close",
|
|
130213
|
+
await new Promise((resolve4) => rl.once("close", () => {
|
|
130214
|
+
controller.abort();
|
|
130215
|
+
resolve4();
|
|
130216
|
+
}));
|
|
130217
|
+
setTimeout(() => process.exit(0), 5000).unref();
|
|
129966
130218
|
}
|
|
129967
130219
|
async function runWorker(opts, signal) {
|
|
129968
130220
|
const crawlOpts = buildCrawlOptions(opts, signal);
|