├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .project
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── browserup-proxy-core
├── .classpath
├── .project
├── Mitmproxy_Integration_Notes.txt
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── browserup
│ │ │ ├── bup
│ │ │ ├── BrowserUpProxy.java
│ │ │ ├── BrowserUpProxyServer.java
│ │ │ ├── MitmProxyServer.java
│ │ │ ├── assertion
│ │ │ │ ├── HarEntryAssertion.java
│ │ │ │ ├── ResponseTimeLessThanOrEqualAssertion.java
│ │ │ │ ├── error
│ │ │ │ │ └── HarEntryAssertionError.java
│ │ │ │ ├── field
│ │ │ │ │ ├── FieldPassesPredicateAssertion.java
│ │ │ │ │ ├── HarEntryAssertionFieldSupplier.java
│ │ │ │ │ ├── HarEntryPredicate.java
│ │ │ │ │ ├── content
│ │ │ │ │ │ ├── ContentContainsStringAssertion.java
│ │ │ │ │ │ ├── ContentDoesNotContainStringAssertion.java
│ │ │ │ │ │ ├── ContentMatchesAssertion.java
│ │ │ │ │ │ ├── ContentPassesPredicateAssertion.java
│ │ │ │ │ │ ├── ContentSizeLessThanOrEqualAssertion.java
│ │ │ │ │ │ └── ContentSizePassesPredicateAssertion.java
│ │ │ │ │ ├── header
│ │ │ │ │ │ ├── FilteredHeadersContainStringAssertion.java
│ │ │ │ │ │ ├── FilteredHeadersDoNotContainStringAssertion.java
│ │ │ │ │ │ ├── FilteredHeadersMatchAssertion.java
│ │ │ │ │ │ ├── HeadersContainStringAssertion.java
│ │ │ │ │ │ ├── HeadersDoNotContainStringAssertion.java
│ │ │ │ │ │ ├── HeadersMatchAssertion.java
│ │ │ │ │ │ └── HeadersPassPredicateAssertion.java
│ │ │ │ │ └── status
│ │ │ │ │ │ ├── StatusBelongsToClassAssertion.java
│ │ │ │ │ │ ├── StatusEqualsAssertion.java
│ │ │ │ │ │ └── StatusPassesPredicateAssertion.java
│ │ │ │ ├── model
│ │ │ │ │ ├── AssertionEntryResult.java
│ │ │ │ │ ├── AssertionResult.java
│ │ │ │ │ └── filter
│ │ │ │ │ │ ├── AssertionFilterInfo.java
│ │ │ │ │ │ └── AssertionUrlFilterInfo.java
│ │ │ │ └── supplier
│ │ │ │ │ ├── CurrentStepHarEntriesSupplier.java
│ │ │ │ │ ├── HarEntriesSupplier.java
│ │ │ │ │ ├── MostRecentHarEntrySupplier.java
│ │ │ │ │ ├── MostRecentUrlFilteredHarEntrySupplier.java
│ │ │ │ │ └── UrlFilteredHarEntriesSupplier.java
│ │ │ ├── client
│ │ │ │ └── ClientUtil.java
│ │ │ ├── exception
│ │ │ │ ├── DecompressionException.java
│ │ │ │ └── UnsupportedCharsetException.java
│ │ │ ├── filters
│ │ │ │ ├── AddHeadersFilter.java
│ │ │ │ ├── AllowlistFilter.java
│ │ │ │ ├── AutoBasicAuthFilter.java
│ │ │ │ ├── BlocklistFilter.java
│ │ │ │ ├── BrowserUpHttpFilterChain.java
│ │ │ │ ├── ClientRequestCaptureFilter.java
│ │ │ │ ├── HarCaptureFilter.java
│ │ │ │ ├── HttpConnectHarCaptureFilter.java
│ │ │ │ ├── HttpsAwareFiltersAdapter.java
│ │ │ │ ├── HttpsHostCaptureFilter.java
│ │ │ │ ├── HttpsOriginalHostCaptureFilter.java
│ │ │ │ ├── LatencyFilter.java
│ │ │ │ ├── ModifiedRequestAwareFilter.java
│ │ │ │ ├── RegisterRequestFilter.java
│ │ │ │ ├── RequestFilter.java
│ │ │ │ ├── RequestFilterAdapter.java
│ │ │ │ ├── ResolvedHostnameCacheFilter.java
│ │ │ │ ├── ResponseFilter.java
│ │ │ │ ├── ResponseFilterAdapter.java
│ │ │ │ ├── RewriteUrlFilter.java
│ │ │ │ ├── ServerResponseCaptureFilter.java
│ │ │ │ ├── UnregisterRequestFilter.java
│ │ │ │ ├── support
│ │ │ │ │ └── HttpConnectTiming.java
│ │ │ │ └── util
│ │ │ │ │ └── HarCaptureUtil.java
│ │ │ ├── mitmproxy
│ │ │ │ ├── MitmProxyProcessManager.java
│ │ │ │ ├── NetworkUtils.java
│ │ │ │ ├── addons
│ │ │ │ │ ├── AbstractAddon.java
│ │ │ │ │ ├── AdditionalHeadersAddOn.java
│ │ │ │ │ ├── AddonsManagerAddOn.java
│ │ │ │ │ ├── AllowListAddOn.java
│ │ │ │ │ ├── AuthBasicAddOn.java
│ │ │ │ │ ├── BlockListAddOn.java
│ │ │ │ │ ├── HarCaptureAddOn.java
│ │ │ │ │ ├── HttpConnectCaptureAddOn.java
│ │ │ │ │ ├── InitFlowAddOn.java
│ │ │ │ │ ├── LatencyAddOn.java
│ │ │ │ │ ├── ProxyManagerAddOn.java
│ │ │ │ │ └── RewriteUrlAddOn.java
│ │ │ │ └── management
│ │ │ │ │ ├── AdditionalHeadersManager.java
│ │ │ │ │ ├── AddonsManagerClient.java
│ │ │ │ │ ├── AllowListManager.java
│ │ │ │ │ ├── AuthBasicManager.java
│ │ │ │ │ ├── BlockListManager.java
│ │ │ │ │ ├── HarCaptureManager.java
│ │ │ │ │ ├── LatencyManager.java
│ │ │ │ │ ├── ProxyManager.java
│ │ │ │ │ └── RewriteUrlManager.java
│ │ │ ├── proxy
│ │ │ │ ├── ActivityMonitor.java
│ │ │ │ ├── Allowlist.java
│ │ │ │ ├── BlocklistEntry.java
│ │ │ │ ├── CaptureType.java
│ │ │ │ ├── RewriteRule.java
│ │ │ │ ├── auth
│ │ │ │ │ └── AuthType.java
│ │ │ │ └── dns
│ │ │ │ │ ├── AbstractHostNameRemapper.java
│ │ │ │ │ ├── AdvancedHostResolver.java
│ │ │ │ │ ├── BasicHostResolver.java
│ │ │ │ │ ├── ChainedHostResolver.java
│ │ │ │ │ ├── DelegatingHostResolver.java
│ │ │ │ │ ├── DnsJavaResolver.java
│ │ │ │ │ ├── HostResolver.java
│ │ │ │ │ ├── NativeCacheManipulatingResolver.java
│ │ │ │ │ └── NativeResolver.java
│ │ │ └── util
│ │ │ │ ├── BrowserUpHttpUtil.java
│ │ │ │ ├── BrowserUpProxyUtil.java
│ │ │ │ ├── HttpMessageContents.java
│ │ │ │ ├── HttpMessageInfo.java
│ │ │ │ ├── HttpObjectUtil.java
│ │ │ │ └── HttpStatusClass.java
│ │ │ └── harreader
│ │ │ ├── HarReader.java
│ │ │ ├── HarReaderException.java
│ │ │ ├── HarReaderMode.java
│ │ │ ├── LICENSE.MD
│ │ │ ├── README.md
│ │ │ ├── filter
│ │ │ ├── HarEntriesFilter.java
│ │ │ └── HarEntriesUrlPatternFilter.java
│ │ │ ├── jackson
│ │ │ ├── DefaultMapperFactory.java
│ │ │ ├── ExceptionIgnoringDateDeserializer.java
│ │ │ ├── ExceptionIgnoringIntegerDeserializer.java
│ │ │ └── MapperFactory.java
│ │ │ └── model
│ │ │ ├── Har.java
│ │ │ ├── HarCache.java
│ │ │ ├── HarContent.java
│ │ │ ├── HarCookie.java
│ │ │ ├── HarCreatorBrowser.java
│ │ │ ├── HarEntry.java
│ │ │ ├── HarHeader.java
│ │ │ ├── HarLog.java
│ │ │ ├── HarPage.java
│ │ │ ├── HarPageTiming.java
│ │ │ ├── HarPostData.java
│ │ │ ├── HarPostDataParam.java
│ │ │ ├── HarQueryParam.java
│ │ │ ├── HarRequest.java
│ │ │ ├── HarResponse.java
│ │ │ ├── HarTiming.java
│ │ │ ├── HttpMethod.java
│ │ │ └── HttpStatus.java
│ └── resources
│ │ ├── com
│ │ └── browserup
│ │ │ └── bup
│ │ │ └── version
│ │ ├── mitmproxy
│ │ ├── additional_headers.py
│ │ ├── allow_list.py
│ │ ├── auth_basic.py
│ │ ├── block_list.py
│ │ ├── bu_addons_manager.py
│ │ ├── har_dump.py
│ │ ├── http_connect_capture.py
│ │ ├── init_flow.py
│ │ ├── latency.py
│ │ ├── proxy_manager.py
│ │ └── rewrite_url.py
│ │ └── sslSupport
│ │ ├── ca-certificate-ec.cer
│ │ ├── ca-certificate-rsa.cer
│ │ ├── ca-keystore-ec.p12
│ │ └── ca-keystore-rsa.p12
│ └── test
│ ├── groovy
│ └── com
│ │ └── browserup
│ │ └── bup
│ │ ├── MitmProxyProcessManagerTest.groovy
│ │ ├── assertion
│ │ ├── ResponseTimeLessThanOrEqualAssertionTest.groovy
│ │ └── supplier
│ │ │ ├── MostRecentUrlFilteredHarEntrySupplierTest.groovy
│ │ │ └── UrlFilteredHarEntrySupplierTest.groovy
│ │ ├── filters
│ │ └── RewriteUrlFilterTest.groovy
│ │ ├── mitmproxy
│ │ ├── AbsentHarTest.groovy
│ │ ├── AdditionalHeadersTest.groovy
│ │ ├── AllowlistTest.groovy
│ │ ├── AutoAuthTest.groovy
│ │ ├── BlocklistTest.groovy
│ │ ├── ChainedProxyAuthTest.groovy
│ │ ├── DefaultHarPageTest.groovy
│ │ ├── DefaultStepIdTest.groovy
│ │ ├── GetHarTest.groovy
│ │ ├── HarValidationTest.groovy
│ │ ├── LatencyTest.groovy
│ │ ├── NewHarTest.groovy
│ │ ├── RewriteUrlFilterTest.groovy
│ │ └── UnbalancedHarEntriesTest.groovy
│ │ ├── proxy
│ │ ├── AbsentHarTest.groovy
│ │ ├── AutoAuthTest.groovy
│ │ ├── BindAddressTest.groovy
│ │ ├── BlacklistTest.groovy
│ │ ├── ChainedProxyAuthTest.groovy
│ │ ├── DefaultStepIdTest.groovy
│ │ ├── FilterChainTest.groovy
│ │ ├── GetHarTest.groovy
│ │ ├── HarValidationTest.groovy
│ │ ├── NewHarTest.groovy
│ │ ├── NonProxyChainTest.groovy
│ │ ├── RemapHostsTest.groovy
│ │ ├── RewriteRuleTest.groovy
│ │ ├── WhitelistTest.groovy
│ │ └── assertion
│ │ │ ├── AllUrlResponsesTimeWithinTest.groovy
│ │ │ ├── BaseAssertionsTest.groovy
│ │ │ ├── MostRecentUrlResponseTimeLessThanOrEqualTest.groovy
│ │ │ └── field
│ │ │ ├── content
│ │ │ ├── ContentBaseTest.groovy
│ │ │ ├── ContentSizeLessThanOrEqualTest.groovy
│ │ │ ├── filtered
│ │ │ │ ├── ContentContainsTest.groovy
│ │ │ │ ├── ContentDoesNotContainTest.groovy
│ │ │ │ ├── ContentLengthLessThanOrEqualTest.groovy
│ │ │ │ ├── ContentMatchesTest.groovy
│ │ │ │ └── FilteredContentBaseTest.groovy
│ │ │ └── mostrecent
│ │ │ │ ├── ContentContainsTest.groovy
│ │ │ │ ├── ContentDoesNotContainTest.groovy
│ │ │ │ ├── ContentMatchesTest.groovy
│ │ │ │ └── MostRecentContentBaseTest.groovy
│ │ │ ├── header
│ │ │ ├── HeaderBaseTest.groovy
│ │ │ ├── filtered
│ │ │ │ ├── FilteredHeaderBaseTest.groovy
│ │ │ │ ├── HeaderContainsTest.groovy
│ │ │ │ ├── HeaderDoesNotContainTest.groovy
│ │ │ │ └── HeaderMatchesTest.groovy
│ │ │ └── mostrecent
│ │ │ │ ├── HeaderContainsTest.groovy
│ │ │ │ ├── HeaderDoesNotContainTest.groovy
│ │ │ │ └── HeaderMatchesTest.groovy
│ │ │ └── status
│ │ │ ├── AllCurrentStepUrlsStatusAssertionsTest.groovy
│ │ │ ├── FilteredUrlsStatusAssertionsTest.groovy
│ │ │ └── mostrecent
│ │ │ ├── FilteredMostRecentUrlStatusAssertionsTest.groovy
│ │ │ └── MostRecentUrlStatusAssertionsTest.groovy
│ │ └── util
│ │ └── BrowserUpHttpUtilTest.groovy
│ ├── java
│ └── com
│ │ └── browserup
│ │ ├── bup
│ │ └── proxy
│ │ │ ├── InterceptorTest.java
│ │ │ ├── NetworkTest.java
│ │ │ ├── QuiescenceTest.java
│ │ │ ├── dns
│ │ │ ├── AdvancedHostResolverCacheTest.java
│ │ │ ├── AdvancedHostResolverTest.java
│ │ │ └── ChainedHostResolverTest.java
│ │ │ └── test
│ │ │ └── util
│ │ │ ├── MockServerTest.java
│ │ │ ├── NewProxyServerTest.java
│ │ │ ├── NewProxyServerTestUtil.java
│ │ │ └── TestConstants.java
│ │ └── harreader
│ │ ├── HarReaderTest.java
│ │ ├── filter
│ │ └── HarEntryFilterTest.java
│ │ └── model
│ │ ├── AbstractMapperTest.java
│ │ ├── HarCacheTest.java
│ │ ├── HarContentTest.java
│ │ ├── HarCookieTest.java
│ │ ├── HarCreatorBrowserTest.java
│ │ ├── HarEntryTest.java
│ │ ├── HarHeaderTest.java
│ │ ├── HarLogTest.java
│ │ ├── HarPageTest.java
│ │ ├── HarPageTimingTest.java
│ │ ├── HarPostDataParamTest.java
│ │ ├── HarPostDataTest.java
│ │ ├── HarQueryParamTest.java
│ │ ├── HarRequestTest.java
│ │ ├── HarResponseTest.java
│ │ ├── HarTest.java
│ │ ├── HarTimingTest.java
│ │ └── HttpStatusTest.java
│ └── resources
│ ├── log4j2-test.json
│ ├── sstoehr.har
│ ├── sstoehr.invalid-date.har
│ └── sstoehr.invalid-integer.har
├── browserup-proxy-dist
├── .classpath
├── .project
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── browserup
│ │ └── bup
│ │ ├── exception
│ │ └── JettyException.java
│ │ ├── proxy
│ │ └── Main.java
│ │ └── util
│ │ └── DeleteDirectoryTask.java
│ └── resources
│ └── bup-logging.yaml
├── browserup-proxy-mitm
├── .classpath
├── .project
├── README.md
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── browserup
│ │ │ └── bup
│ │ │ ├── mitm
│ │ │ ├── CertificateAndKey.java
│ │ │ ├── CertificateAndKeySource.java
│ │ │ ├── CertificateInfo.java
│ │ │ ├── CertificateInfoGenerator.java
│ │ │ ├── ExistingCertificateSource.java
│ │ │ ├── HostnameCertificateInfoGenerator.java
│ │ │ ├── KeyStoreCertificateSource.java
│ │ │ ├── KeyStoreFileCertificateSource.java
│ │ │ ├── PemFileCertificateSource.java
│ │ │ ├── RootCertificateGenerator.java
│ │ │ ├── TrustSource.java
│ │ │ ├── exception
│ │ │ │ ├── CertificateCreationException.java
│ │ │ │ ├── CertificateSourceException.java
│ │ │ │ ├── ExportException.java
│ │ │ │ ├── ImportException.java
│ │ │ │ ├── KeyGeneratorException.java
│ │ │ │ ├── KeyStoreAccessException.java
│ │ │ │ ├── MitmException.java
│ │ │ │ ├── SslContextInitializationException.java
│ │ │ │ ├── TrustSourceException.java
│ │ │ │ └── UncheckedIOException.java
│ │ │ ├── keys
│ │ │ │ ├── ECKeyGenerator.java
│ │ │ │ ├── KeyGenerator.java
│ │ │ │ └── RSAKeyGenerator.java
│ │ │ ├── manager
│ │ │ │ └── ImpersonatingMitmManager.java
│ │ │ ├── stats
│ │ │ │ └── CertificateGenerationStatistics.java
│ │ │ ├── tools
│ │ │ │ ├── BouncyCastleSecurityProviderTool.java
│ │ │ │ ├── DefaultSecurityProviderTool.java
│ │ │ │ └── SecurityProviderTool.java
│ │ │ ├── trustmanager
│ │ │ │ ├── InsecureExtendedTrustManager.java
│ │ │ │ └── InsecureTrustManagerFactory.java
│ │ │ └── util
│ │ │ │ ├── EncryptionUtil.java
│ │ │ │ ├── KeyStoreUtil.java
│ │ │ │ ├── MitmConstants.java
│ │ │ │ ├── SslUtil.java
│ │ │ │ └── TrustUtil.java
│ │ │ └── util
│ │ │ ├── ClasspathResourceUtil.java
│ │ │ └── HttpUtil.java
│ └── resources
│ │ ├── cacerts.pem
│ │ └── default-ciphers.txt
│ └── test
│ ├── groovy
│ └── com
│ │ └── browserup
│ │ └── bup
│ │ └── mitm
│ │ ├── ExistingCertificateSourceTest.groovy
│ │ ├── ImpersonatingMitmManagerTest.groovy
│ │ ├── KeyStoreCertificateSourceTest.groovy
│ │ ├── KeyStoreFileCertificateSourceTest.groovy
│ │ ├── PemFileCertificateSourceTest.groovy
│ │ ├── RootCertificateGeneratorTest.groovy
│ │ ├── TrustSourceTest.groovy
│ │ └── tools
│ │ ├── ECKeyGeneratorTest.groovy
│ │ └── RSAKeyGeneratorTest.groovy
│ ├── java
│ └── com
│ │ └── browserup
│ │ └── bup
│ │ └── mitm
│ │ ├── ImpersonationPerformanceTests.java
│ │ ├── example
│ │ ├── CustomCAKeyStoreExample.java
│ │ ├── CustomCAPemFileExample.java
│ │ ├── EllipticCurveCAandServerExample.java
│ │ ├── LittleProxyDefaultConfigExample.java
│ │ └── SaveGeneratedCAExample.java
│ │ ├── integration
│ │ └── LittleProxyIntegrationTest.java
│ │ └── test
│ │ └── util
│ │ └── CertificateTestUtil.java
│ └── resources
│ ├── com
│ └── browserup
│ │ └── bup
│ │ └── mitm
│ │ ├── certificate.crt
│ │ ├── encrypted-private-key.key
│ │ ├── keystore.jks
│ │ ├── keystore.p12
│ │ ├── trusted-cert.jks
│ │ └── unencrypted-private-key.key
│ └── log4j2-test.json
├── browserup-proxy-rest-clients
├── build.gradle
└── src
│ ├── main
│ └── resources
│ │ └── openapi-config.json
│ └── test
│ ├── groovy
│ └── com
│ │ └── browserup
│ │ └── bup
│ │ ├── WithRunningProxyRestTest.groovy
│ │ ├── javascript
│ │ └── JavaScriptClientTest.groovy
│ │ ├── python
│ │ └── PythonTestClient.groovy
│ │ └── ruby
│ │ └── RubyClientTest.groovy
│ ├── javascript
│ ├── .gitignore
│ ├── Dockerfile
│ └── test
│ │ └── javascript_test.js
│ ├── python
│ ├── .gitignore
│ ├── Dockerfile
│ └── test
│ │ └── python_test.py
│ ├── resources
│ └── log4j2-test.json
│ └── ruby
│ ├── .gitignore
│ ├── .rspec
│ ├── Dockerfile
│ ├── Gemfile
│ ├── Gemfile.lock
│ └── spec
│ └── test_client_spec.rb
├── browserup-proxy-rest
├── .classpath
├── .project
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── browserup
│ │ │ └── bup
│ │ │ ├── exception
│ │ │ ├── JavascriptCompilationException.java
│ │ │ ├── ProxyExistsException.java
│ │ │ └── ProxyPortsExhaustedException.java
│ │ │ ├── filters
│ │ │ └── JavascriptRequestResponseFilter.java
│ │ │ ├── proxy
│ │ │ ├── MitmProxyManager.java
│ │ │ ├── ProxyManager.java
│ │ │ ├── bricks
│ │ │ │ └── ProxyResource.java
│ │ │ └── guice
│ │ │ │ ├── ConfigModule.java
│ │ │ │ ├── JettyModule.java
│ │ │ │ ├── JettyServerProvider.java
│ │ │ │ └── NamedImpl.java
│ │ │ └── rest
│ │ │ ├── filter
│ │ │ └── LoggingFilter.java
│ │ │ ├── openapi
│ │ │ ├── CustomOpenApiReader.java
│ │ │ └── DocConstants.java
│ │ │ ├── resource
│ │ │ ├── entries
│ │ │ │ └── EntriesProxyResource.java
│ │ │ └── mostrecent
│ │ │ │ └── MostRecentEntryProxyResource.java
│ │ │ └── validation
│ │ │ ├── HttpStatusCodeConstraint.java
│ │ │ ├── LongPositiveConstraint.java
│ │ │ ├── NotBlankConstraint.java
│ │ │ ├── NotNullConstraint.java
│ │ │ ├── PatternConstraint.java
│ │ │ ├── PortWithExistingProxyConstraint.java
│ │ │ ├── mapper
│ │ │ ├── ConstraintViolationExceptionMapper.java
│ │ │ └── model
│ │ │ │ ├── ArgumentConstraintsErrors.java
│ │ │ │ └── ConstraintsErrors.java
│ │ │ └── util
│ │ │ └── MessageSanitizer.java
│ └── resources
│ │ └── swagger-config.yaml
│ └── test
│ ├── groovy
│ └── com
│ │ └── browserup
│ │ └── bup
│ │ └── proxy
│ │ ├── FilterTest.groovy
│ │ ├── mitmproxy
│ │ ├── BaseRestTest.groovy
│ │ ├── FindHarEntriesRestTest.groovy
│ │ ├── FindMostRecentEntryRestTest.groovy
│ │ ├── ProxyManagerTest.groovy
│ │ ├── ProxyPortAssignmentTest.java
│ │ ├── ProxyResourceTest.groovy
│ │ ├── ValidateHarRestTest.groovy
│ │ ├── WithRunningProxyRestTest.groovy
│ │ ├── assertion
│ │ │ ├── entries
│ │ │ │ ├── EntriesAssertTimeLessThanOrEqualRestTest.groovy
│ │ │ │ ├── content
│ │ │ │ │ ├── BaseEntriesAssertContentRestTest.groovy
│ │ │ │ │ ├── EntriesAssertContentContainsRestTest.groovy
│ │ │ │ │ ├── EntriesAssertContentDoesNotContainRestTest.groovy
│ │ │ │ │ ├── EntriesAssertContentLengthLessThanOrEqualRestTest.groovy
│ │ │ │ │ └── EntriesAssertContentMatchesRestTest.groovy
│ │ │ │ ├── header
│ │ │ │ │ ├── BaseEntriesAssertHeaderRestTest.groovy
│ │ │ │ │ ├── EntriesAssertHeaderContainsRestTest.groovy
│ │ │ │ │ ├── EntriesAssertHeaderDoesNotContainRestTest.groovy
│ │ │ │ │ └── EntriesAssertHeaderMatchesRestTest.groovy
│ │ │ │ └── status
│ │ │ │ │ ├── EntriesAssertStatusClientErrorRestTest.groovy
│ │ │ │ │ ├── EntriesAssertStatusEqualsRestTest.groovy
│ │ │ │ │ ├── EntriesAssertStatusRedirectionRestTest.groovy
│ │ │ │ │ ├── EntriesAssertStatusServerErrorRestTest.groovy
│ │ │ │ │ └── EntriesAssertStatusSuccessRestTest.groovy
│ │ │ └── mostrecent
│ │ │ │ ├── MostRecentEntryAssertTimeLessThanOrEqualRestTest.groovy
│ │ │ │ ├── content
│ │ │ │ ├── MostRecentEntryAssertContentContainsRestTest.groovy
│ │ │ │ ├── MostRecentEntryAssertContentDoesNotContainRestTest.groovy
│ │ │ │ └── MostRecentEntryAssertContentLengthLessThanOrEqualRestTest.groovy
│ │ │ │ ├── header
│ │ │ │ ├── MostRecentEntryAssertHeaderContainsRestTest.groovy
│ │ │ │ ├── MostRecentEntryAssertHeaderDoesNotContainRestTest.groovy
│ │ │ │ └── MostRecentEntryAssertHeaderMatchesRestTest.groovy
│ │ │ │ └── status
│ │ │ │ ├── MostRecentEntryAssertStatusClientErrorRestTest.groovy
│ │ │ │ ├── MostRecentEntryAssertStatusEqualsRestTest.groovy
│ │ │ │ ├── MostRecentEntryAssertStatusRedirectionRestTest.groovy
│ │ │ │ ├── MostRecentEntryAssertStatusServerErrorRestTest.groovy
│ │ │ │ └── MostRecentEntryAssertStatusSuccessRestTest.groovy
│ │ └── validation
│ │ │ ├── HttpStatusCodeConstraintTest.groovy
│ │ │ ├── LongPositiveConstraintTest.groovy
│ │ │ ├── PatternConstraintTest.groovy
│ │ │ └── PortWithExistingProxyConstraintTest.groovy
│ │ └── test
│ │ └── util
│ │ └── ProxyResourceTest.groovy
│ ├── java
│ └── com
│ │ └── browserup
│ │ └── bup
│ │ └── proxy
│ │ ├── ExpiringProxyTest.java
│ │ ├── ProxyPortAssignmentTest.java
│ │ └── test
│ │ └── util
│ │ └── ProxyManagerTest.java
│ └── resources
│ └── log4j2-test.json
├── browserup-proxy.iml
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── nohup.out
└── settings.gradle
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Add Proxy with these settings, in this manner
16 | 2. Go to '...'
17 | 3. Look in '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Please complete the following information:**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari, firefox]
29 | - Version [e.g. 22]
30 |
31 |
32 |
33 | **Additional context**
34 | Add any other context about the problem here.
35 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[enhancement]"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | browserup-proxy
4 | Project browserup-proxy created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.buildship.core.gradleprojectbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.buildship.core.gradleprojectnature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | How to Contribute
2 |
3 | Find a bug?
4 |
5 | Ensure the bug was not already reported by searching on GitHub under Issues.
6 |
7 | If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
8 |
9 | Did you write a patch that fixes a bug?
10 |
11 | Open a new GitHub pull request with the patch. We may choose not to accept pull requests without tests, or for other reasons.
12 |
13 | Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
14 |
15 | Contributions will be Apache 2 Licensed. Contributions welcomed!
16 |
17 | Thanks! ❤️ ❤️ ❤️
18 |
19 | BrowserUp Team
20 |
--------------------------------------------------------------------------------
/browserup-proxy-core/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/browserup-proxy-core/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | browserup-proxy-core
4 | Project browserup-proxy-core created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.buildship.core.gradleprojectbuilder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.buildship.core.gradleprojectnature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/browserup-proxy-core/Mitmproxy_Integration_Notes.txt:
--------------------------------------------------------------------------------
1 | 1. com.browserup.bup.MitmProxyServer.setChainedProxyNonProxyHosts
2 |
3 | Mitmproxy doesn't provide 'upstream' proxy exception hosts API:
4 | https://github.com/mitmproxy/mitmproxy/issues/1821
5 |
6 | Possible workaround might be using approach from addon 'change_upstream_proxy.py' (using flow.live.change_upstream_proxy_server),
7 | but it doesn't allow to avoid upstream proxy at all - only switch between upstream proxies.
8 | We could add transparent pass-through proxy for user and redirect request there in case request host is matched by non-upstream-proxy host filters, provided by user, but that doesn't sound acceptable, we'd still have upstream proxy.
9 | Related issue:
10 | https://github.com/mitmproxy/mitmproxy/issues/2123
11 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/HarEntryAssertion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion;
6 |
7 | import com.browserup.bup.assertion.error.HarEntryAssertionError;
8 | import com.browserup.harreader.model.HarEntry;
9 |
10 | import java.util.Optional;
11 |
12 | @FunctionalInterface
13 | public interface HarEntryAssertion {
14 |
15 | Optional assertion(HarEntry entry);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/ResponseTimeLessThanOrEqualAssertion.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion;
6 |
7 | import com.browserup.bup.assertion.error.HarEntryAssertionError;
8 | import com.browserup.harreader.model.HarEntry;
9 |
10 | import java.util.Optional;
11 |
12 | public class ResponseTimeLessThanOrEqualAssertion implements HarEntryAssertion {
13 | private final Long time;
14 |
15 | public ResponseTimeLessThanOrEqualAssertion(Long time) {
16 | this.time = time;
17 | }
18 |
19 | @Override
20 | public Optional assertion(HarEntry entry) {
21 | if (entry.getTime() > time) {
22 | return Optional.of(new HarEntryAssertionError("Time exceeded", time, entry.getTime()));
23 | }
24 | return Optional.empty();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/error/HarEntryAssertionError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion.error;
6 |
7 | public class HarEntryAssertionError {
8 | private final String message;
9 |
10 | public HarEntryAssertionError(String message) {
11 | this.message = message;
12 | }
13 |
14 | public HarEntryAssertionError(Object expected, Object actual) {
15 | this.message = String.format("Assertion failed, expected: %s, actual: %s",
16 | String.valueOf(expected), String.valueOf(actual));
17 | }
18 |
19 | public HarEntryAssertionError(String prefixMessage, Object expected, Object actual) {
20 | this.message = String.format("%s. Expected: %s, actual: %s",
21 | prefixMessage, String.valueOf(expected), String.valueOf(actual));
22 | }
23 |
24 | public String getMessage() {
25 | return message;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/FieldPassesPredicateAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field;
2 |
3 | import com.browserup.bup.assertion.HarEntryAssertion;
4 | import com.browserup.bup.assertion.error.HarEntryAssertionError;
5 | import com.browserup.harreader.model.HarEntry;
6 |
7 | import java.util.Optional;
8 |
9 | public abstract class FieldPassesPredicateAssertion implements HarEntryAssertion {
10 |
11 | public abstract HarEntryAssertionFieldSupplier getFieldSupplier();
12 |
13 | public abstract HarEntryPredicate getHarEntryPredicate();
14 |
15 | @Override
16 | public Optional assertion(HarEntry entry) {
17 | FieldType input = getFieldSupplier().apply(entry);
18 |
19 | return getHarEntryPredicate().test(input).map(HarEntryAssertionError::new);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/HarEntryAssertionFieldSupplier.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field;
2 |
3 | import com.browserup.harreader.model.HarEntry;
4 |
5 | import java.util.function.Function;
6 |
7 | @FunctionalInterface
8 | public interface HarEntryAssertionFieldSupplier extends Function {
9 | }
10 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/HarEntryPredicate.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field;
2 |
3 | import java.util.Optional;
4 |
5 | public interface HarEntryPredicate {
6 |
7 | Optional test(T entry);
8 | }
9 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/content/ContentContainsStringAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.content;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import org.apache.commons.lang3.StringUtils;
5 |
6 | import java.util.Optional;
7 |
8 | public class ContentContainsStringAssertion extends ContentPassesPredicateAssertion {
9 | private final String text;
10 |
11 | public ContentContainsStringAssertion(String text) {
12 | this.text = text;
13 | }
14 |
15 | @Override
16 | public HarEntryPredicate getHarEntryPredicate() {
17 | return content -> {
18 | Optional result = Optional.empty();
19 | if (!StringUtils.contains(content, text)) {
20 | result = Optional.of(
21 | String.format(
22 | "Expected to find string in content. Search string: '%s', content: '%s'",
23 | text, content
24 | ));
25 | }
26 | return result;
27 | };
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/content/ContentDoesNotContainStringAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.content;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import org.apache.commons.lang3.StringUtils;
5 |
6 | import java.util.Optional;
7 |
8 | public class ContentDoesNotContainStringAssertion extends ContentPassesPredicateAssertion {
9 | private final String text;
10 |
11 | public ContentDoesNotContainStringAssertion(String text) {
12 | this.text = text;
13 | }
14 |
15 | @Override
16 | public HarEntryPredicate getHarEntryPredicate() {
17 | return content -> {
18 | Optional result = Optional.empty();
19 | if (StringUtils.contains(content, text)) {
20 | result = Optional.of(
21 | String.format(
22 | "Expected to find no string with specified value in content. Search string: '%s', content: '%s'",
23 | text, content
24 | ));
25 | }
26 | return result;
27 | };
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/content/ContentMatchesAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.content;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 |
5 | import java.util.Optional;
6 | import java.util.regex.Pattern;
7 |
8 | public class ContentMatchesAssertion extends ContentPassesPredicateAssertion {
9 | private final Pattern contentPattern;
10 |
11 | public ContentMatchesAssertion(Pattern contentPattern) {
12 | this.contentPattern = contentPattern;
13 | }
14 |
15 | @Override
16 | public HarEntryPredicate getHarEntryPredicate() {
17 | return content -> {
18 | Optional result = Optional.empty();
19 | if (content == null || !contentPattern.matcher(content).matches()) {
20 | result = Optional.of(
21 | String.format("Expected content to match pattern. Pattern: '%s', content: '%s'",
22 | contentPattern.pattern(),
23 | content
24 | ));
25 | }
26 | return result;
27 | };
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/content/ContentPassesPredicateAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.content;
2 |
3 | import com.browserup.bup.assertion.field.FieldPassesPredicateAssertion;
4 | import com.browserup.bup.assertion.field.HarEntryAssertionFieldSupplier;
5 | import org.apache.commons.lang3.StringUtils;
6 |
7 | public abstract class ContentPassesPredicateAssertion extends FieldPassesPredicateAssertion {
8 |
9 | @Override
10 | public HarEntryAssertionFieldSupplier getFieldSupplier() {
11 | return entry -> StringUtils.defaultString(entry.getResponse().getContent().getText());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/content/ContentSizeLessThanOrEqualAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.content;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 |
5 | import java.util.Optional;
6 |
7 | public class ContentSizeLessThanOrEqualAssertion extends ContentSizePassesPredicateAssertion {
8 | private final Long size;
9 |
10 | public ContentSizeLessThanOrEqualAssertion(Long size) {
11 | this.size = size;
12 | }
13 |
14 | @Override
15 | public HarEntryPredicate getHarEntryPredicate() {
16 | return s -> {
17 | Optional result = Optional.empty();
18 | if (s > size) {
19 | result = Optional.of(String.format(
20 | "Expected content length not to exceed max value. Max value: %d, content length: %d", size, s));
21 | }
22 | return result;
23 | };
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/content/ContentSizePassesPredicateAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.content;
2 |
3 | import com.browserup.bup.assertion.field.FieldPassesPredicateAssertion;
4 | import com.browserup.bup.assertion.field.HarEntryAssertionFieldSupplier;
5 |
6 | public abstract class ContentSizePassesPredicateAssertion extends FieldPassesPredicateAssertion {
7 |
8 | @Override
9 | public HarEntryAssertionFieldSupplier getFieldSupplier() {
10 | return entry -> entry.getResponse().getContent().getSize();
11 | }
12 | }
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/header/FilteredHeadersContainStringAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.header;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import com.browserup.harreader.model.HarHeader;
5 |
6 | import java.util.List;
7 | import java.util.Optional;
8 |
9 | import static org.apache.commons.lang3.StringUtils.contains;
10 |
11 | public class FilteredHeadersContainStringAssertion extends HeadersPassPredicateAssertion {
12 | private final String name;
13 | private final String value;
14 |
15 | public FilteredHeadersContainStringAssertion(String name, String value) {
16 | this.name = name;
17 | this.value = value;
18 | }
19 |
20 | @Override
21 | public HarEntryPredicate> getHarEntryPredicate() {
22 | return harHeaders -> {
23 | Optional result = Optional.empty();
24 | boolean contains = harHeaders.stream()
25 | .filter(NONEMPTY_HEADER_FILTER)
26 | .filter(h -> h.getName().equals(name))
27 | .anyMatch(h -> contains(h.getValue(), value));
28 | if (!contains) {
29 | result = Optional.of(String.format(
30 | "Expected to find header with name: '%s' and value containing string: '%s'", name, value
31 | ));
32 | }
33 | return result;
34 | };
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/header/FilteredHeadersDoNotContainStringAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.header;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import com.browserup.harreader.model.HarHeader;
5 |
6 | import java.util.List;
7 | import java.util.Optional;
8 |
9 | import static org.apache.commons.lang3.StringUtils.contains;
10 |
11 | public class FilteredHeadersDoNotContainStringAssertion extends HeadersPassPredicateAssertion {
12 | private final String value;
13 | private final String name;
14 |
15 | public FilteredHeadersDoNotContainStringAssertion(String name, String value) {
16 | this.value = value;
17 | this.name = name;
18 | }
19 |
20 | @Override
21 | public HarEntryPredicate> getHarEntryPredicate() {
22 | return harHeaders -> {
23 | Optional found = harHeaders.stream()
24 | .filter(NONEMPTY_HEADER_FILTER)
25 | .filter(h -> h.getName().equals(name))
26 | .filter(h -> contains(h.getValue(), value))
27 | .findFirst();
28 |
29 | return found.map(h -> String.format(
30 | "Expected to find no header with name '%s' and value containing string '%s'", h.getName(), value));
31 | };
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/header/FilteredHeadersMatchAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.header;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import com.browserup.harreader.model.HarHeader;
5 |
6 | import java.util.List;
7 | import java.util.Optional;
8 | import java.util.regex.Pattern;
9 | import java.util.stream.Collectors;
10 |
11 | public class FilteredHeadersMatchAssertion extends HeadersPassPredicateAssertion {
12 | private final Pattern namePattern;
13 | private final Pattern valuePattern;
14 |
15 | public FilteredHeadersMatchAssertion(Pattern namePattern, Pattern valuePattern) {
16 | this.namePattern = namePattern;
17 | this.valuePattern = valuePattern;
18 | }
19 |
20 | @Override
21 | public HarEntryPredicate> getHarEntryPredicate() {
22 | return harHeaders -> {
23 | Optional result = Optional.empty();
24 |
25 | List notMatchingHeaders = harHeaders.stream()
26 | .filter(NONEMPTY_HEADER_FILTER)
27 | .filter(h -> namePattern.matcher(h.getName()).matches())
28 | .filter(h -> !valuePattern.matcher(h.getValue()).matches())
29 | .collect(Collectors.toList());
30 |
31 | if (notMatchingHeaders.size() > 0) {
32 | String notMatchingHeadersNames = notMatchingHeaders.stream()
33 | .map(HarHeader::getName)
34 | .collect(Collectors.joining(","));
35 |
36 | result = Optional.of(String.format(
37 | "Expected headers with names matching pattern: '%s' to have values matching pattern: '%s'. " +
38 | "Headers names not matching value pattern: '%s'",
39 | namePattern.pattern(), valuePattern.pattern(), notMatchingHeadersNames
40 | ));
41 | }
42 |
43 | return result;
44 | };
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/header/HeadersContainStringAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.header;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import com.browserup.harreader.model.HarHeader;
5 |
6 | import java.util.List;
7 | import java.util.Optional;
8 |
9 | import static org.apache.commons.lang3.StringUtils.contains;
10 |
11 | public class HeadersContainStringAssertion extends HeadersPassPredicateAssertion {
12 | private final String value;
13 |
14 | public HeadersContainStringAssertion(String value) {
15 | this.value = value;
16 | }
17 |
18 | @Override
19 | public HarEntryPredicate> getHarEntryPredicate() {
20 | return harHeaders -> {
21 | Optional result = Optional.empty();
22 | boolean contains = harHeaders.stream()
23 | .filter(NONEMPTY_HEADER_FILTER)
24 | .map(HarHeader::getValue)
25 | .anyMatch(hv -> contains(hv, value));
26 | if (!contains) {
27 | result = Optional.of(String.format(
28 | "Expected to find one or more headers containing string: '%s'", value
29 | ));
30 | }
31 | return result;
32 | };
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/header/HeadersDoNotContainStringAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.header;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import com.browserup.harreader.model.HarHeader;
5 |
6 | import java.util.List;
7 | import java.util.Optional;
8 |
9 | import static org.apache.commons.lang3.StringUtils.contains;
10 |
11 | public class HeadersDoNotContainStringAssertion extends HeadersPassPredicateAssertion {
12 | private final String value;
13 |
14 | public HeadersDoNotContainStringAssertion(String value) {
15 | this.value = value;
16 | }
17 |
18 | @Override
19 | public HarEntryPredicate> getHarEntryPredicate() {
20 | return harHeaders -> {
21 | Optional found = harHeaders.stream()
22 | .filter(NONEMPTY_HEADER_FILTER)
23 | .filter(hv -> contains(hv.getValue(), value))
24 | .findFirst();
25 |
26 | return found.map(h -> String.format(
27 | "Expected to find no headers containing string '%s'. Found header with name: '%s' containing string: '%s'",
28 | value, h.getName(), value
29 | ));
30 | };
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/header/HeadersMatchAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.header;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import com.browserup.harreader.model.HarHeader;
5 |
6 | import java.util.List;
7 | import java.util.Optional;
8 | import java.util.regex.Pattern;
9 | import java.util.stream.Collectors;
10 |
11 | public class HeadersMatchAssertion extends HeadersPassPredicateAssertion {
12 | private final Pattern valuePattern;
13 |
14 | public HeadersMatchAssertion(Pattern valuePattern) {
15 | this.valuePattern = valuePattern;
16 | }
17 |
18 | @Override
19 | public HarEntryPredicate> getHarEntryPredicate() {
20 | return harHeaders -> {
21 | Optional result = Optional.empty();
22 |
23 | List notMatchingHeaders = harHeaders.stream()
24 | .filter(NONEMPTY_HEADER_FILTER)
25 | .filter(h -> !valuePattern.matcher(h.getValue()).matches())
26 | .collect(Collectors.toList());
27 |
28 | if (notMatchingHeaders.size() > 0) {
29 | String notMatchingHeadersNames = notMatchingHeaders.stream()
30 | .map(HarHeader::getName)
31 | .collect(Collectors.joining(","));
32 |
33 | result = Optional.of(String.format(
34 | "Expected headers values to match pattern: '%s'. Headers names which values don't match value pattern: %s",
35 | valuePattern.pattern(), notMatchingHeadersNames
36 | ));
37 | }
38 |
39 | return result;
40 | };
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/header/HeadersPassPredicateAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.header;
2 |
3 | import com.browserup.bup.assertion.field.FieldPassesPredicateAssertion;
4 | import com.browserup.bup.assertion.field.HarEntryAssertionFieldSupplier;
5 | import com.browserup.harreader.model.HarHeader;
6 |
7 | import java.util.List;
8 | import java.util.function.Predicate;
9 |
10 | public abstract class HeadersPassPredicateAssertion extends FieldPassesPredicateAssertion> {
11 | protected static final Predicate NONEMPTY_HEADER_FILTER = h -> h.getName() != null && h.getValue() != null;
12 |
13 | @Override
14 | public HarEntryAssertionFieldSupplier> getFieldSupplier() {
15 | return entry -> entry.getResponse().getHeaders();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/status/StatusBelongsToClassAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.status;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 | import com.browserup.bup.util.HttpStatusClass;
5 |
6 | import java.util.Optional;
7 |
8 | public class StatusBelongsToClassAssertion extends StatusPassesPredicateAssertion {
9 | private final HttpStatusClass statusClass;
10 |
11 |
12 | public StatusBelongsToClassAssertion(HttpStatusClass statusClass) {
13 | this.statusClass = statusClass;
14 | }
15 |
16 | @Override
17 | public HarEntryPredicate getHarEntryPredicate() {
18 | return s -> {
19 | Optional result = Optional.empty();
20 |
21 | if (!statusClass.contains(s)) {
22 | result = Optional.of(String.format(
23 | "Expected response status to belong to class: %s, but was: %d (belongs to %s)",
24 | statusClass.name(), s, HttpStatusClass.valueOf(s)
25 | ));
26 | }
27 |
28 | return result;
29 | };
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/status/StatusEqualsAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.status;
2 |
3 | import com.browserup.bup.assertion.field.HarEntryPredicate;
4 |
5 | import java.util.Optional;
6 |
7 | public class StatusEqualsAssertion extends StatusPassesPredicateAssertion {
8 | private final Integer status;
9 |
10 | public StatusEqualsAssertion(Integer status) {
11 | this.status = status;
12 | }
13 |
14 | @Override
15 | public HarEntryPredicate getHarEntryPredicate() {
16 | return s -> {
17 | Optional result = Optional.empty();
18 |
19 | if (!s.equals(status)) {
20 | return Optional.of(String.format(
21 | "Expected response status to be: '%d', but was: '%d'", status, s));
22 | }
23 |
24 | return result;
25 | };
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/field/status/StatusPassesPredicateAssertion.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.field.status;
2 |
3 | import com.browserup.bup.assertion.field.FieldPassesPredicateAssertion;
4 | import com.browserup.bup.assertion.field.HarEntryAssertionFieldSupplier;
5 |
6 | public abstract class StatusPassesPredicateAssertion extends FieldPassesPredicateAssertion {
7 |
8 | @Override
9 | public HarEntryAssertionFieldSupplier getFieldSupplier() {
10 | return entry -> entry.getResponse().getStatus();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/model/AssertionEntryResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion.model;
6 |
7 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
8 | import com.fasterxml.jackson.annotation.JsonInclude;
9 | import org.apache.commons.lang3.StringUtils;
10 |
11 | @JsonInclude(JsonInclude.Include.NON_NULL)
12 | @JsonIgnoreProperties(ignoreUnknown = true)
13 | public class AssertionEntryResult {
14 | private String url;
15 | private String message;
16 | private Boolean failed;
17 |
18 | public AssertionEntryResult() {
19 | }
20 |
21 | private AssertionEntryResult(String url, String message, Boolean failed) {
22 | this.url = url;
23 | this.message = message;
24 | this.failed = failed;
25 | }
26 |
27 | public String getUrl() {
28 | return this.url;
29 | }
30 |
31 | public String getMessage() {
32 | return this.message;
33 | }
34 |
35 | public Boolean getFailed() {
36 | return this.failed;
37 | }
38 |
39 | public static class Builder {
40 | private String url;
41 | private String message;
42 | private Boolean failed;
43 |
44 | public Builder setUrl(String url) {
45 | this.url = url;
46 | return this;
47 | }
48 |
49 | public Builder setMessage(String message) {
50 | this.message = message;
51 | return this;
52 | }
53 |
54 | public Builder setFailed(Boolean failed) {
55 | this.failed = failed;
56 | return this;
57 | }
58 |
59 | public AssertionEntryResult create() {
60 | if (StringUtils.isEmpty(url) || failed == null) {
61 | throw new IllegalArgumentException("Not all required fields are set");
62 | }
63 | return new AssertionEntryResult(url, message, failed);
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/model/filter/AssertionFilterInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion.model.filter;
6 |
7 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
8 | import com.fasterxml.jackson.annotation.JsonInclude;
9 |
10 | @JsonInclude(JsonInclude.Include.NON_NULL)
11 | @JsonIgnoreProperties(ignoreUnknown = true)
12 | public class AssertionFilterInfo {
13 | public AssertionFilterInfo() {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/model/filter/AssertionUrlFilterInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion.model.filter;
6 |
7 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
8 | import com.fasterxml.jackson.annotation.JsonInclude;
9 |
10 | @JsonInclude(JsonInclude.Include.NON_NULL)
11 | @JsonIgnoreProperties(ignoreUnknown = true)
12 | public class AssertionUrlFilterInfo extends AssertionFilterInfo {
13 | private String urlPattern;
14 |
15 | public AssertionUrlFilterInfo() {
16 | }
17 |
18 | public AssertionUrlFilterInfo(String urlPattern) {
19 | this.urlPattern = urlPattern;
20 | }
21 |
22 | public String getUrlPattern() {
23 | return urlPattern;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/supplier/CurrentStepHarEntriesSupplier.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.supplier;
2 |
3 | import com.browserup.bup.assertion.model.filter.AssertionFilterInfo;
4 | import com.browserup.harreader.model.Har;
5 | import com.browserup.harreader.model.HarEntry;
6 |
7 | import java.util.List;
8 |
9 | public class CurrentStepHarEntriesSupplier extends HarEntriesSupplier {
10 | public CurrentStepHarEntriesSupplier(Har har) {
11 | super(har, new AssertionFilterInfo());
12 | }
13 |
14 | @Override
15 | public List get() {
16 | return getHar().getLog().getEntries();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/supplier/HarEntriesSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion.supplier;
6 |
7 | import com.browserup.bup.assertion.model.filter.AssertionFilterInfo;
8 | import com.browserup.harreader.model.Har;
9 | import com.browserup.harreader.model.HarEntry;
10 |
11 | import java.util.List;
12 | import java.util.function.Supplier;
13 |
14 | public abstract class HarEntriesSupplier implements Supplier> {
15 | private final Har har;
16 | private final AssertionFilterInfo filterInfo;
17 |
18 | public HarEntriesSupplier(Har har, AssertionFilterInfo filterInfo) {
19 | this.har = har;
20 | this.filterInfo = filterInfo;
21 | }
22 |
23 | public Har getHar() {
24 | return har;
25 | }
26 |
27 | public AssertionFilterInfo getFilterInfo() {
28 | return filterInfo;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/supplier/MostRecentHarEntrySupplier.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.assertion.supplier;
2 |
3 | import com.browserup.bup.assertion.model.filter.AssertionFilterInfo;
4 | import com.browserup.harreader.model.Har;
5 | import com.browserup.harreader.model.HarEntry;
6 |
7 | import java.util.Collections;
8 | import java.util.Comparator;
9 | import java.util.List;
10 | import java.util.regex.Pattern;
11 |
12 | public class MostRecentHarEntrySupplier extends HarEntriesSupplier {
13 |
14 | public MostRecentHarEntrySupplier(Har har) {
15 | super(har, new AssertionFilterInfo());
16 | }
17 |
18 | @Override
19 | public List get() {
20 | return getHar().getLog().getEntries().stream()
21 | .max(Comparator.comparing(HarEntry::getStartedDateTime))
22 | .map(Collections::singletonList)
23 | .orElse(Collections.emptyList());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/supplier/MostRecentUrlFilteredHarEntrySupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion.supplier;
6 |
7 | import com.browserup.harreader.model.Har;
8 | import com.browserup.harreader.model.HarEntry;
9 |
10 | import java.util.Collections;
11 | import java.util.List;
12 | import java.util.regex.Pattern;
13 |
14 | public class MostRecentUrlFilteredHarEntrySupplier extends UrlFilteredHarEntriesSupplier {
15 |
16 | public MostRecentUrlFilteredHarEntrySupplier(Har har, Pattern pattern) {
17 | super(har, pattern);
18 | }
19 |
20 | @Override
21 | public List get() {
22 | return getHar().getLog().findMostRecentEntry(getPattern()).
23 | map(Collections::singletonList).
24 | orElse(Collections.emptyList());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/assertion/supplier/UrlFilteredHarEntriesSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion.supplier;
6 |
7 | import com.browserup.bup.assertion.model.filter.AssertionUrlFilterInfo;
8 | import com.browserup.harreader.model.Har;
9 | import com.browserup.harreader.model.HarEntry;
10 |
11 | import java.util.List;
12 | import java.util.regex.Pattern;
13 |
14 | public class UrlFilteredHarEntriesSupplier extends HarEntriesSupplier {
15 | private final Pattern pattern;
16 |
17 | public UrlFilteredHarEntriesSupplier(Har har, Pattern pattern) {
18 | super(har, new AssertionUrlFilterInfo(pattern.pattern()));
19 | this.pattern = pattern;
20 | }
21 |
22 | @Override
23 | public List get() {
24 | return getHar().getLog().findEntries(pattern);
25 | }
26 |
27 | public Pattern getPattern() {
28 | return pattern;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/exception/DecompressionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.exception;
6 |
7 | /**
8 | * Indicates that an error occurred while decompressing content.
9 | */
10 | public class DecompressionException extends RuntimeException {
11 | private static final long serialVersionUID = 8666473793514307564L;
12 |
13 | public DecompressionException() {
14 | }
15 |
16 | public DecompressionException(String message) {
17 | super(message);
18 | }
19 |
20 | public DecompressionException(String message, Throwable cause) {
21 | super(message, cause);
22 | }
23 |
24 | public DecompressionException(Throwable cause) {
25 | super(cause);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/exception/UnsupportedCharsetException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.exception;
6 |
7 | /**
8 | * A checked exception wrapper for {@link java.nio.charset.UnsupportedCharsetException}. This exception is checked to prevent
9 | * situations where an unsupported character set in e.g. a Content-Type header causes the proxy to fail completely, rather
10 | * than fallback to some suitable default behavior, such as not parsing the text contents of a message.
11 | */
12 | public class UnsupportedCharsetException extends Exception {
13 | public UnsupportedCharsetException(java.nio.charset.UnsupportedCharsetException e) {
14 | super(e);
15 |
16 | if (e == null) {
17 | throw new IllegalArgumentException("com.browserup.bup.exception.UnsupportedCharsetException must be initialized with a non-null instance of java.nio.charset.UnsupportedCharsetException");
18 | }
19 | }
20 |
21 | /**
22 | * @return the underlying {@link java.nio.charset.UnsupportedCharsetException} that this exception wraps.
23 | */
24 | public java.nio.charset.UnsupportedCharsetException getUnsupportedCharsetExceptionCause() {
25 | return (java.nio.charset.UnsupportedCharsetException) this.getCause();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/filters/AddHeadersFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.filters;
6 |
7 | import io.netty.handler.codec.http.HttpObject;
8 | import io.netty.handler.codec.http.HttpRequest;
9 | import io.netty.handler.codec.http.HttpResponse;
10 | import org.littleshoot.proxy.HttpFiltersAdapter;
11 |
12 | import java.util.Collections;
13 | import java.util.Map;
14 |
15 | /**
16 | * Adds the headers specified in the constructor to this request. The filter does not make a defensive copy of the map, so there is no guarantee
17 | * that the map at the time of construction will contain the same values when the filter is actually invoked, if the map is modified concurrently.
18 | */
19 | public class AddHeadersFilter extends HttpFiltersAdapter {
20 | private final Map additionalHeaders;
21 |
22 | public AddHeadersFilter(HttpRequest originalRequest, Map additionalHeaders) {
23 | super(originalRequest);
24 |
25 | if (additionalHeaders != null) {
26 | this.additionalHeaders = additionalHeaders;
27 | } else {
28 | this.additionalHeaders = Collections.emptyMap();
29 | }
30 | }
31 |
32 | @Override
33 | public HttpResponse clientToProxyRequest(HttpObject httpObject) {
34 | if (httpObject instanceof HttpRequest) {
35 | HttpRequest httpRequest = (HttpRequest) httpObject;
36 |
37 | additionalHeaders.forEach((key, value) -> httpRequest.headers().add(key, value));
38 | }
39 |
40 | return null;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/filters/LatencyFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.filters;
6 |
7 | import io.netty.handler.codec.http.HttpObject;
8 | import io.netty.handler.codec.http.HttpRequest;
9 | import io.netty.handler.codec.http.HttpResponse;
10 | import org.littleshoot.proxy.HttpFiltersAdapter;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import java.util.concurrent.TimeUnit;
15 |
16 | /**
17 | * Adds latency to a response before sending it to the client. This filter always adds the specified latency, even if the latency
18 | * between the proxy and the remote server already exceeds this value.
19 | */
20 | public class LatencyFilter extends HttpFiltersAdapter {
21 | private static final Logger log = LoggerFactory.getLogger(HttpFiltersAdapter.class);
22 |
23 | private final int latencyMs;
24 |
25 | public LatencyFilter(HttpRequest originalRequest, int latencyMs) {
26 | super(originalRequest);
27 |
28 | this.latencyMs = latencyMs;
29 | }
30 |
31 | @Override
32 | public HttpObject proxyToClientResponse(HttpObject httpObject) {
33 | if (httpObject instanceof HttpResponse) {
34 | if (latencyMs > 0) {
35 | try {
36 | TimeUnit.MILLISECONDS.sleep(latencyMs);
37 | } catch (InterruptedException e) {
38 | Thread.currentThread().interrupt();
39 |
40 | log.warn("Interrupted while adding latency to response", e);
41 | }
42 | }
43 | }
44 |
45 | return super.proxyToClientResponse(httpObject);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/filters/ModifiedRequestAwareFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.filters;
6 |
7 | import io.netty.handler.codec.http.HttpRequest;
8 |
9 | /**
10 | * Indicates that a filter wishes to capture the final HttpRequest that is sent to the server, reflecting all
11 | * modifications from request filters. {@link BrowserUpHttpFilterChain#clientToProxyRequest(io.netty.handler.codec.http.HttpObject)}
12 | * will invoke the {@link #setModifiedHttpRequest(HttpRequest)} method after all filters have processed the initial
13 | * {@link HttpRequest} object.
14 | */
15 | public interface ModifiedRequestAwareFilter {
16 | /**
17 | * Notifies implementing classes of the modified HttpRequest that will be sent to the server, reflecting all
18 | * modifications from filters.
19 | *
20 | * @param modifiedHttpRequest the modified HttpRequest sent to the server
21 | */
22 | void setModifiedHttpRequest(HttpRequest modifiedHttpRequest);
23 | }
24 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/filters/RegisterRequestFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.filters;
6 |
7 | import io.netty.channel.ChannelHandlerContext;
8 | import io.netty.handler.codec.http.HttpObject;
9 | import io.netty.handler.codec.http.HttpRequest;
10 | import io.netty.handler.codec.http.HttpResponse;
11 | import com.browserup.bup.proxy.ActivityMonitor;
12 | import org.littleshoot.proxy.HttpFiltersAdapter;
13 |
14 | /**
15 | * Registers this request with the {@link com.browserup.bup.proxy.ActivityMonitor} when the HttpRequest is received from the client.
16 | */
17 | public class RegisterRequestFilter extends HttpFiltersAdapter {
18 | private final ActivityMonitor activityMonitor;
19 |
20 | public RegisterRequestFilter(HttpRequest originalRequest, ChannelHandlerContext ctx, ActivityMonitor activityMonitor) {
21 | super(originalRequest, ctx);
22 |
23 | this.activityMonitor = activityMonitor;
24 | }
25 |
26 | @Override
27 | public HttpResponse clientToProxyRequest(HttpObject httpObject) {
28 | if (httpObject instanceof HttpRequest) {
29 | activityMonitor.requestStarted();
30 | }
31 |
32 | return super.clientToProxyRequest(httpObject);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/filters/RequestFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.filters;
6 |
7 | import io.netty.handler.codec.http.HttpRequest;
8 | import io.netty.handler.codec.http.HttpResponse;
9 | import com.browserup.bup.util.HttpMessageContents;
10 | import com.browserup.bup.util.HttpMessageInfo;
11 |
12 | /**
13 | * A functional interface to simplify modification and manipulation of requests.
14 | */
15 | public interface RequestFilter {
16 | /**
17 | * Implement this method to filter an HTTP request. The HTTP method, URI, headers, etc. are available in the {@code request} parameter,
18 | * while the contents of the message are available in the {@code contents} parameter. The request can be modified directly, while the
19 | * contents may be modified using the {@link HttpMessageContents#setTextContents(String)} or {@link HttpMessageContents#setBinaryContents(byte[])}
20 | * methods. The request can be "short-circuited" by returning a non-null value.
21 | *
22 | * @param request The request object, including method, URI, headers, etc. Modifications to the request object will be reflected in the request sent to the server.
23 | * @param contents The request contents.
24 | * @param messageInfo Additional information relating to the HTTP message.
25 | * @return if the return value is non-null, the proxy will suppress the request and send the specified response to the client immediately
26 | */
27 | HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo);
28 | }
29 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/filters/ResponseFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.filters;
6 |
7 | import io.netty.handler.codec.http.HttpResponse;
8 | import com.browserup.bup.util.HttpMessageContents;
9 | import com.browserup.bup.util.HttpMessageInfo;
10 |
11 | /**
12 | * A functional interface to simplify modification and manipulation of responses.
13 | */
14 | public interface ResponseFilter {
15 | /**
16 | * Implement this method to filter an HTTP response. The URI, headers, status line, etc. are available in the {@code response} parameter,
17 | * while the contents of the message are available in the {@code contents} parameter. The response can be modified directly, while the
18 | * contents may be modified using the {@link HttpMessageContents#setTextContents(String)} or {@link HttpMessageContents#setBinaryContents(byte[])}
19 | * methods.
20 | *
21 | * @param response The response object, including URI, headers, status line, etc. Modifications to the response object will be reflected in the client response.
22 | * @param contents The response contents.
23 | * @param messageInfo Additional information relating to the HTTP message.
24 | */
25 | void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo);
26 | }
27 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/filters/UnregisterRequestFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.filters;
6 |
7 | import io.netty.channel.ChannelHandlerContext;
8 | import io.netty.handler.codec.http.HttpObject;
9 | import io.netty.handler.codec.http.HttpRequest;
10 | import io.netty.handler.codec.http.LastHttpContent;
11 | import com.browserup.bup.proxy.ActivityMonitor;
12 | import org.littleshoot.proxy.HttpFiltersAdapter;
13 |
14 | /**
15 | * Unregisters this request with the {@link com.browserup.bup.proxy.ActivityMonitor} when the LastHttpContent is sent to the client.
16 | */
17 | public class UnregisterRequestFilter extends HttpFiltersAdapter {
18 | private final ActivityMonitor activityMonitor;
19 |
20 | public UnregisterRequestFilter(HttpRequest originalRequest, ChannelHandlerContext ctx, ActivityMonitor activityMonitor) {
21 | super(originalRequest, ctx);
22 |
23 | this.activityMonitor = activityMonitor;
24 | }
25 |
26 | @Override
27 | public HttpObject proxyToClientResponse(HttpObject httpObject) {
28 | if (httpObject instanceof LastHttpContent) {
29 | activityMonitor.requestFinished();
30 | }
31 |
32 | return super.proxyToClientResponse(httpObject);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/NetworkUtils.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy;
2 |
3 | import com.browserup.bup.filters.HttpConnectHarCaptureFilter;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import java.io.IOException;
8 | import java.net.DatagramSocket;
9 | import java.net.ServerSocket;
10 |
11 | public class NetworkUtils {
12 | private static final Logger log = LoggerFactory
13 | .getLogger(HttpConnectHarCaptureFilter.class);
14 |
15 | public static boolean isPortAvailable(int port) {
16 | try (ServerSocket ss = new ServerSocket(port); DatagramSocket ds = new DatagramSocket(port)) {
17 | return true;
18 | } catch (IOException e) {
19 | return false;
20 | }
21 | }
22 |
23 | public static int getFreePort() {
24 | ServerSocket s = null;
25 | try {
26 | s = new ServerSocket(0);
27 | } catch (IOException e) {
28 | throw new RuntimeException("Couldn't find free port", e);
29 | } finally {
30 | if (s != null) {
31 | try {
32 | s.close();
33 | } catch (IOException e) {
34 | //
35 | }
36 | }
37 | }
38 | return s.getLocalPort();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/AdditionalHeadersAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class AdditionalHeadersAddOn extends AbstractAddon {
4 | private static final String ADDITIONAL_HEADERS_ADDON_FILE = "additional_headers.py";
5 |
6 | @Override
7 | public String[] getCommandParams() {
8 | return new String[]{
9 | "-s", getAddOnFilePath()
10 | };
11 | }
12 |
13 | @Override
14 | public String getAddOnFileName() {
15 | return ADDITIONAL_HEADERS_ADDON_FILE;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/AddonsManagerAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class AddonsManagerAddOn extends AbstractAddon {
4 | private static final String HAR_DUMP_ADD_ON_FILE_NAME = "bu_addons_manager.py";
5 | private final int port;
6 |
7 | public AddonsManagerAddOn(int port) {
8 | this.port = port;
9 | }
10 |
11 | @Override
12 | public String[] getCommandParams() {
13 | return new String[]{
14 | "-s", getAddOnFilePath(),
15 | "--set", "addons_management_port=" + port
16 | };
17 | }
18 |
19 | @Override
20 | public String getAddOnFileName() {
21 | return HAR_DUMP_ADD_ON_FILE_NAME;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/AllowListAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class AllowListAddOn extends AbstractAddon {
4 | private static final String ALLOW_LIST_ADDON_FILE = "allow_list.py";
5 |
6 | @Override
7 | public String[] getCommandParams() {
8 | return new String[]{
9 | "-s", getAddOnFilePath()
10 | };
11 | }
12 |
13 | @Override
14 | public String getAddOnFileName() {
15 | return ALLOW_LIST_ADDON_FILE;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/AuthBasicAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class AuthBasicAddOn extends AbstractAddon {
4 | private static final String ALLOW_LIST_ADDON_FILE = "auth_basic.py";
5 |
6 | @Override
7 | public String[] getCommandParams() {
8 | return new String[]{
9 | "-s", getAddOnFilePath()
10 | };
11 | }
12 |
13 | @Override
14 | public String getAddOnFileName() {
15 | return ALLOW_LIST_ADDON_FILE;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/BlockListAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class BlockListAddOn extends AbstractAddon {
4 | private static final String BLOCK_LIST_ADDON_FILE = "block_list.py";
5 |
6 | @Override
7 | public String[] getCommandParams() {
8 | return new String[]{
9 | "-s", getAddOnFilePath()
10 | };
11 | }
12 |
13 | @Override
14 | public String getAddOnFileName() {
15 | return BLOCK_LIST_ADDON_FILE;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/HarCaptureAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.Optional;
6 |
7 | public class HarCaptureAddOn extends AbstractAddon {
8 | private static final String HAR_DUMP_ADD_ON_FILE_NAME = "har_dump.py";
9 |
10 | private File harDumpFile = null;
11 |
12 | @Override
13 | public String[] getCommandParams() {
14 | return new String[]{
15 | "-s", getAddOnFilePath()
16 | };
17 | }
18 |
19 | @Override
20 | public String getAddOnFileName() {
21 | return HAR_DUMP_ADD_ON_FILE_NAME;
22 | }
23 |
24 | public Optional getHarDumpFile() {
25 |
26 | return Optional.ofNullable(harDumpFile);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/HttpConnectCaptureAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class HttpConnectCaptureAddOn extends AbstractAddon {
4 | private static final String HTTP_CONNECT_CAPTURE_ADDON_FILE = "http_connect_capture.py";
5 |
6 | @Override
7 | public String[] getCommandParams() {
8 | return new String[]{
9 | "-s", getAddOnFilePath()
10 | };
11 | }
12 |
13 | @Override
14 | public String getAddOnFileName() {
15 | return HTTP_CONNECT_CAPTURE_ADDON_FILE;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/InitFlowAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class InitFlowAddOn extends AbstractAddon {
4 | private static final String INIT_FLOW_ADDON_FILE = "init_flow.py";
5 |
6 | @Override
7 | public String[] getCommandParams() {
8 | return new String[]{
9 | "-s", getAddOnFilePath()
10 | };
11 | }
12 |
13 | @Override
14 | public String getAddOnFileName() {
15 | return INIT_FLOW_ADDON_FILE;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/LatencyAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class LatencyAddOn extends AbstractAddon {
4 | private static final String ADDITIONAL_HEADERS_ADDON_FILE = "latency.py";
5 |
6 | @Override
7 | public String[] getCommandParams() {
8 | return new String[]{
9 | "-s", getAddOnFilePath()
10 | };
11 | }
12 |
13 | @Override
14 | public String getAddOnFileName() {
15 | return ADDITIONAL_HEADERS_ADDON_FILE;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/ProxyManagerAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | import java.io.File;
4 | import java.util.Optional;
5 |
6 | public class ProxyManagerAddOn extends AbstractAddon {
7 | private static final String PROXY_MANAGER_ADDON_FILE = "proxy_manager.py";
8 |
9 | @Override
10 | public String[] getCommandParams() {
11 | return new String[]{
12 | "-s", getAddOnFilePath()
13 | };
14 | }
15 |
16 | @Override
17 | public String getAddOnFileName() {
18 | return PROXY_MANAGER_ADDON_FILE;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/addons/RewriteUrlAddOn.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.addons;
2 |
3 | public class RewriteUrlAddOn extends AbstractAddon {
4 | private static final String REWRITE_URL_ADDON_FILE = "rewrite_url.py";
5 |
6 | @Override
7 | public String[] getCommandParams() {
8 | return new String[]{
9 | "-s", getAddOnFilePath()
10 | };
11 | }
12 |
13 | @Override
14 | public String getAddOnFileName() {
15 | return REWRITE_URL_ADDON_FILE;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/management/LatencyManager.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.mitmproxy.management;
2 |
3 | import com.browserup.bup.mitmproxy.MitmProxyProcessManager;
4 | import org.apache.commons.lang3.tuple.Pair;
5 |
6 | import java.util.ArrayList;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | import static java.lang.String.valueOf;
10 | import static org.apache.commons.lang3.tuple.Pair.of;
11 |
12 | public class LatencyManager {
13 | private final AddonsManagerClient addonsManagerClient;
14 | private final MitmProxyProcessManager mitmProxyManager;
15 |
16 | private volatile int latencyMs;
17 |
18 | public LatencyManager(AddonsManagerClient addonsManagerClient, MitmProxyProcessManager mitmProxyManager) {
19 | this.addonsManagerClient = addonsManagerClient;
20 | this.mitmProxyManager = mitmProxyManager;
21 | }
22 |
23 | public void setLatency(long latency, TimeUnit timeUnit) {
24 | this.latencyMs = (int) TimeUnit.MILLISECONDS.convert(latency, timeUnit);
25 |
26 | if (!mitmProxyManager.isRunning()) return;
27 |
28 | addonsManagerClient.
29 | getRequestToAddonsManager(
30 | "latency",
31 | "set_latency",
32 | new ArrayList>() {{
33 | add(of("latency", valueOf(latencyMs)));
34 | }},
35 | Void.class);
36 | }
37 |
38 | public int getLatencyMs() {
39 | return latencyMs;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/proxy/RewriteRule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy;
6 |
7 | import java.util.regex.Pattern;
8 |
9 | /**
10 | * Container for a URL rewrite rule pattern and replacement string.
11 | */
12 | public class RewriteRule {
13 | private final Pattern pattern;
14 | private final String replace;
15 |
16 | public RewriteRule(String pattern, String replace) {
17 | this.pattern = Pattern.compile(pattern);
18 | this.replace = replace;
19 | }
20 |
21 | public Pattern getPattern() {
22 | return pattern;
23 | }
24 |
25 | public String getReplace() {
26 | return replace;
27 | }
28 |
29 | @Override
30 | public boolean equals(Object o) {
31 | if (this == o) return true;
32 | if (o == null || getClass() != o.getClass()) return false;
33 |
34 | RewriteRule that = (RewriteRule) o;
35 |
36 | if (!pattern.equals(that.pattern)) return false;
37 | if (!replace.equals(that.replace)) return false;
38 |
39 | return true;
40 | }
41 |
42 | @Override
43 | public int hashCode() {
44 | int result = pattern.hashCode();
45 | result = 31 * result + replace.hashCode();
46 | return result;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/proxy/auth/AuthType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.auth;
6 |
7 | /**
8 | * Authentication types support by BrowserUpProxy.
9 | */
10 | public enum AuthType {
11 | BASIC,
12 | // TODO: determine if we can actually do NTLM authentication
13 | NTLM
14 | }
15 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/proxy/dns/DelegatingHostResolver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.dns;
6 |
7 | import com.google.common.collect.Iterables;
8 |
9 | import java.net.InetAddress;
10 | import java.net.InetSocketAddress;
11 | import java.net.UnknownHostException;
12 | import java.util.Collection;
13 |
14 | /**
15 | * A LittleProxy HostResolver that delegates to the specified {@link com.browserup.bup.proxy.dns.AdvancedHostResolver} instance. This class
16 | * serves as a bridge between {@link AdvancedHostResolver} and {@link org.littleshoot.proxy.HostResolver}.
17 | */
18 | public class DelegatingHostResolver implements org.littleshoot.proxy.HostResolver {
19 | private volatile AdvancedHostResolver resolver;
20 |
21 | /**
22 | * Creates a new resolver that will delegate to the specified resolver.
23 | *
24 | * @param resolver HostResolver to delegate to
25 | */
26 | public DelegatingHostResolver(AdvancedHostResolver resolver) {
27 | this.resolver = resolver;
28 | }
29 |
30 | public AdvancedHostResolver getResolver() {
31 | return resolver;
32 | }
33 |
34 | public void setResolver(AdvancedHostResolver resolver) {
35 | this.resolver = resolver;
36 | }
37 |
38 | @Override
39 | public InetSocketAddress resolve(String host, int port) throws UnknownHostException {
40 | Collection resolvedAddresses = resolver.resolve(host);
41 | if (!resolvedAddresses.isEmpty()) {
42 | InetAddress resolvedAddress = Iterables.get(resolvedAddresses, 0);
43 | return new InetSocketAddress(resolvedAddress, port);
44 | }
45 |
46 | // no address found by the resolver
47 | throw new UnknownHostException(host);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/proxy/dns/HostResolver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.dns;
6 |
7 | import com.browserup.bup.BrowserUpProxy;
8 |
9 | import java.net.InetAddress;
10 | import java.util.Collection;
11 |
12 | /**
13 | * Defines the basic functionality that {@link BrowserUpProxy} implementations require when resolving hostnames.
14 | */
15 | public interface HostResolver {
16 | /**
17 | * Resolves a hostname to one or more IP addresses. The iterator over the returned Collection is recommended to reflect the ordering
18 | * returned by the underlying name lookup service. For example, if a DNS server returns three IP addresses, 1.1.1.1, 2.2.2.2, and
19 | * 3.3.3.3, corresponding to www.somehost.com, the returned Collection iterator is recommended to iterate in
20 | * the order [1.1.1.1, 2.2.2.2, 3.3.3.3].
21 | *
22 | * @param host host to resolve
23 | * @return resolved InetAddresses, or an empty collection if no addresses were found
24 | */
25 | Collection resolve(String host);
26 | }
27 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/bup/util/HttpStatusClass.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.util;
2 |
3 | public enum HttpStatusClass {
4 | INFORMATIONAL(100, 200, "Informational"),
5 | SUCCESS(200, 300, "Success"),
6 | REDIRECTION(300, 400, "Redirection"),
7 | CLIENT_ERROR(400, 500, "Client Error"),
8 | SERVER_ERROR(500, 600, "Server Error"),
9 | UNKNOWN(0, 0, "Unknown Status") {
10 | @Override
11 | public boolean contains(int code) {
12 | return code < 100 || code >= 600;
13 | }
14 | };
15 |
16 | public static HttpStatusClass valueOf(int code) {
17 | if (INFORMATIONAL.contains(code)) {
18 | return INFORMATIONAL;
19 | }
20 | if (SUCCESS.contains(code)) {
21 | return SUCCESS;
22 | }
23 | if (REDIRECTION.contains(code)) {
24 | return REDIRECTION;
25 | }
26 | if (CLIENT_ERROR.contains(code)) {
27 | return CLIENT_ERROR;
28 | }
29 | if (SERVER_ERROR.contains(code)) {
30 | return SERVER_ERROR;
31 | }
32 | return UNKNOWN;
33 | }
34 |
35 | private final int min;
36 | private final int max;
37 | private final String description;
38 |
39 | HttpStatusClass(int min, int max, String description) {
40 | this.min = min;
41 | this.max = max;
42 | this.description = description;
43 | }
44 |
45 | public boolean contains(int code) {
46 | return code >= min && code < max;
47 | }
48 |
49 | public int getMin() {
50 | return min;
51 | }
52 |
53 | public int getMax() {
54 | return max;
55 | }
56 |
57 | public String getDescription() {
58 | return description;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/HarReader.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.browserup.harreader.jackson.DefaultMapperFactory;
5 | import com.browserup.harreader.jackson.MapperFactory;
6 | import com.browserup.harreader.model.Har;
7 |
8 | import java.io.File;
9 | import java.io.IOException;
10 |
11 | public class HarReader {
12 |
13 | private final MapperFactory mapperFactory;
14 |
15 | public HarReader(MapperFactory mapperFactory) {
16 | if (mapperFactory == null) {
17 | throw new IllegalArgumentException("mapperFactory must not be null!");
18 | }
19 | this.mapperFactory = mapperFactory;
20 | }
21 |
22 | public HarReader() {
23 | this(new DefaultMapperFactory());
24 | }
25 |
26 | public Har readFromFile(File har) throws HarReaderException {
27 | return this.readFromFile(har, HarReaderMode.STRICT);
28 | }
29 |
30 | public Har readFromFile(File har, HarReaderMode mode) throws HarReaderException {
31 | ObjectMapper mapper = mapperFactory.instance(mode);
32 | try {
33 | return mapper.readValue(har, Har.class);
34 | } catch (IOException e) {
35 | throw new HarReaderException(e);
36 | }
37 | }
38 |
39 | public Har readFromString(String har) throws HarReaderException {
40 | return this.readFromString(har, HarReaderMode.STRICT);
41 | }
42 |
43 | public Har readFromString(String har, HarReaderMode mode) throws HarReaderException {
44 | ObjectMapper mapper = mapperFactory.instance(mode);
45 | try {
46 | return mapper.readValue(har, Har.class);
47 | } catch (IOException e) {
48 | throw new HarReaderException(e);
49 | }
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/HarReaderException.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader;
2 |
3 | public class HarReaderException extends Exception {
4 |
5 | public HarReaderException(Throwable cause) {
6 | super(cause);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/HarReaderMode.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader;
2 |
3 | public enum HarReaderMode {
4 |
5 | /**
6 | * Using strict mode enforces some rules.
7 | * When trying to open an invalid HAR file an exception will be thrown.
8 | */
9 | STRICT,
10 |
11 | /**
12 | * Using lax mode you are able to read even invalid HAR files.
13 | * Currently lax mode allows:
14 | *
15 | * - invalid date formats
16 | *
17 | */
18 | LAX;
19 | }
20 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/LICENSE.MD:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Sebastian Stöhr, 2019 BrowserUp
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/README.md:
--------------------------------------------------------------------------------
1 | The har reader is included via MIT license.
2 |
3 | Original source: https://github.com/sdstoehr/har-reader
4 |
5 | Additions by BrowserUp are governed by the Apache License 2.0.
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/filter/HarEntriesFilter.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.filter;
2 |
3 | import com.browserup.harreader.model.HarEntry;
4 | import java.util.function.Predicate;
5 |
6 | public interface HarEntriesFilter extends Predicate {
7 |
8 | @Override
9 | boolean test(HarEntry entry);
10 | }
11 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/filter/HarEntriesUrlPatternFilter.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.filter;
2 |
3 | import com.browserup.harreader.model.HarEntry;
4 | import java.util.regex.Pattern;
5 |
6 | public class HarEntriesUrlPatternFilter implements HarEntriesFilter {
7 |
8 | private final Pattern pattern;
9 |
10 | public HarEntriesUrlPatternFilter(Pattern pattern) {
11 | this.pattern = pattern;
12 | }
13 |
14 | @Override
15 | public boolean test(HarEntry entry) {
16 | return pattern.matcher(entry.getRequest().getUrl()).matches();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/jackson/DefaultMapperFactory.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.jackson;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.fasterxml.jackson.databind.module.SimpleModule;
5 | import com.browserup.harreader.HarReaderMode;
6 |
7 | import java.util.Date;
8 |
9 | public class DefaultMapperFactory implements MapperFactory {
10 |
11 | public ObjectMapper instance(HarReaderMode mode) {
12 | ObjectMapper mapper = new ObjectMapper();
13 | SimpleModule module = new SimpleModule();
14 | if (mode == HarReaderMode.LAX) {
15 | module.addDeserializer(Date.class, new ExceptionIgnoringDateDeserializer());
16 | module.addDeserializer(Integer.class, new ExceptionIgnoringIntegerDeserializer());
17 | }
18 | mapper.registerModule(module);
19 | return mapper;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/jackson/ExceptionIgnoringDateDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.jackson;
2 |
3 | import java.io.IOException;
4 | import java.util.Date;
5 |
6 | import com.fasterxml.jackson.core.JsonParser;
7 | import com.fasterxml.jackson.databind.DeserializationContext;
8 | import com.fasterxml.jackson.databind.JsonDeserializer;
9 | import com.fasterxml.jackson.databind.deser.std.DateDeserializers;
10 |
11 | public class ExceptionIgnoringDateDeserializer extends JsonDeserializer {
12 |
13 | @Override
14 | public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws java.io.IOException {
15 | try {
16 | DateDeserializers.DateDeserializer dateDeserializer = new DateDeserializers.DateDeserializer();
17 | return dateDeserializer.deserialize(jp, ctxt);
18 | } catch (IOException e) {
19 | //ignore
20 | }
21 | return new Date(0L);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/jackson/ExceptionIgnoringIntegerDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.jackson;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.databind.DeserializationContext;
5 | import com.fasterxml.jackson.databind.JsonDeserializer;
6 | import com.fasterxml.jackson.databind.deser.std.NumberDeserializers;
7 |
8 | import java.io.IOException;
9 |
10 | public class ExceptionIgnoringIntegerDeserializer extends JsonDeserializer {
11 | @Override
12 | public Integer deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
13 | try {
14 | NumberDeserializers.IntegerDeserializer integerDeserializer = new NumberDeserializers.IntegerDeserializer(Integer.class, null);
15 | return integerDeserializer.deserialize(jp, ctxt);
16 | } catch (IOException e) {
17 | //ignore
18 | }
19 | return null;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/jackson/MapperFactory.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.jackson;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.browserup.harreader.HarReaderMode;
5 |
6 | public interface MapperFactory {
7 |
8 | ObjectMapper instance(HarReaderMode mode);
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/model/Har.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 |
7 | import java.io.File;
8 | import java.io.IOException;
9 | import java.io.OutputStream;
10 | import java.io.Writer;
11 | import java.util.Objects;
12 |
13 | /**
14 | * Main HTTP Archive Class.
15 | * @see speicification
16 | */
17 | @JsonInclude(JsonInclude.Include.NON_NULL)
18 | @JsonIgnoreProperties(ignoreUnknown = true)
19 | public class Har {
20 |
21 | private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
22 |
23 | private HarLog log;
24 |
25 | /**
26 | * @return HAR log.
27 | */
28 | public HarLog getLog() {
29 | if (log == null) {
30 | log = new HarLog();
31 | }
32 | return log;
33 | }
34 |
35 | public void setLog(HarLog log) {
36 | this.log = log;
37 | }
38 |
39 | @Override
40 | public boolean equals(Object o) {
41 | if (this == o) return true;
42 | if (o == null || getClass() != o.getClass()) return false;
43 | Har har = (Har) o;
44 | return Objects.equals(log, har.log);
45 | }
46 |
47 | @Override
48 | public int hashCode() {
49 | return Objects.hash(log);
50 | }
51 |
52 | public void writeTo(Writer writer) throws IOException {
53 | OBJECT_MAPPER.writeValue(writer, this);
54 | }
55 |
56 | public void writeTo(OutputStream os) throws IOException {
57 | OBJECT_MAPPER.writeValue(os, this);
58 | }
59 |
60 | public void writeTo(File file) throws IOException {
61 | OBJECT_MAPPER.writeValue(file, this);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/model/HarHeader.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 |
6 | import java.util.Objects;
7 |
8 | /**
9 | * Information about a header used in request and/or response.
10 | * @see specification
11 | */
12 | @JsonInclude(JsonInclude.Include.NON_NULL)
13 | @JsonIgnoreProperties(ignoreUnknown = true)
14 | public class HarHeader {
15 |
16 | private String name;
17 | private String value;
18 | private String comment;
19 |
20 | /**
21 | * @return Header name, null if not present.
22 | */
23 | public String getName() {
24 | return name;
25 | }
26 |
27 | public void setName(String name) {
28 | this.name = name;
29 | }
30 |
31 | /**
32 | * @return Header value, null if not present.
33 | */
34 | public String getValue() {
35 | return value;
36 | }
37 |
38 | public void setValue(String value) {
39 | this.value = value;
40 | }
41 |
42 | /**
43 | * @return Comment provided by the user or application, null if not present.
44 | */
45 | public String getComment() {
46 | return comment;
47 | }
48 |
49 | public void setComment(String comment) {
50 | this.comment = comment;
51 | }
52 |
53 | @Override
54 | public boolean equals(Object o) {
55 | if (this == o) return true;
56 | if (o == null || getClass() != o.getClass()) return false;
57 | HarHeader harHeader = (HarHeader) o;
58 | return Objects.equals(name, harHeader.name) &&
59 | Objects.equals(value, harHeader.value) &&
60 | Objects.equals(comment, harHeader.comment);
61 | }
62 |
63 | @Override
64 | public int hashCode() {
65 | return Objects.hash(name, value, comment);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/model/HarQueryParam.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 | import com.fasterxml.jackson.annotation.JsonInclude;
5 |
6 | import java.util.Objects;
7 |
8 | /**
9 | * Information about query params.
10 | * @see specification
11 | */
12 | @JsonInclude(JsonInclude.Include.NON_NULL)
13 | @JsonIgnoreProperties(ignoreUnknown = true)
14 | public class HarQueryParam {
15 |
16 | private String name;
17 | private String value;
18 | private String comment;
19 |
20 | /**
21 | * @return Name of param, null if not present.
22 | */
23 | public String getName() {
24 | return name;
25 | }
26 |
27 | public void setName(String name) {
28 | this.name = name;
29 | }
30 |
31 | /**
32 | * @return Value of param, null if not present.
33 | */
34 | public String getValue() {
35 | return value;
36 | }
37 |
38 | public void setValue(String value) {
39 | this.value = value;
40 | }
41 |
42 | /**
43 | * @return Comment provided by the user or application, null if not present.
44 | */
45 | public String getComment() {
46 | return comment;
47 | }
48 |
49 | public void setComment(String comment) {
50 | this.comment = comment;
51 | }
52 |
53 | @Override
54 | public boolean equals(Object o) {
55 | if (this == o) return true;
56 | if (o == null || getClass() != o.getClass()) return false;
57 | HarQueryParam that = (HarQueryParam) o;
58 | return Objects.equals(name, that.name) &&
59 | Objects.equals(value, that.value) &&
60 | Objects.equals(comment, that.comment);
61 | }
62 |
63 | @Override
64 | public int hashCode() {
65 | return Objects.hash(name, value, comment);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/java/com/browserup/harreader/model/HttpMethod.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | public enum HttpMethod {
4 | GET, POST, PUT, HEAD, PROPFIND, OPTIONS, REPORT, DELETE, CONNECT, TRACE, CCM_POST, PATCH;
5 | }
6 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/com/browserup/bup/version:
--------------------------------------------------------------------------------
1 | ${project.version}
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/mitmproxy/additional_headers.py:
--------------------------------------------------------------------------------
1 | import json
2 | import base64
3 | import typing
4 | import tempfile
5 |
6 | import re
7 |
8 | from datetime import datetime
9 | from datetime import timezone
10 |
11 | import falcon
12 |
13 | from mitmproxy import ctx
14 |
15 | from mitmproxy import connections
16 | from mitmproxy import version
17 | from mitmproxy.utils import strutils
18 | from mitmproxy.net.http import cookies
19 | from mitmproxy import http
20 |
21 | class AddHeadersResource:
22 |
23 | def addon_path(self):
24 | return "additional_headers"
25 |
26 | def __init__(self, additional_headers_addon):
27 | self.additional_headers_addon = additional_headers_addon
28 |
29 | def on_get(self, req, resp, method_name):
30 | getattr(self, "on_" + method_name)(req, resp)
31 |
32 | def on_add_headers(self, req, resp):
33 | for k, v in req.params.items():
34 | self.additional_headers_addon.headers[k] = v
35 |
36 |
37 | def on_add_header(self, req, resp):
38 | for k, v in req.params.items():
39 | self.additional_headers_addon.headers[k] = v
40 |
41 | def on_remove_header(self, req, resp):
42 | self.additional_headers_addon.headers.pop(req.get_param('name'))
43 |
44 | def on_remove_all_headers(self, req, resp):
45 | self.additional_headers_addon.headers = {}
46 |
47 | class AddHeadersAddOn:
48 |
49 | def __init__(self):
50 | self.num = 0
51 | self.headers = {}
52 |
53 | def get_resource(self):
54 | return AddHeadersResource(self)
55 |
56 | def request(self, flow):
57 | for k, v in self.headers.items():
58 | flow.request.headers[k] = v
59 |
60 |
61 | addons = [
62 | AddHeadersAddOn()
63 | ]
64 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/mitmproxy/auth_basic.py:
--------------------------------------------------------------------------------
1 | import json
2 | import base64
3 | import typing
4 | import tempfile
5 |
6 | import re
7 |
8 | from datetime import datetime
9 | from datetime import timezone
10 |
11 | import falcon
12 |
13 | from mitmproxy import ctx
14 |
15 | from mitmproxy import connections
16 | from mitmproxy import version
17 | from mitmproxy.utils import strutils
18 | from mitmproxy.net.http import cookies
19 | from mitmproxy import http
20 |
21 | class AuthBasicResource:
22 |
23 | def addon_path(self):
24 | return "auth_basic"
25 |
26 | def __init__(self, auth_basic_addon):
27 | self.auth_basic_addon = auth_basic_addon
28 |
29 | def on_get(self, req, resp, method_name):
30 | getattr(self, "on_" + method_name)(req, resp)
31 |
32 | def on_auth_authorization(self, req, resp):
33 | credentials = req.get_param('base64EncodedCredentials')
34 | domain = req.get_param('domain')
35 | self.auth_basic_addon.credentials_map[domain] = credentials
36 |
37 | def on_stop_authorization(self, req, resp):
38 | domain = req.get_param('domain')
39 | self.auth_basic_addon.credentials_map.pop(domain)
40 |
41 | class AuthBasicAddOn:
42 |
43 | def __init__(self):
44 | self.num = 0
45 | self.credentials_map = {}
46 |
47 | def get_resource(self):
48 | return AuthBasicResource(self)
49 |
50 | def request(self, flow):
51 | if flow.request.host in self.credentials_map:
52 | flow.request.headers['Authorization'] = 'Basic ' + self.credentials_map[flow.request.host]
53 |
54 |
55 | addons = [
56 | AuthBasicAddOn()
57 | ]
58 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/mitmproxy/init_flow.py:
--------------------------------------------------------------------------------
1 | import json
2 | import base64
3 | import typing
4 | import tempfile
5 |
6 | from time import sleep
7 |
8 | import re
9 |
10 | from datetime import datetime
11 | from datetime import timezone
12 |
13 | import falcon
14 |
15 | from mitmproxy import ctx
16 |
17 | from mitmproxy import connections
18 | from mitmproxy import version
19 | from mitmproxy.utils import strutils
20 | from mitmproxy.net.http import cookies
21 | from mitmproxy import http
22 |
23 | class InitFlowResource:
24 |
25 | def addon_path(self):
26 | return "init_flow"
27 |
28 | def __init__(self, init_flow_addon):
29 | self.init_flow_addon = init_flow_addon
30 | for a in ctx.master.addons.get("scriptloader").addons:
31 | if 'har_dump.py' in a.fullpath:
32 | self.init_flow_addon.har_dump_addon = a.addons[0].addons[0]
33 |
34 | def on_get(self, req, resp, method_name):
35 | getattr(self, "on_" + method_name)(req, resp)
36 |
37 |
38 | class InitFlowAddOn:
39 |
40 | def __init__(self):
41 | self.num = 0
42 | self.har_dump_addon = None
43 |
44 | def get_resource(self):
45 | return InitFlowResource(self)
46 |
47 | # def http_connect(self, flow):
48 | # if not hasattr(flow.request, 'har_entry'):
49 | # self.init_har_entry(flow)
50 |
51 | def request(self, flow):
52 | if not hasattr(flow.request, 'har_entry'):
53 | self.init_har_entry(flow)
54 |
55 | def init_har_entry(self, flow):
56 | ctx.log.debug("Initializing har entry for flow request: {}".format(str(flow.request)))
57 | setattr(flow.request, 'har_entry', self.har_dump_addon.generate_har_entry(flow.request.url))
58 | self.har_dump_addon.append_har_entry(flow.request.har_entry)
59 |
60 | addons = [
61 | InitFlowAddOn()
62 | ]
63 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/mitmproxy/latency.py:
--------------------------------------------------------------------------------
1 | import json
2 | import base64
3 | import typing
4 | import tempfile
5 |
6 | from time import sleep
7 |
8 | import re
9 |
10 | from datetime import datetime
11 | from datetime import timezone
12 |
13 | import falcon
14 |
15 | from mitmproxy import ctx
16 |
17 | from mitmproxy import connections
18 | from mitmproxy import version
19 | from mitmproxy.utils import strutils
20 | from mitmproxy.net.http import cookies
21 | from mitmproxy import http
22 |
23 | class LatencyResource:
24 |
25 | def addon_path(self):
26 | return "latency"
27 |
28 | def __init__(self, latency_addon):
29 | self.latency_addon = latency_addon
30 |
31 | def on_get(self, req, resp, method_name):
32 | getattr(self, "on_" + method_name)(req, resp)
33 |
34 | def on_set_latency(self, req, resp):
35 | self.latency_addon.latency_ms = int(req.get_param('latency'))
36 |
37 |
38 | class LatencyAddOn:
39 |
40 | def __init__(self):
41 | self.num = 0
42 | self.latency_ms = 0
43 |
44 | def get_resource(self):
45 | return LatencyResource(self)
46 |
47 | def response(self, flow):
48 | if self.latency_ms != 0:
49 | sleep(self.latency_ms / 1000)
50 |
51 | addons = [
52 | LatencyAddOn()
53 | ]
54 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/sslSupport/ca-certificate-ec.cer:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIB8jCCAZigAwIBAgIUUridrS1mqPKh8aA7igVOQRUc8P8wCgYIKoZIzj0EAwQw
3 | RjEZMBcGA1UEAwwQTGl0dGxlUHJveHkgTUlUTTEpMCcGA1UECgwgTGl0dGxlUHJv
4 | eHkgRUNDIEltcGVyc29uYXRpb24gQ0EwHhcNMTUwMTAyMDAwMDAwWhcNMjUwMTAy
5 | MDAwMDAwWjBGMRkwFwYDVQQDDBBMaXR0bGVQcm94eSBNSVRNMSkwJwYDVQQKDCBM
6 | aXR0bGVQcm94eSBFQ0MgSW1wZXJzb25hdGlvbiBDQTBZMBMGByqGSM49AgEGCCqG
7 | SM49AwEHA0IABB9DdlM/uhkMWTYFo9ETzPrMWBlfhCD0z3J2F1aH9a3OPiPYBio6
8 | fzTVSZO2rU9ItfcRRpCGeMzY+pilfUNkPXyjZDBiMB0GA1UdDgQWBBQ0TT/oOVF2
9 | mT10+X9W3NDESql7ZzAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBtjAjBgNV
10 | HSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAwCgYIKoZIzj0EAwQDSAAw
11 | RQIhAOb/s6H8v1XeEPGEmMdVEhRnhJgTYAktQKQLZid8QBzsAiA7zc1mFLRAKs98
12 | 5d9+qGFsv7Fy0yTNO3vFyL7DL2mykg==
13 | -----END CERTIFICATE-----
14 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/sslSupport/ca-certificate-rsa.cer:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDfzCCAmegAwIBAgIVAMFQpicWi3EjPX08LgeuA8nAOEfIMA0GCSqGSIb3DQEB
3 | DQUAMEYxGTAXBgNVBAMMEExpdHRsZVByb3h5IE1JVE0xKTAnBgNVBAoMIExpdHRs
4 | ZVByb3h5IFJTQSBJbXBlcnNvbmF0aW9uIENBMB4XDTE1MDEwMjAwMDAwMFoXDTI1
5 | MDEwMjAwMDAwMFowRjEZMBcGA1UEAwwQTGl0dGxlUHJveHkgTUlUTTEpMCcGA1UE
6 | CgwgTGl0dGxlUHJveHkgUlNBIEltcGVyc29uYXRpb24gQ0EwggEiMA0GCSqGSIb3
7 | DQEBAQUAA4IBDwAwggEKAoIBAQC141M+lc046DJaNqIARozRPROGt/s5Ng1UOE84
8 | tKhd+M/REaOeNovW+42uMa4ZifJAK7Csc0dx54Iq35LXy0tMw6ly/MB0pFi+aFCJ
9 | VzXZhbAWIsUmjU8t6z2Y0sjKVX/g3HkdXqaX94jlDtsTjeQXvFhiJNRlX/Locc/f
10 | /oNYZWhg7IPGyQglRY9Dco9kZMSbh5y0yfM8002PNPbNOP4dMX4yYqovT90XbvQ2
11 | rCBbiS6Cys7j44vwOcra9srlb3YQiOCOsYCf7eIhT1GH8tqQ84CHblufqxcGIvXv
12 | V1ex6bDFy63tiPySsOwuVnZglkQ0MDl1GMKVySdPw/qQM5v9AgMBAAGjZDBiMB0G
13 | A1UdDgQWBBRFMQtpkCyZIK9NxaEJDvbfaV1QOzAPBgNVHRMBAf8EBTADAQH/MAsG
14 | A1UdDwQEAwIBtjAjBgNVHSUEHDAaBggrBgEFBQcDAQYIKwYBBQUHAwIGBFUdJQAw
15 | DQYJKoZIhvcNAQENBQADggEBAJuYv1NuxPHom579iAjs19YrFGewHpv4aZC7aWTt
16 | oC1y9418w7QzVOAz2VzluURazUdg/HS9s8abJ8IS0iD0xLz0B1cvJ6F2BezjAwyG
17 | 2LxZggmBdLqwjdRkX0Mx3a2HqUpEqaNeKyE8VmzwPuDHN1AqbFcuOPHN7fm7kAtL
18 | 4bxFmjgSt7PjEdYwysdjkLC6m+236tuFydpVkXMjuBthsk/hZ1Y/3tbCj/B9a9//
19 | 5O+HhYEy+Oa64iFvxfgDfKKUQR3VmwThj1Dh2iJw/kbPJEuQ/PtfcnQhOqyliwg6
20 | Edxd1kaO4HU8Am6TwpmpPFWHRqhM2xj2PAGyfFtN1WfBEQ4=
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/sslSupport/ca-keystore-ec.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/browserup/browserup-proxy/0f28ec6e8f1423e1fdb014fded72e9278bdd083f/browserup-proxy-core/src/main/resources/sslSupport/ca-keystore-ec.p12
--------------------------------------------------------------------------------
/browserup-proxy-core/src/main/resources/sslSupport/ca-keystore-rsa.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/browserup/browserup-proxy/0f28ec6e8f1423e1fdb014fded72e9278bdd083f/browserup-proxy-core/src/main/resources/sslSupport/ca-keystore-rsa.p12
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/assertion/ResponseTimeLessThanOrEqualAssertionTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.assertion
6 |
7 | import com.browserup.harreader.model.HarEntry
8 | import org.junit.Assert;
9 | import org.junit.Test;
10 |
11 | class ResponseTimeLessThanOrEqualAssertionTest {
12 |
13 | @Test
14 | void testAssertionFailsIfTimeExceeds() {
15 | def expectedTime = 500
16 | def assertion = new ResponseTimeLessThanOrEqualAssertion(expectedTime)
17 | def entry = new HarEntry()
18 | def time = 1000
19 | entry.setTime(time)
20 |
21 | def result = assertion.assertion(entry)
22 |
23 | Assert.assertTrue("Expected assertion to return error", result.present)
24 | }
25 |
26 | @Test
27 | void testAssertionDoesNotFailIfTimeDoesNotExceed() {
28 | def expectedTime = 2000
29 | def assertion = new ResponseTimeLessThanOrEqualAssertion(expectedTime)
30 | def entry = new HarEntry()
31 | def time = 1000
32 | entry.setTime(time)
33 |
34 | def result = assertion.assertion(entry)
35 |
36 | Assert.assertFalse("Expected assertion not to return error", result.present)
37 | }
38 | }
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/mitmproxy/LatencyTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitmproxy
6 |
7 |
8 | import com.browserup.bup.MitmProxyServer
9 | import com.browserup.bup.proxy.test.util.MockServerTest
10 | import com.browserup.bup.proxy.test.util.NewProxyServerTestUtil
11 | import org.apache.http.HttpResponse
12 | import org.apache.http.client.methods.HttpGet
13 | import org.junit.After
14 | import org.junit.Test
15 |
16 | import java.util.concurrent.TimeUnit
17 |
18 | import static com.github.tomakehurst.wiremock.client.WireMock.*
19 | import static org.junit.Assert.assertEquals
20 | import static org.junit.Assert.assertTrue
21 |
22 | class LatencyTest extends MockServerTest {
23 | private MitmProxyServer proxy
24 |
25 | @After
26 | void tearDown() {
27 | if (proxy?.started) {
28 | proxy.abort()
29 | }
30 | }
31 |
32 | @Test
33 | void testLatency() {
34 | String url = "/latency"
35 | stubFor(get(urlEqualTo(url)).willReturn(ok()))
36 |
37 | proxy = new MitmProxyServer()
38 | proxy.setLatency(2, TimeUnit.SECONDS)
39 | proxy.start()
40 |
41 | NewProxyServerTestUtil.getNewHttpClient(proxy.getPort()).withCloseable {
42 | long start = System.nanoTime()
43 | HttpResponse response = it.execute(new HttpGet("http://127.0.0.1:" + mockServerPort + "/latency"))
44 | long stop = System.nanoTime()
45 |
46 | assertEquals("Expected to receive an HTTP 200 from the upstream server", 200, response.getStatusLine().getStatusCode())
47 | assertTrue("Expected latency to be at least 2 seconds. Total time was: " + TimeUnit.MILLISECONDS.convert(stop - start, TimeUnit.NANOSECONDS) + "ms",
48 | TimeUnit.SECONDS.convert(stop - start, TimeUnit.NANOSECONDS) >= 2)
49 | }
50 |
51 | verify(1, getRequestedFor(urlEqualTo(url)))
52 | }
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/proxy/assertion/field/content/ContentBaseTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.assertion.field.content
2 |
3 | import com.browserup.bup.proxy.CaptureType
4 | import com.browserup.bup.proxy.assertion.BaseAssertionsTest
5 | import com.github.tomakehurst.wiremock.matching.EqualToPattern
6 | import org.apache.http.HttpHeaders
7 | import org.apache.http.HttpStatus
8 | import org.eclipse.jetty.http.HttpHeader
9 | import org.junit.Before
10 | import java.util.regex.Pattern
11 |
12 | import static com.github.tomakehurst.wiremock.client.WireMock.get
13 | import static com.github.tomakehurst.wiremock.client.WireMock.ok
14 | import static com.github.tomakehurst.wiremock.client.WireMock.stubFor
15 | import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo
16 | class ContentBaseTest extends BaseAssertionsTest {
17 | protected static final String BODY_PART = 'body part'
18 | protected static final String BODY_CONTAINING_BODY_PART = "body example with ${BODY_PART} in the middle".toString()
19 | protected static final String BODY_NOT_CONTAINING_BODY_PART = 'body example'
20 | protected static final Pattern BODY_PATTERN_TO_MATCH_BODY_PART = Pattern.compile(".*${BODY_PART}.*")
21 | protected static final String BODY_PATTERN_NOT_TO_MATCH_BODY_PART = Pattern.compile(".*NOT-TO-MATCH.*")
22 |
23 | @Before
24 | void setUp() {
25 | proxy.enableHarCaptureTypes(CaptureType.RESPONSE_CONTENT, CaptureType.REQUEST_BINARY_CONTENT, CaptureType.REQUEST_CONTENT)
26 | }
27 |
28 | protected mockResponse(String path, String body) {
29 | stubFor(get(urlEqualTo("/" + path))
30 | .willReturn(ok().withHeader(HttpHeaders.CONTENT_TYPE, "text/plain").withBody(body)))
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/proxy/assertion/field/content/ContentSizeLessThanOrEqualTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.assertion.field.content
2 |
3 | import org.apache.commons.lang3.StringUtils
4 | import org.junit.Test
5 |
6 | import java.util.regex.Pattern
7 |
8 | import static org.junit.Assert.assertFalse
9 | import static org.junit.Assert.assertTrue
10 |
11 | class ContentSizeLessThanOrEqualTest extends ContentBaseTest {
12 |
13 | @Test
14 | void contentSizeWithinAssertionPasses() {
15 | def body = StringUtils.repeat('a', 100)
16 | def bodySize = body.bytes.size()
17 |
18 | mockResponse(URL_PATH, body)
19 |
20 | requestToMockedServer(URL_PATH, body)
21 |
22 | def result = proxy.assertMostRecentResponseContentLengthLessThanOrEqual(Pattern.compile(".*${URL_PATH}.*"), bodySize)
23 |
24 | assertTrue("Expected assertion to pass", result.passed)
25 | assertFalse("Expected assertion to pass", result.failed)
26 | }
27 |
28 | @Test
29 | void contentSizeWithinAssertionFails() {
30 | def body = StringUtils.repeat('a', 100)
31 | def bodySize = body.bytes.size()
32 |
33 | mockResponse(URL_PATH, body)
34 |
35 | requestToMockedServer(URL_PATH, body)
36 |
37 | def result = proxy.assertMostRecentResponseContentLengthLessThanOrEqual(Pattern.compile(".*${URL_PATH}.*"), bodySize - 1)
38 |
39 | assertFalse("Expected assertion to fail", result.passed)
40 | assertTrue("Expected assertion to fail", result.failed)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/proxy/assertion/field/content/filtered/FilteredContentBaseTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.assertion.field.content.filtered;
2 |
3 | import com.browserup.bup.proxy.assertion.field.content.ContentBaseTest;
4 |
5 | import java.util.regex.Pattern;
6 |
7 | class FilteredContentBaseTest extends ContentBaseTest {
8 | protected static final String FIRST_URL_PATH = "first-url-path-with-${URL_PATH}-in-the-middle"
9 | protected static final String SECOND_URL_PATH = "second-url-path-with-${URL_PATH}-in-the-middle"
10 | protected static final Pattern URL_PATTERN_TO_MATCH_BOTH = Pattern.compile(".*${URL_PATH}.*")
11 | protected static final Pattern URL_PATTERN_TO_MATCH_FIRST = Pattern.compile(".*${FIRST_URL_PATH}.*")
12 |
13 | protected mockAndSendRequestsToMockedServer(String firstBody, String secondBody) {
14 | mockResponse(FIRST_URL_PATH, firstBody)
15 | mockResponse(SECOND_URL_PATH, secondBody)
16 |
17 | requestToMockedServer(FIRST_URL_PATH, firstBody)
18 | requestToMockedServer(SECOND_URL_PATH, secondBody)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/proxy/assertion/field/content/mostrecent/ContentContainsTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.assertion.field.content.mostrecent
2 |
3 | import org.junit.Test
4 |
5 | import static org.junit.Assert.assertFalse
6 | import static org.junit.Assert.assertTrue
7 |
8 | class ContentContainsTest extends MostRecentContentBaseTest {
9 |
10 | @Test
11 | void oldAndRecentContainsTextAndRecentFilterIsUsedPasses() {
12 | mockAndSendRequestsToMockedServer(BODY_CONTAINING_BODY_PART, BODY_CONTAINING_BODY_PART)
13 |
14 | def result = proxy.assertMostRecentResponseContentContains(RECENT_REQUEST_URL_PATH_PATTERN, BODY_PART)
15 |
16 | assertAssertionPassed(result)
17 | }
18 |
19 | @Test
20 | void oldAndRecentContainsTextAndOldFilterIsUsedPasses() {
21 | mockAndSendRequestsToMockedServer(BODY_CONTAINING_BODY_PART, BODY_CONTAINING_BODY_PART)
22 |
23 | def result = proxy.assertMostRecentResponseContentContains(OLD_REQUEST_URL_PATH_PATTERN, BODY_PART)
24 |
25 | assertAssertionPassed(result)
26 | }
27 |
28 | @Test
29 | void onlyOldContainsTextAndOldFilterIsUsedPasses() {
30 | mockAndSendRequestsToMockedServer(BODY_NOT_CONTAINING_BODY_PART, BODY_CONTAINING_BODY_PART)
31 |
32 | def result = proxy.assertMostRecentResponseContentContains(OLD_REQUEST_URL_PATH_PATTERN, BODY_PART)
33 |
34 | assertAssertionPassed(result)
35 | }
36 |
37 | @Test
38 | void onlyOldContainsTextAndRecentFilterIsUsedFails() {
39 | mockAndSendRequestsToMockedServer(BODY_NOT_CONTAINING_BODY_PART, BODY_CONTAINING_BODY_PART)
40 |
41 | def result = proxy.assertMostRecentResponseContentContains(RECENT_REQUEST_URL_PATH_PATTERN, BODY_PART)
42 |
43 | assertAssertionFailed(result)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/proxy/assertion/field/content/mostrecent/ContentDoesNotContainTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.assertion.field.content.mostrecent
2 |
3 | import org.junit.Test
4 |
5 | import static org.junit.Assert.assertFalse
6 | import static org.junit.Assert.assertTrue
7 |
8 | class ContentDoesNotContainTest extends MostRecentContentBaseTest {
9 |
10 | @Test
11 | void oldAndRecentDoNotContainTextAndRecentFilterIsUsedPasses() {
12 | mockAndSendRequestsToMockedServer(BODY_NOT_CONTAINING_BODY_PART, BODY_NOT_CONTAINING_BODY_PART)
13 |
14 | def result = proxy.assertMostRecentResponseContentDoesNotContain(RECENT_REQUEST_URL_PATH_PATTERN, BODY_PART)
15 |
16 | assertAssertionPassed(result)
17 | }
18 |
19 | @Test
20 | void oldAndRecentDoNotContainTextAndOldFilterIsUsedPasses() {
21 | mockAndSendRequestsToMockedServer(BODY_NOT_CONTAINING_BODY_PART, BODY_NOT_CONTAINING_BODY_PART)
22 |
23 | def result = proxy.assertMostRecentResponseContentDoesNotContain(OLD_REQUEST_URL_PATH_PATTERN, BODY_PART)
24 |
25 | assertAssertionPassed(result)
26 | }
27 |
28 | @Test
29 | void onlyOldDoesNotContainTextAndOldFilterIsUsedPasses() {
30 | mockAndSendRequestsToMockedServer(BODY_NOT_CONTAINING_BODY_PART, BODY_NOT_CONTAINING_BODY_PART)
31 |
32 | def result = proxy.assertMostRecentResponseContentDoesNotContain(OLD_REQUEST_URL_PATH_PATTERN, BODY_PART)
33 |
34 | assertAssertionPassed(result)
35 | }
36 |
37 | @Test
38 | void onlyOldDoesNotContainTextAndRecentFilterIsUsedFails() {
39 | mockAndSendRequestsToMockedServer(BODY_CONTAINING_BODY_PART, BODY_NOT_CONTAINING_BODY_PART)
40 |
41 | def result = proxy.assertMostRecentResponseContentDoesNotContain(RECENT_REQUEST_URL_PATH_PATTERN, BODY_PART)
42 |
43 | assertAssertionFailed(result)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/proxy/assertion/field/content/mostrecent/MostRecentContentBaseTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.assertion.field.content.mostrecent
2 |
3 | import com.browserup.bup.proxy.assertion.field.content.ContentBaseTest
4 |
5 | import java.util.regex.Pattern
6 |
7 | class MostRecentContentBaseTest extends ContentBaseTest {
8 | protected static final String RECENT_REQUEST_URL_PATH = "recent-${URL_PATH}"
9 | protected static final Pattern RECENT_REQUEST_URL_PATH_PATTERN = Pattern.compile(".*${RECENT_REQUEST_URL_PATH}.*")
10 | protected static final String OLD_REQUEST_URL_PATH = "old-${URL_PATH}"
11 | protected static final Pattern OLD_REQUEST_URL_PATH_PATTERN = Pattern.compile(".*${OLD_REQUEST_URL_PATH}.*")
12 | protected static final Integer DELAY_BETWEEN_REQUESTS = 50
13 | protected static final String RECENT_BODY = "recent body"
14 | protected static final String OLD_BODY = 'old body'
15 | protected static final Pattern BODY_PATTERN_TO_MATCH_RECENT = Pattern.compile(".*${RECENT_BODY}.*")
16 | protected static final Pattern BODY_PATTERN_TO_MATCH_OLD = Pattern.compile(".*${OLD_BODY}.*")
17 |
18 | protected mockAndSendRequestsToMockedServer(String recentBody, String oldBody) {
19 | mockResponse(RECENT_REQUEST_URL_PATH, recentBody)
20 | mockResponse(OLD_REQUEST_URL_PATH, oldBody)
21 |
22 | requestToMockedServer(OLD_REQUEST_URL_PATH, oldBody)
23 | sleep DELAY_BETWEEN_REQUESTS
24 | requestToMockedServer(RECENT_REQUEST_URL_PATH, recentBody)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/groovy/com/browserup/bup/proxy/assertion/field/header/HeaderBaseTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.assertion.field.header
2 |
3 | import com.browserup.bup.proxy.CaptureType
4 | import com.browserup.bup.proxy.assertion.BaseAssertionsTest
5 | import com.github.tomakehurst.wiremock.http.HttpHeader
6 | import com.github.tomakehurst.wiremock.http.HttpHeaders
7 | import org.apache.http.HttpStatus
8 | import org.junit.Before
9 |
10 | import static com.github.tomakehurst.wiremock.client.WireMock.get
11 | import static com.github.tomakehurst.wiremock.client.WireMock.ok
12 | import static com.github.tomakehurst.wiremock.client.WireMock.stubFor
13 | import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo
14 |
15 | class HeaderBaseTest extends BaseAssertionsTest {
16 | protected static final def HEADER_NAME = 'headerName'
17 | protected static final def NOT_MATCHING_HEADER_NAME = 'headerName not to match'
18 | protected static final def HEADER_VALUE = 'headerValue'
19 | protected static final def NOT_MATCHING_HEADER_VALUE = 'headerValue not to match'
20 | protected static final def HEADER = new HttpHeader(HEADER_NAME, HEADER_VALUE)
21 |
22 | @Before
23 | void setUp() {
24 | proxy.enableHarCaptureTypes(CaptureType.RESPONSE_HEADERS)
25 | mockResponse(URL_PATH, HEADER)
26 | }
27 |
28 | protected mockResponse(String path, HttpHeader header) {
29 | stubFor(get(urlEqualTo("/" + path))
30 | .willReturn(ok()
31 | .withBody(SUCCESSFUL_RESPONSE_BODY)
32 | .withHeaders(new HttpHeaders(header))
33 | ))
34 | // mockServer.when(request()
35 | // .withMethod("GET")
36 | // .withPath("/${path}"),
37 | // Times.once())
38 | // .respond(response()
39 | // .withStatusCode(HttpStatus.SC_OK)
40 | // .withBody(SUCCESSFUL_RESPONSE_BODY)
41 | // .withHeader(header))
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/bup/proxy/test/util/MockServerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.test.util;
6 |
7 | import com.github.tomakehurst.wiremock.junit.WireMockRule;
8 | import org.junit.Before;
9 | import org.junit.Rule;
10 |
11 | import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
12 |
13 | /**
14 | * Tests can subclass this to get access to a ClientAndServer instance for creating mock responses.
15 | */
16 | public class MockServerTest {
17 | protected int mockServerPort;
18 | protected int mockServerHttpsPort;
19 |
20 | @Rule
21 | public WireMockRule wireMockRule = new WireMockRule(options().port(0).httpsPort(0));
22 |
23 | @Before
24 | public void setUpMockServer() {
25 | mockServerPort = wireMockRule.port();
26 | mockServerHttpsPort = wireMockRule.httpsPort();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/bup/proxy/test/util/NewProxyServerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.test.util;
6 |
7 | import com.browserup.bup.BrowserUpProxy;
8 | import com.browserup.bup.BrowserUpProxyServer;
9 | import org.junit.After;
10 | import org.junit.Before;
11 |
12 | /**
13 | * A base class that spins up and shuts down a BrowserUpProxy instance using the new interface. It also provides mock server support via
14 | * {@link com.browserup.bup.proxy.test.util.MockServerTest}.
15 | */
16 | public class NewProxyServerTest extends MockServerTest {
17 | protected BrowserUpProxy proxy;
18 |
19 | @Before
20 | public void setUpProxyServer() {
21 | proxy = new BrowserUpProxyServer();
22 | proxy.start();
23 | }
24 |
25 | @After
26 | public void shutDownProxyServer() {
27 | if (proxy != null) {
28 | proxy.abort();
29 | }
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/bup/proxy/test/util/TestConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.test.util;
6 |
7 | import com.google.common.collect.ImmutableList;
8 |
9 | import java.net.InetAddress;
10 | import java.net.UnknownHostException;
11 | import java.util.List;
12 |
13 | /**
14 | * Convenience class for test constants.
15 | */
16 | public class TestConstants {
17 | public static final InetAddress addressOnes;
18 | public static final InetAddress addressTwos;
19 | public static final List addressOnesList;
20 | public static final List addressTwosList;
21 |
22 | static {
23 | try {
24 | addressOnes = InetAddress.getByName("1.1.1.1");
25 | addressTwos = InetAddress.getByName("2.2.2.2");
26 | addressOnesList = ImmutableList.of(TestConstants.addressOnes);
27 | addressTwosList = ImmutableList.of(TestConstants.addressTwos);
28 | } catch (UnknownHostException e) {
29 | throw new RuntimeException(e);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/AbstractMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.junit.Assert;
5 | import org.junit.Test;
6 |
7 | public abstract class AbstractMapperTest {
8 |
9 | protected final static String UNKNOWN_PROPERTY = "{\"unknownProperty\":\"value\"}";
10 |
11 | @Test
12 | public abstract void testMapping();
13 |
14 | public T map(String input, Class tClass) {
15 | ObjectMapper mapper = new ObjectMapper();
16 | try {
17 | return mapper.readValue(input, tClass);
18 | } catch (Exception e) {
19 | Assert.fail(e.getMessage());
20 | }
21 | return null;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarCacheTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 |
5 | import java.util.Date;
6 |
7 | public class HarCacheTest extends AbstractMapperTest {
8 |
9 | private final static Date EXPECTED_EXPIRES = new Date() {{
10 | setTime(1388577600000L);
11 | }};
12 | private final static Date EXPECTED_LAST_ACCESS = new Date() {{
13 | setTime(1370088000000L);
14 | }};
15 |
16 | @Override
17 | public void testMapping() {
18 | HarCache cache = map("{\"beforeRequest\":{\"expires\":\"2014-01-01T12:00:00\",\"lastAccess\":\"2013-06-01T12:00:00\",\"eTag\":\"abc123\"," +
19 | "\"hitCount\":3,\"comment\":\"my comment\"},\"afterRequest\":{},\"comment\":\"my comment 2\"}", HarCache.class);
20 |
21 | Assert.assertNotNull(cache.getBeforeRequest());
22 | Assert.assertEquals(EXPECTED_EXPIRES, cache.getBeforeRequest().getExpires());
23 | Assert.assertEquals(EXPECTED_LAST_ACCESS, cache.getBeforeRequest().getLastAccess());
24 | Assert.assertEquals("abc123", cache.getBeforeRequest().geteTag());
25 | Assert.assertEquals(3, (long) cache.getBeforeRequest().getHitCount());
26 | Assert.assertEquals("my comment", cache.getBeforeRequest().getComment());
27 |
28 | Assert.assertNotNull(cache.getAfterRequest());
29 |
30 | Assert.assertEquals("my comment 2", cache.getComment());
31 |
32 | cache = map(UNKNOWN_PROPERTY, HarCache.class);
33 | Assert.assertNotNull(cache);
34 |
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarContentTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 |
5 | public class HarContentTest extends AbstractMapperTest {
6 |
7 | @Override
8 | public void testMapping() {
9 | HarContent content = map("{\"size\":123,\"compression\":45,\"mimeType\":\"mime/type\"," +
10 | "\"text\":\"my content\",\"encoding\":\"base64\",\"comment\":\"my comment\"}", HarContent.class);
11 |
12 | Assert.assertEquals(123L, (long) content.getSize());
13 | Assert.assertEquals(45L, (long) content.getCompression());
14 | Assert.assertEquals("mime/type", content.getMimeType());
15 | Assert.assertEquals("my content", content.getText());
16 | Assert.assertEquals("base64", content.getEncoding());
17 | Assert.assertEquals("my comment", content.getComment());
18 |
19 | content = map(UNKNOWN_PROPERTY, HarContent.class);
20 | Assert.assertNotNull(content);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarCookieTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 |
5 | import java.util.Date;
6 |
7 | public class HarCookieTest extends AbstractMapperTest {
8 |
9 | private final static Date EXPECTED_EXPIRES = new Date() {{
10 | setTime(1388577600000L);
11 | }};
12 |
13 | @Override
14 | public void testMapping() {
15 | HarCookie cookie = map("{\"name\":\"aName\",\"value\":\"aValue\",\"path\":\"/\",\"domain\":\"sstoehr.de\"," +
16 | "\"expires\":\"2014-01-01T12:00:00\",\"httpOnly\":\"true\",\"secure\":\"false\",\"comment\":\"my comment\"}", HarCookie.class);
17 |
18 | Assert.assertNotNull(cookie);
19 | Assert.assertEquals("aName", cookie.getName());
20 | Assert.assertEquals("aValue", cookie.getValue());
21 | Assert.assertEquals("/", cookie.getPath());
22 | Assert.assertEquals("sstoehr.de", cookie.getDomain());
23 | Assert.assertEquals(EXPECTED_EXPIRES, cookie.getExpires());
24 | Assert.assertEquals(true, cookie.getHttpOnly());
25 | Assert.assertEquals(false, cookie.getSecure());
26 | Assert.assertEquals("my comment", cookie.getComment());
27 |
28 | cookie = map(UNKNOWN_PROPERTY, HarCookie.class);
29 | Assert.assertNotNull(cookie);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarCreatorBrowserTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 |
5 | public class HarCreatorBrowserTest extends AbstractMapperTest {
6 |
7 | @Override
8 | public void testMapping() {
9 | HarCreatorBrowser creatorBrowser = map("{\"name\":\"aName\",\"version\":\"aVersion\",\"comment\":\"my comment\"}", HarCreatorBrowser.class);
10 |
11 | Assert.assertNotNull(creatorBrowser);
12 | Assert.assertEquals("aName", creatorBrowser.getName());
13 | Assert.assertEquals("aVersion", creatorBrowser.getVersion());
14 | Assert.assertEquals("my comment", creatorBrowser.getComment());
15 |
16 | creatorBrowser = map(UNKNOWN_PROPERTY, HarCreatorBrowser.class);
17 | Assert.assertNotNull(creatorBrowser);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarHeaderTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 |
5 | public class HarHeaderTest extends AbstractMapperTest {
6 |
7 | @Override
8 | public void testMapping() {
9 | HarHeader header = map("{\"name\":\"aName\",\"value\":\"aValue\",\"comment\":\"my comment\"}", HarHeader.class);
10 |
11 | Assert.assertNotNull(header);
12 | Assert.assertEquals("aName", header.getName());
13 | Assert.assertEquals("aValue", header.getValue());
14 | Assert.assertEquals("my comment", header.getComment());
15 |
16 | header = map(UNKNOWN_PROPERTY, HarHeader.class);
17 | Assert.assertNotNull(header);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarPageTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | import java.util.Date;
7 |
8 | public class HarPageTest extends AbstractMapperTest {
9 |
10 | private final static Date EXPECTED_STARTED = new Date() {{
11 | setTime(1388577600000L);
12 | }};
13 |
14 | @Override
15 | public void testMapping() {
16 | HarPage page = map("{\"startedDateTime\":\"2014-01-01T12:00:00\",\"id\":\"anId\","
17 | + "\"title\":\"aTitle\",\"pageTimings\":{},\"comment\":\"my comment\", \"_add\": \"additional info\"}", HarPage.class);
18 |
19 | Assert.assertNotNull(page);
20 | Assert.assertEquals(EXPECTED_STARTED, page.getStartedDateTime());
21 | Assert.assertEquals("anId", page.getId());
22 | Assert.assertEquals("aTitle", page.getTitle());
23 | Assert.assertNotNull(page.getPageTimings());
24 | Assert.assertEquals("my comment", page.getComment());
25 | Assert.assertEquals("additional info", page.getAdditional().get("_add"));
26 |
27 | page = map(UNKNOWN_PROPERTY, HarPage.class);
28 | Assert.assertNotNull(page);
29 | }
30 |
31 | @Test
32 | public void testPageTimingsNull() {
33 | HarPage page = new HarPage();
34 | page.setPageTimings(null);
35 | Assert.assertNotNull(page.getPageTimings());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarPageTimingTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class HarPageTimingTest extends AbstractMapperTest {
7 |
8 | private static final Integer EXPECTED_DEFAULT_DURATION = -1;
9 |
10 | @Test
11 | public void testOnContentLoad() {
12 | HarPageTiming pageTiming = new HarPageTiming();
13 | Assert.assertEquals(EXPECTED_DEFAULT_DURATION, pageTiming.getOnContentLoad());
14 |
15 | pageTiming.setOnContentLoad(1234);
16 | Assert.assertEquals(1234, (int) pageTiming.getOnContentLoad());
17 |
18 | pageTiming.setOnContentLoad(null);
19 | Assert.assertEquals(EXPECTED_DEFAULT_DURATION, pageTiming.getOnContentLoad());
20 | }
21 |
22 | @Test
23 | public void testOnLoad() {
24 | HarPageTiming pageTiming = new HarPageTiming();
25 | Assert.assertEquals(EXPECTED_DEFAULT_DURATION, pageTiming.getOnLoad());
26 |
27 | pageTiming.setOnLoad(1234);
28 | Assert.assertEquals(1234, (int) pageTiming.getOnLoad());
29 |
30 | pageTiming.setOnLoad(null);
31 | Assert.assertEquals(EXPECTED_DEFAULT_DURATION, pageTiming.getOnLoad());
32 | }
33 |
34 | @Override
35 | public void testMapping() {
36 | HarPageTiming pageTiming = map("{\"onContentLoad\": 1234, \"onLoad\": 5678, \"comment\": \"My comment\"}", HarPageTiming.class);
37 |
38 | Assert.assertEquals(1234, (int) pageTiming.getOnContentLoad());
39 | Assert.assertEquals(5678, (int) pageTiming.getOnLoad());
40 | Assert.assertEquals("My comment", pageTiming.getComment());
41 |
42 | pageTiming = map(UNKNOWN_PROPERTY, HarPageTiming.class);
43 | Assert.assertNotNull(pageTiming);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarPostDataParamTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 |
5 | public class HarPostDataParamTest extends AbstractMapperTest {
6 |
7 | @Override
8 | public void testMapping() {
9 | HarPostDataParam postDataParam = map("{\"name\": \"aName\", \"value\": \"aValue\", \"fileName\": \"aFilename\", \"contentType\": \"aContentType\", \"comment\": \"My comment\"}", HarPostDataParam.class);
10 |
11 | Assert.assertEquals("aName", postDataParam.getName());
12 | Assert.assertEquals("aValue", postDataParam.getValue());
13 | Assert.assertEquals("aFilename", postDataParam.getFileName());
14 | Assert.assertEquals("aContentType", postDataParam.getContentType());
15 | Assert.assertEquals("My comment", postDataParam.getComment());
16 |
17 |
18 | postDataParam = map(UNKNOWN_PROPERTY, HarPostDataParam.class);
19 | Assert.assertNotNull(postDataParam);
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarPostDataTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class HarPostDataTest extends AbstractMapperTest {
10 |
11 | private static final List EXPECTED_LIST = new ArrayList<>();
12 |
13 | @Override
14 | public void testMapping() {
15 | HarPostData postData = map("{\"mimeType\": \"aMimeType\", \"params\": [], \"text\":\"aText\", \"comment\": \"My comment\"}", HarPostData.class);
16 |
17 | Assert.assertEquals("aMimeType", postData.getMimeType());
18 | Assert.assertEquals(EXPECTED_LIST, postData.getParams());
19 | Assert.assertEquals("aText", postData.getText());
20 | Assert.assertEquals("My comment", postData.getComment());
21 |
22 | postData = map(UNKNOWN_PROPERTY, HarPostData.class);
23 | Assert.assertNotNull(postData);
24 | }
25 |
26 | @Test
27 | public void testParams() {
28 | HarPostData postData = new HarPostData();
29 | postData.setParams(null);
30 | Assert.assertNotNull(postData.getParams());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarQueryParamTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 |
5 | public class HarQueryParamTest extends AbstractMapperTest {
6 |
7 | @Override
8 | public void testMapping() {
9 | HarQueryParam queryParam = map("{\"name\": \"aName\", \"value\":\"aValue\", \"comment\": \"My comment\"}", HarQueryParam.class);
10 |
11 | Assert.assertEquals("aName", queryParam.getName());
12 | Assert.assertEquals("aValue", queryParam.getValue());
13 | Assert.assertEquals("My comment", queryParam.getComment());
14 | }
15 |
16 | }
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class HarTest extends AbstractMapperTest{
7 |
8 | @Test
9 | public void testLogNull() {
10 | Har har = new Har();
11 | har.setLog(null);
12 | Assert.assertNotNull(har.getLog());
13 | }
14 |
15 | @Override
16 | public void testMapping() {
17 | Har har = map("{\"log\": {}}", Har.class);
18 | Assert.assertNotNull(har.getLog());
19 |
20 | har = map(UNKNOWN_PROPERTY, Har.class);
21 | Assert.assertNotNull(har);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HarTimingTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class HarTimingTest extends AbstractMapperTest {
7 |
8 | @Override
9 | public void testMapping() {
10 | HarTiming timing = map("{\"blocked\": 3804,\"dns\": 23,\"connect\": 5,\"send\": 9,\"wait\": 5209,"
11 | + "\"receive\": 79, \"ssl\": 123, \"comment\": \"my comment\"}", HarTiming.class);
12 |
13 | Assert.assertNotNull(timing);
14 | Assert.assertEquals(3804, (int) timing.getBlocked());
15 | Assert.assertEquals(23, (int) timing.getDns());
16 | Assert.assertEquals(5, (int) timing.getConnect());
17 | Assert.assertEquals(9, (int) timing.getSend());
18 | Assert.assertEquals(5209, (int) timing.getWait());
19 | Assert.assertEquals(79, (int) timing.getReceive());
20 | Assert.assertEquals(123, (int) timing.getSsl());
21 | Assert.assertEquals("my comment", timing.getComment());
22 | }
23 |
24 | @Test
25 | public void testBlocked() {
26 | HarTiming timing = new HarTiming();
27 | timing.setBlocked(null);
28 | Assert.assertEquals(-1, (int) timing.getBlocked());
29 | }
30 |
31 | @Test
32 | public void testDns() {
33 | HarTiming timing = new HarTiming();
34 | timing.setDns(null);
35 | Assert.assertEquals(-1, (int) timing.getDns());
36 | }
37 |
38 | @Test
39 | public void testConnect() {
40 | HarTiming timing = new HarTiming();
41 | timing.setConnect(null);
42 | Assert.assertEquals(-1, (int) timing.getConnect());
43 | }
44 |
45 | @Test
46 | public void testSsl() {
47 | HarTiming timing = new HarTiming();
48 | timing.setSsl(null);
49 | Assert.assertEquals(-1, (int) timing.getSsl());
50 | }
51 | }
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/java/com/browserup/harreader/model/HttpStatusTest.java:
--------------------------------------------------------------------------------
1 | package com.browserup.harreader.model;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class HttpStatusTest {
7 |
8 | @Test
9 | public void testByCode() {
10 | for (HttpStatus status : HttpStatus.values()) {
11 | Assert.assertEquals(status, HttpStatus.byCode(status.getCode()));
12 | }
13 | }
14 |
15 | @Test
16 | public void test302() {
17 | Assert.assertEquals(HttpStatus.FOUND, HttpStatus.byCode(302));
18 | }
19 |
20 | @Test
21 | public void testInvalidCode() {
22 | Assert.assertEquals(HttpStatus.UNKNOWN_HTTP_STATUS, HttpStatus.byCode(0));
23 | Assert.assertEquals(HttpStatus.UNKNOWN_HTTP_STATUS, HttpStatus.byCode(1000));
24 | Assert.assertEquals(HttpStatus.UNKNOWN_HTTP_STATUS, HttpStatus.byCode(-999));
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-core/src/test/resources/log4j2-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "configuration" : {
3 | "name": "test",
4 | "appenders": {
5 | "Console": {
6 | "name": "console",
7 | "target": "SYSTEM_OUT",
8 | "PatternLayout": {
9 | "pattern": "%-7r %date %level [%thread] %logger - %msg%n"
10 | }
11 | }
12 | },
13 |
14 | "loggers": {
15 | "root": {
16 | "level": "debug",
17 | "appender-ref": {
18 | "ref": "console"
19 | }
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/browserup-proxy-dist/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/browserup-proxy-dist/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | browserup-proxy-dist
4 | Project browserup-proxy-dist created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.buildship.core.gradleprojectbuilder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.buildship.core.gradleprojectnature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/browserup-proxy-dist/src/main/java/com/browserup/bup/exception/JettyException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.exception;
6 |
7 | /**
8 | * A wrapper for exceptions coming from Jetty methods that throw Exception,
9 | * rather than a useful Exception subclass.
10 | */
11 | public class JettyException extends RuntimeException {
12 | private static final long serialVersionUID = 8125833642102189196L;
13 |
14 | public JettyException() {
15 | }
16 |
17 | public JettyException(String message) {
18 | super(message);
19 | }
20 |
21 | public JettyException(Throwable cause) {
22 | super(cause);
23 | }
24 |
25 | public JettyException(String message, Throwable cause) {
26 | super(message, cause);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/browserup-proxy-dist/src/main/resources/bup-logging.yaml:
--------------------------------------------------------------------------------
1 | # This file controls the logging configuration for BrowserUp-proxy in "standalone" mode. To adjust the amount of log output, modify the
2 | # 'level' fields below. For more information on log4j configuration files, see http://logging.apache.org/log4j/2.x/manual/configuration.html.
3 |
4 | configuration:
5 | name: standalone
6 | appenders:
7 | console:
8 | name: console
9 | target: SYSTEM_OUT
10 | PatternLayout:
11 | pattern: "[%-5level %date{ISO8601} %logger] (%thread) %msg %xThrowable%n"
12 | file:
13 | -
14 | name: file
15 | fileName: bup.log
16 | PatternLayout:
17 | pattern: "[%-5level %date{ISO8601} %logger] (%thread) %msg %xThrowable%n"
18 | append: false
19 | loggers:
20 | logger:
21 | -
22 | name: com.browserup.bup.proxy.jetty.util.ThreadedServer
23 | level: warn
24 | additivity: false
25 | -
26 | name: com.browserup.bup
27 | # to suppress unwanted BUP logging statements, set the level below for the source logger to WARN or ERROR.
28 | # to enable more verbose logging, set the level to DEBUG or TRACE.
29 | level: info
30 | root:
31 | # to suppress unwanted logging statements globally, set the level below to WARN or ERROR.
32 | level: info
33 | appender-ref:
34 | -
35 | ref: console
36 | -
37 | ref: file
--------------------------------------------------------------------------------
/browserup-proxy-mitm/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | browserup-proxy-mitm
4 | Project browserup-proxy-mitm created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.buildship.core.gradleprojectbuilder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.buildship.core.gradleprojectnature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/CertificateAndKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm;
6 |
7 | import java.security.PrivateKey;
8 | import java.security.cert.X509Certificate;
9 |
10 | /**
11 | * A simple container for an X.509 certificate and its corresponding private key.
12 | */
13 | public class CertificateAndKey {
14 | private final X509Certificate certificate;
15 | private final PrivateKey privateKey;
16 |
17 | public CertificateAndKey(X509Certificate certificate, PrivateKey privateKey) {
18 | this.certificate = certificate;
19 | this.privateKey = privateKey;
20 | }
21 |
22 | public X509Certificate getCertificate() {
23 | return certificate;
24 | }
25 |
26 | public PrivateKey getPrivateKey() {
27 | return privateKey;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/CertificateAndKeySource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm;
6 |
7 | /**
8 | * A CertificateAndKeySource generates {@link CertificateAndKey}s, i.e. the root certificate and private key used
9 | * to sign impersonated certificates of upstream servers. Implementations of this interface load impersonation materials
10 | * from various sources, including Java KeyStores, JKS files, etc., or generate them on-the-fly.
11 | */
12 | public interface CertificateAndKeySource {
13 | /**
14 | * Loads a certificate and its corresponding private key. Every time this method is called, it should return the same
15 | * certificate and private key (although it may be a different {@link CertificateAndKey} instance).
16 | *
17 | * @return certificate and its corresponding private key
18 | */
19 | CertificateAndKey load();
20 | }
21 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/CertificateInfoGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm;
6 |
7 | import java.security.cert.X509Certificate;
8 | import java.util.List;
9 |
10 | /**
11 | * A functional interface to allow customization of the certificates generated by the
12 | * {@link com.browserup.bup.mitm.manager.ImpersonatingMitmManager}.
13 | */
14 | public interface CertificateInfoGenerator {
15 | /**
16 | * Generate a certificate for the specified hostnames, optionally using parameters from the originalCertificate.
17 | *
18 | * @param hostnames the hostnames to generate the certificate for, which may include wildcards
19 | * @param originalCertificate original X.509 certificate sent by the upstream server, which may be null
20 | * @return CertificateInfo to be used to create an X509Certificate for the specified hostnames
21 | */
22 | CertificateInfo generate(List hostnames, X509Certificate originalCertificate);
23 | }
24 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/ExistingCertificateSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm;
6 |
7 | import java.security.PrivateKey;
8 | import java.security.cert.X509Certificate;
9 |
10 | /**
11 | * A simple adapter that produces a {@link CertificateAndKey} from existing {@link X509Certificate} and {@link PrivateKey}
12 | * java objects.
13 | */
14 | public class ExistingCertificateSource implements CertificateAndKeySource {
15 | private final X509Certificate rootCertificate;
16 | private final PrivateKey privateKey;
17 |
18 | public ExistingCertificateSource(X509Certificate rootCertificate, PrivateKey privateKey) {
19 | if (rootCertificate == null) {
20 | throw new IllegalArgumentException("CA root certificate cannot be null");
21 | }
22 |
23 | if (privateKey == null) {
24 | throw new IllegalArgumentException("Private key cannot be null");
25 | }
26 |
27 | this.rootCertificate = rootCertificate;
28 | this.privateKey = privateKey;
29 | }
30 |
31 | @Override
32 | public CertificateAndKey load() {
33 | return new CertificateAndKey(rootCertificate, privateKey);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/CertificateCreationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates a problem creating a certificate (server or CA).
9 | */
10 | public class CertificateCreationException extends RuntimeException {
11 | private static final long serialVersionUID = 592999944486567944L;
12 |
13 | public CertificateCreationException() {
14 | }
15 |
16 | public CertificateCreationException(String message) {
17 | super(message);
18 | }
19 |
20 | public CertificateCreationException(String message, Throwable cause) {
21 | super(message, cause);
22 | }
23 |
24 | public CertificateCreationException(Throwable cause) {
25 | super(cause);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/CertificateSourceException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates that a {@link com.browserup.bup.mitm.CertificateAndKeySource} encountered an error while loading a
9 | * certificate and/or private key from a KeyStore, PEM file, or other source.
10 | */
11 | public class CertificateSourceException extends RuntimeException {
12 | private static final long serialVersionUID = 6195838041376082083L;
13 |
14 | public CertificateSourceException() {
15 | }
16 |
17 | public CertificateSourceException(String message) {
18 | super(message);
19 | }
20 |
21 | public CertificateSourceException(String message, Throwable cause) {
22 | super(message, cause);
23 | }
24 |
25 | public CertificateSourceException(Throwable cause) {
26 | super(cause);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/ExportException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates an error occurred while exporting/serializing a certificate, private key, KeyStore, etc.
9 | */
10 | public class ExportException extends RuntimeException {
11 | private static final long serialVersionUID = -3505301862887355206L;
12 |
13 | public ExportException() {
14 | }
15 |
16 | public ExportException(String message) {
17 | super(message);
18 | }
19 |
20 | public ExportException(String message, Throwable cause) {
21 | super(message, cause);
22 | }
23 |
24 | public ExportException(Throwable cause) {
25 | super(cause);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/ImportException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates that an error occurred while importing a certificate, private key, or KeyStore.
9 | */
10 | public class ImportException extends RuntimeException {
11 | private static final long serialVersionUID = 584414535648926010L;
12 |
13 | public ImportException() {
14 | }
15 |
16 | public ImportException(String message) {
17 | super(message);
18 | }
19 |
20 | public ImportException(String message, Throwable cause) {
21 | super(message, cause);
22 | }
23 |
24 | public ImportException(Throwable cause) {
25 | super(cause);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/KeyGeneratorException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates an exception occurred while generating a key pair.
9 | */
10 | public class KeyGeneratorException extends RuntimeException {
11 | private static final long serialVersionUID = 7607159769324427808L;
12 |
13 | public KeyGeneratorException() {
14 | }
15 |
16 | public KeyGeneratorException(String message) {
17 | super(message);
18 | }
19 |
20 | public KeyGeneratorException(String message, Throwable cause) {
21 | super(message, cause);
22 | }
23 |
24 | public KeyGeneratorException(Throwable cause) {
25 | super(cause);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/KeyStoreAccessException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates an error occurred while accessing a java KeyStore.
9 | */
10 | public class KeyStoreAccessException extends RuntimeException {
11 | private static final long serialVersionUID = -5560417886988154298L;
12 |
13 | public KeyStoreAccessException() {
14 | }
15 |
16 | public KeyStoreAccessException(String message) {
17 | super(message);
18 | }
19 |
20 | public KeyStoreAccessException(String message, Throwable cause) {
21 | super(message, cause);
22 | }
23 |
24 | public KeyStoreAccessException(Throwable cause) {
25 | super(cause);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/MitmException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates a general problem occurred while attempting to man-in-the-middle communications between the client and the
9 | * upstream server.
10 | */
11 | public class MitmException extends RuntimeException {
12 | private static final long serialVersionUID = -1960691906515767537L;
13 |
14 | public MitmException() {
15 | }
16 |
17 | public MitmException(String message) {
18 | super(message);
19 | }
20 |
21 | public MitmException(String message, Throwable cause) {
22 | super(message, cause);
23 | }
24 |
25 | public MitmException(Throwable cause) {
26 | super(cause);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/SslContextInitializationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates an error occurred while attempting to create a new {@link javax.net.ssl.SSLContext}.
9 | */
10 | public class SslContextInitializationException extends RuntimeException {
11 | private static final long serialVersionUID = 6744059714710316821L;
12 |
13 | public SslContextInitializationException() {
14 | }
15 |
16 | public SslContextInitializationException(String message) {
17 | super(message);
18 | }
19 |
20 | public SslContextInitializationException(String message, Throwable cause) {
21 | super(message, cause);
22 | }
23 |
24 | public SslContextInitializationException(Throwable cause) {
25 | super(cause);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/TrustSourceException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | /**
8 | * Indicates that an error occurred while attempting to create or populate a {@link com.browserup.bup.mitm.TrustSource}.
9 | */
10 | public class TrustSourceException extends RuntimeException {
11 | public TrustSourceException() {
12 | }
13 |
14 | public TrustSourceException(String message) {
15 | super(message);
16 | }
17 |
18 | public TrustSourceException(String message, Throwable cause) {
19 | super(message, cause);
20 | }
21 |
22 | public TrustSourceException(Throwable cause) {
23 | super(cause);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/exception/UncheckedIOException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.exception;
6 |
7 | import java.io.IOException;
8 |
9 | /**
10 | * A convenience exception that wraps checked {@link IOException}s. (The built-in java.io.UncheckedIOException is only
11 | * available on Java 8.)
12 | */
13 | public class UncheckedIOException extends RuntimeException {
14 | public UncheckedIOException(String message, IOException cause) {
15 | super(message, cause);
16 | }
17 |
18 | public UncheckedIOException(IOException cause) {
19 | super(cause);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/keys/KeyGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.keys;
6 |
7 | import java.security.KeyPair;
8 |
9 | /**
10 | * A functional interface for key pair generators.
11 | */
12 | public interface KeyGenerator {
13 | /**
14 | * Generates a new public/private key pair. This method should not cache or reuse any previously-generated key pairs.
15 | *
16 | * @return a new public/private key pair
17 | */
18 | KeyPair generate();
19 | }
20 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/keys/RSAKeyGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.keys;
6 |
7 | import com.browserup.bup.mitm.exception.KeyGeneratorException;
8 |
9 | import java.security.KeyPair;
10 | import java.security.KeyPairGenerator;
11 | import java.security.NoSuchAlgorithmException;
12 |
13 | /**
14 | * A {@link KeyGenerator} that creates RSA key pairs.
15 | */
16 | public class RSAKeyGenerator implements KeyGenerator {
17 | private static final String RSA_KEY_GEN_ALGORITHM = "RSA";
18 |
19 | /**
20 | * Use a default RSA key size of 2048, since Chrome, Firefox, and possibly other browsers have begun to distrust
21 | * certificates signed with 1024-bit RSA keys.
22 | */
23 | private static final int DEFAULT_KEY_SIZE = 2048;
24 |
25 | private final int keySize;
26 |
27 | /**
28 | * Create a {@link KeyGenerator} that will create a 2048-bit RSA key pair.
29 | */
30 | public RSAKeyGenerator() {
31 | this.keySize = DEFAULT_KEY_SIZE;
32 | }
33 |
34 | /**
35 | * Create a {@link KeyGenerator} that will create an RSA key pair of the specified keySize.
36 | * @param keySize keySize
37 | */
38 | public RSAKeyGenerator(int keySize) {
39 | this.keySize = keySize;
40 | }
41 |
42 | @Override
43 | public KeyPair generate() {
44 | // obtain an RSA key pair generator for the specified key size
45 | KeyPairGenerator generator;
46 | try {
47 | generator = KeyPairGenerator.getInstance(RSA_KEY_GEN_ALGORITHM);
48 | generator.initialize(keySize);
49 | } catch (NoSuchAlgorithmException e) {
50 | throw new KeyGeneratorException("Unable to generate " + keySize + "-bit RSA public/private key pair", e);
51 | }
52 |
53 | return generator.generateKeyPair();
54 | }
55 |
56 | @Override
57 | public String toString() {
58 | return "RSA (" + keySize + ")";
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/java/com/browserup/bup/mitm/util/MitmConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.util;
6 |
7 | /**
8 | * Default values for basic MITM properties.
9 | */
10 | public class MitmConstants {
11 | /**
12 | * The default message digest to use when signing certificates (CA or server). On 64-bit systems this is set to
13 | * SHA512, on 32-bit systems this is SHA256. On 64-bit systems, SHA512 generally performs better than SHA256; see
14 | * this question for details: http://crypto.stackexchange.com/questions/26336/sha512-faster-than-sha256. SHA384 is
15 | * SHA512 with a smaller output size.
16 | */
17 | public static final String DEFAULT_MESSAGE_DIGEST = is32BitJvm() ? "SHA256": "SHA384";
18 |
19 | /**
20 | * The default {@link java.security.KeyStore} type to use when creating KeyStores (e.g. for impersonated server
21 | * certificates). PKCS12 is widely supported.
22 | */
23 | public static final String DEFAULT_KEYSTORE_TYPE = "PKCS12";
24 |
25 | /**
26 | * Uses the non-portable system property sun.arch.data.model to help determine if we are running on a 32-bit JVM.
27 | * Since the majority of modern systems are 64 bits, this method "assumes" 64 bits and only returns true if
28 | * sun.arch.data.model explicitly indicates a 32-bit JVM.
29 | *
30 | * @return true if we can determine definitively that this is a 32-bit JVM, otherwise false
31 | */
32 | private static boolean is32BitJvm() {
33 | Integer bits = Integer.getInteger("sun.arch.data.model");
34 |
35 | return bits != null && bits == 32;
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/main/resources/default-ciphers.txt:
--------------------------------------------------------------------------------
1 | TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
2 | TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
3 | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
4 | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
5 | TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
6 | TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
7 | TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
8 | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
9 | TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
10 | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
11 | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
12 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
13 | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
14 | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
15 | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
16 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
17 | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
18 | TLS_DHE_RSA_WITH_AES_256_CBC_SHA
19 | TLS_DHE_RSA_WITH_AES_128_CBC_SHA
20 | TLS_RSA_WITH_AES_256_GCM_SHA384
21 | TLS_RSA_WITH_AES_256_GCM_SHA384
22 | TLS_RSA_WITH_AES_128_GCM_SHA256
23 | TLS_RSA_WITH_AES_256_CBC_SHA
24 | TLS_RSA_WITH_AES_128_CBC_SHA
25 | SSL_RSA_WITH_3DES_EDE_CBC_SHA
26 | TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
27 | TLS_DHE_DSS_WITH_AES_256_CBC_SHA
28 | TLS_DHE_DSS_WITH_AES_128_CBC_SHA
29 |
30 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/groovy/com/browserup/bup/mitm/ExistingCertificateSourceTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm
6 |
7 | import org.junit.Test
8 |
9 | import java.security.PrivateKey
10 | import java.security.cert.X509Certificate
11 |
12 | import static org.junit.Assert.assertEquals
13 | import static org.mockito.Mockito.mock
14 |
15 | class ExistingCertificateSourceTest {
16 |
17 | X509Certificate mockCertificate = mock(X509Certificate)
18 | PrivateKey mockPrivateKey = mock(PrivateKey)
19 |
20 | @Test
21 | void testLoadExistingCertificateAndKey() {
22 | ExistingCertificateSource certificateSource = new ExistingCertificateSource(mockCertificate, mockPrivateKey)
23 | CertificateAndKey certificateAndKey = certificateSource.load()
24 |
25 | assertEquals(mockCertificate, certificateAndKey.certificate)
26 | assertEquals(mockPrivateKey, certificateAndKey.privateKey)
27 | }
28 |
29 | @Test(expected = IllegalArgumentException)
30 | void testMustSupplyCertificate() {
31 | ExistingCertificateSource certificateSource = new ExistingCertificateSource(null, mockPrivateKey)
32 | certificateSource.load()
33 | }
34 |
35 | @Test(expected = IllegalArgumentException)
36 | void testMustSupplyPrivateKey() {
37 | ExistingCertificateSource certificateSource = new ExistingCertificateSource(mockCertificate, null)
38 | certificateSource.load()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/groovy/com/browserup/bup/mitm/KeyStoreCertificateSourceTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm
6 |
7 | import org.junit.Test
8 |
9 | import java.security.KeyStore
10 |
11 | import static org.mockito.Mockito.mock
12 |
13 | class KeyStoreCertificateSourceTest {
14 |
15 | KeyStore mockKeyStore = mock(KeyStore)
16 |
17 | // the happy-path test cases are already covered implicitly as part of KeyStoreFileCertificateSourceTest, so just test negative cases
18 |
19 | @Test(expected = IllegalArgumentException)
20 | void testMustSupplyKeystore() {
21 | KeyStoreCertificateSource keyStoreCertificateSource = new KeyStoreCertificateSource(null, "privatekey", "password")
22 | keyStoreCertificateSource.load()
23 | }
24 |
25 | @Test(expected = IllegalArgumentException)
26 | void testMustSupplyPassword() {
27 | KeyStoreCertificateSource keyStoreCertificateSource = new KeyStoreCertificateSource(mockKeyStore, "privatekey", null)
28 | keyStoreCertificateSource.load()
29 | }
30 |
31 | @Test(expected = IllegalArgumentException)
32 | void testMustSupplyPrivateKeyAlias() {
33 | KeyStoreCertificateSource keyStoreCertificateSource = new KeyStoreCertificateSource(mockKeyStore, null, "password")
34 | keyStoreCertificateSource.load()
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/groovy/com/browserup/bup/mitm/tools/ECKeyGeneratorTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.tools
6 |
7 | import com.browserup.bup.mitm.keys.ECKeyGenerator
8 | import org.junit.Test
9 |
10 | import java.security.KeyPair
11 |
12 | import static org.junit.Assert.assertNotNull
13 |
14 | class ECKeyGeneratorTest {
15 | @Test
16 | void testGenerateWithDefaults() {
17 | ECKeyGenerator keyGenerator = new ECKeyGenerator()
18 | KeyPair keyPair = keyGenerator.generate()
19 |
20 | assertNotNull(keyPair)
21 | }
22 |
23 | @Test
24 | void testGenerateWithExplicitNamedCurve() {
25 | ECKeyGenerator keyGenerator = new ECKeyGenerator("secp384r1")
26 | KeyPair keyPair = keyGenerator.generate()
27 |
28 | assertNotNull(keyPair)
29 | // not much else to verify, other than successful generation
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/groovy/com/browserup/bup/mitm/tools/RSAKeyGeneratorTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.tools
6 |
7 | import com.browserup.bup.mitm.keys.RSAKeyGenerator
8 | import org.junit.Test
9 |
10 | import java.security.KeyPair
11 |
12 | import static org.junit.Assert.assertNotNull
13 |
14 | class RSAKeyGeneratorTest {
15 | @Test
16 | void testGenerateWithDefaults() {
17 | RSAKeyGenerator keyGenerator = new RSAKeyGenerator()
18 | KeyPair keyPair = keyGenerator.generate()
19 |
20 | assertNotNull(keyPair)
21 | }
22 |
23 | @Test
24 | void testGenerateWithExplicitKeySize() {
25 | RSAKeyGenerator keyGenerator = new RSAKeyGenerator(1024)
26 | KeyPair keyPair = keyGenerator.generate()
27 |
28 | assertNotNull(keyPair)
29 | // not much else to verify, other than successful generation
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/example/CustomCAKeyStoreExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.example;
6 |
7 | import com.browserup.bup.mitm.KeyStoreFileCertificateSource;
8 | import com.browserup.bup.mitm.manager.ImpersonatingMitmManager;
9 | import org.littleshoot.proxy.HttpProxyServer;
10 | import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
11 |
12 | import java.io.File;
13 |
14 | /**
15 | * This example creates an ImpersonatingMitmManager which loads the CA Root Certificate and Private Key
16 | * from a custom KeyStore.
17 | */
18 | public class CustomCAKeyStoreExample {
19 | public static void main(String[] args) {
20 | // load the root certificate and private key from an existing KeyStore
21 | KeyStoreFileCertificateSource fileCertificateSource = new KeyStoreFileCertificateSource(
22 | "PKCS12", // KeyStore type. for .jks files (Java KeyStore), use "JKS"
23 | new File("/path/to/my/keystore.p12"),
24 | "keyAlias", // alias of the private key in the KeyStore; if you did not specify an alias when creating it, use "1"
25 | "keystorePassword");
26 |
27 |
28 | // tell the MitmManager to use the custom certificate and private key
29 | ImpersonatingMitmManager mitmManager = ImpersonatingMitmManager.builder()
30 | .rootCertificateSource(fileCertificateSource)
31 | .build();
32 |
33 | // tell the HttpProxyServerBootstrap to use the new MitmManager
34 | HttpProxyServer proxyServer = DefaultHttpProxyServer.bootstrap()
35 | .withManInTheMiddle(mitmManager)
36 | .start();
37 |
38 | // make your requests to the proxy server
39 | //...
40 |
41 | proxyServer.abort();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/example/CustomCAPemFileExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.example;
6 |
7 | import com.browserup.bup.mitm.PemFileCertificateSource;
8 | import com.browserup.bup.mitm.manager.ImpersonatingMitmManager;
9 | import org.littleshoot.proxy.HttpProxyServer;
10 | import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
11 |
12 | import java.io.File;
13 |
14 | /**
15 | * This example creates an ImpersonatingMitmManager which loads the CA Root Certificate and Private Key
16 | * from a PEM-encoded certificate and a PEM-encoded private key file.
17 | */
18 | public class CustomCAPemFileExample {
19 | public static void main(String[] args) {
20 | // load the root certificate and private key from existing PEM-encoded certificate and private key files
21 | PemFileCertificateSource fileCertificateSource = new PemFileCertificateSource(
22 | new File("/path/to/my/certificate.cer"), // the PEM-encoded certificate file
23 | new File("/path/to/my/private-key.pem"), // the PEM-encoded private key file
24 | "privateKeyPassword"); // the password for the private key -- can be null if the private key is not encrypted
25 |
26 |
27 | // tell the MitmManager to use the custom certificate and private key
28 | ImpersonatingMitmManager mitmManager = ImpersonatingMitmManager.builder()
29 | .rootCertificateSource(fileCertificateSource)
30 | .build();
31 |
32 | // tell the HttpProxyServerBootstrap to use the new MitmManager
33 | HttpProxyServer proxyServer = DefaultHttpProxyServer.bootstrap()
34 | .withManInTheMiddle(mitmManager)
35 | .start();
36 |
37 | // make your requests to the proxy server
38 | //...
39 |
40 | proxyServer.abort();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/example/LittleProxyDefaultConfigExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.example;
6 |
7 | import com.browserup.bup.mitm.manager.ImpersonatingMitmManager;
8 | import org.littleshoot.proxy.HttpProxyServer;
9 | import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
10 |
11 | /**
12 | * This example creates an ImpersonatingMitmManager with all-default settings:
13 | * - Dynamically-generated CA Root Certificate and Private Key (2048-bit RSA. SHA512 signature)
14 | * - Server certificate impersonation by domain name (2048-bit RSA, SHA512 signature)
15 | * - Default Java trust store (upstream servers' certificates validated against Java's trusted CAs)
16 | */
17 | public class LittleProxyDefaultConfigExample {
18 | public static void main(String[] args) {
19 | // initialize an MitmManager with default settings
20 | ImpersonatingMitmManager mitmManager = ImpersonatingMitmManager.builder().build();
21 |
22 | // to save the generated CA certificate for installation in a browser, see SaveGeneratedCAExample.java
23 |
24 | // tell the HttpProxyServerBootstrap to use the new MitmManager
25 | HttpProxyServer proxyServer = DefaultHttpProxyServer.bootstrap()
26 | .withManInTheMiddle(mitmManager)
27 | .start();
28 |
29 | // make your requests to the proxy server
30 | //...
31 |
32 | proxyServer.abort();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/example/SaveGeneratedCAExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.example;
6 |
7 | import com.browserup.bup.mitm.RootCertificateGenerator;
8 | import com.browserup.bup.mitm.manager.ImpersonatingMitmManager;
9 | import org.littleshoot.proxy.HttpProxyServer;
10 | import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
11 |
12 | import java.io.File;
13 |
14 | /**
15 | * This example creates an ImpersonatingMitmManager with all-default settings and saves the dynamically generated
16 | * CA Root Certificate as a PEM file for installation in a browser.
17 | */
18 | public class SaveGeneratedCAExample {
19 | public static void main(String[] args) {
20 | // create a dynamic CA root certificate generator using default settings (2048-bit RSA keys)
21 | RootCertificateGenerator rootCertificateGenerator = RootCertificateGenerator.builder().build();
22 |
23 | // save the dynamically-generated CA root certificate for installation in a browser
24 | rootCertificateGenerator.saveRootCertificateAsPemFile(new File("/tmp/my-dynamic-ca.cer"));
25 |
26 | // tell the MitmManager to use the root certificate we just generated
27 | ImpersonatingMitmManager mitmManager = ImpersonatingMitmManager.builder()
28 | .rootCertificateSource(rootCertificateGenerator)
29 | .build();
30 |
31 | // tell the HttpProxyServerBootstrap to use the new MitmManager
32 | HttpProxyServer proxyServer = DefaultHttpProxyServer.bootstrap()
33 | .withManInTheMiddle(mitmManager)
34 | .start();
35 |
36 | // make your requests to the proxy server
37 | //...
38 |
39 | proxyServer.abort();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/java/com/browserup/bup/mitm/test/util/CertificateTestUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.mitm.test.util;
6 |
7 | import com.browserup.bup.mitm.CertificateAndKey;
8 |
9 | import java.security.PrivateKey;
10 | import java.security.cert.X509Certificate;
11 |
12 | import static org.junit.Assert.assertEquals;
13 | import static org.junit.Assert.assertNotNull;
14 |
15 | /**
16 | * Utility methods for X.509 certificate verification in unit tests.
17 | */
18 | public class CertificateTestUtil {
19 | /**
20 | * Asserts that the specified {@link CertificateAndKey} contains an RSA private key and an X.509 certificate
21 | * with CN="littleproxy-test" and O="LittleProxy test".
22 | */
23 | public static void verifyTestRSACertWithCNandO(CertificateAndKey certificateAndKey) {
24 | X509Certificate certificate = certificateAndKey.getCertificate();
25 | assertNotNull(certificate);
26 | assertNotNull(certificate.getIssuerDN());
27 | assertEquals("CN=littleproxy-test, O=LittleProxy test", certificate.getIssuerDN().getName());
28 |
29 | PrivateKey privateKey = certificateAndKey.getPrivateKey();
30 | assertNotNull(privateKey);
31 | assertEquals("RSA", privateKey.getAlgorithm());
32 | }
33 |
34 | /**
35 | * Asserts that the specified {@link CertificateAndKey} contains an RSA private key and an X.509 certificate
36 | * with CN="littleproxy-test".
37 | */
38 | public static void verifyTestRSACertWithCN(CertificateAndKey certificateAndKey) {
39 | X509Certificate certificate = certificateAndKey.getCertificate();
40 | assertNotNull(certificate);
41 | assertNotNull(certificate.getIssuerDN());
42 | assertEquals("CN=littleproxy-test", certificate.getIssuerDN().getName());
43 |
44 | PrivateKey privateKey = certificateAndKey.getPrivateKey();
45 | assertNotNull(privateKey);
46 | assertEquals("RSA", privateKey.getAlgorithm());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/certificate.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDPzCCAiegAwIBAgIJALPOOC+0RqAQMA0GCSqGSIb3DQEBCwUAMDYxGTAXBgNV
3 | BAoMEExpdHRsZVByb3h5IHRlc3QxGTAXBgNVBAMMEGxpdHRsZXByb3h5LXRlc3Qw
4 | HhcNMTUxMjE4MDIxMDI4WhcNMjUxMjE1MDIxMDI4WjA2MRkwFwYDVQQKDBBMaXR0
5 | bGVQcm94eSB0ZXN0MRkwFwYDVQQDDBBsaXR0bGVwcm94eS10ZXN0MIIBIjANBgkq
6 | hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2vcm/qETdg92EjYka3Zt+UEraLKzTovz
7 | gvVx4F0EmCC3KDU2v2+WeX4wmVjP6qtMr6nJOSYkFedAvIRGi7hbf3JKQ1nqhH1q
8 | U2zP9HXNt+/LCw8kOFJFii9cp6/h8OnlF8hoIWz4lRTMMcjoiBzV5vfyTb2zWE0l
9 | 1DXGypKTxjqg8Pd/tqsMl2uc4+xnEL/ZK9cK8wxg0suUqaGQRaX2R3SovbFKZ1c3
10 | VApS8zHksSm6qQStbisuEEHSYLpFCrMnXsLJ9KfzTUDwBqrKaMyDAEjoS2LpoijF
11 | YalTW3bF721GiYl2GtcwCIzqpHcIbHAPn1PxQY4UHUt3z4YSjTsuXwIDAQABo1Aw
12 | TjAdBgNVHQ4EFgQUElRcE71sJsuWUVOyYALgQQhPHUUwHwYDVR0jBBgwFoAUElRc
13 | E71sJsuWUVOyYALgQQhPHUUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
14 | AQEArU29g5/V5rywfQizo5J/XEbWjfN0zvuFithS7Zc2OqrSKV8c3NY6NdER/0jj
15 | CmhohnUkduMW+/bizWcuiyt5KDwg6Ar2kEXYY0YgOLbxTmoNvBG84zO+54BV0qy7
16 | 16D8ItrPbcIn83eW8TXug1dWISxWhVRIpHdH2Ok4/XDRFgTxORsC08v2OwwQ566g
17 | PqphR6eIJN8MwThcT9D9rv0HcX9esBJJlNc9OigB9T3O2Xg7+qPJtgqktkN8vlTb
18 | Co0BWoR43xVPTNam533ioUX7woUWnlsQtclN//vazr+uofJ8jnHjpAkh9gZ/l6kn
19 | AdZVrExA+SSUqtWgk9cD0WGSEQ==
20 | -----END CERTIFICATE-----
21 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/encrypted-private-key.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | Proc-Type: 4,ENCRYPTED
3 | DEK-Info: AES-256-CBC,2D5055AA227DC3421AEBE5C8480F57B1
4 |
5 | VZnrQPjan9fUvkJVKwJrJLWqWx7qgw9M8eeqZoqjrueZLNFu74mp2qbKeJ4hkbqf
6 | dBvMuBaSaqrS2SxfHf/T8uZg+K0vMB0hH+1pVt+AtJRYLybQLmjZSnU/8CDEp358
7 | 59FX5rYFvMRD3fUkESWeQSlSDuE/YG5YlqmxnSVOKEmAQQ0QTGEDIDKl77gRrg7r
8 | mr6ey8NgW2OBaJvLbXLAldHd2lBlj/NH7sXwWq1LgbF/CMm5LLtIEMkOSZ5jgFvU
9 | UqMOTTSGrhtPa4vvy1m8XFx9Z33usi/mEvXQpVeLCmE4BQkS7rSMV1E/ETVkzsfF
10 | wq3c6cWNmh/JvPYUIa6dXjDZPwCz/WpVH7fVwTqBkBTbTUuIJSP//jJB7npZoQrE
11 | rfpdJ9eX9QAjbFI6goYnc4SVWhpzR9LDSk9mpEikGysN8yDYabKbl0OzT9KovGn0
12 | CLKYxo2LQBwGJR171y5yyC/3s39b9pPC6JQAzji4S7uJQjayYx8Yv3xb1f+4t2Xa
13 | /3M46QtAUJMGAqdmpTXhvNzPyGzJFK1gwNoUf6oM/Vww8KRvVNJTfPljEARxTyRO
14 | jzan4Dd5jtSqw87E2b76ECrj92C7qp3iC/4zkkCHTulPMjwvIzY9WQ2wx1qyVy9B
15 | 4qwat9h90AnrAX9q6kvDTglD3n605vgU6P/u1PCzTsTLT1DL5OyMfT3MVSS/MyNs
16 | SKLx5vJh93aq7EyWurWVCzUfYDIFngb+WFINEGb2XYFD3Ah/y5D6kD24vooATgFJ
17 | KQBQdCBWWjZbYS4nZUTOSJqSMp5V/RzjjKr9QpCKpXLvxwfQ9ME6MaobgfUSy1er
18 | S+btHNItD/xA7/rO/eAfmlkFLJgGi6cfvnyBxHsR7+/T5yDyZAPbDwp8kErxFFeY
19 | xqQmY6hvaSiQXek23AIiTOCuzyYluMsTnxRfQGlL/A77R+t7gJv5in0FPQqHzD1T
20 | h5V4fIBcpOSmc6Qk7U7vYNi3AyvpWDsr03E+bNlY5dzNguxsO9QzJMWGd17VZiwc
21 | Q2qkKxl5JC0c3h4mYh4e3V5C0c9z32ffYS6sICsNaAw0r8C2svULBCtm29oDDc5X
22 | oC5EzfZb5vG9qpQ8H/LE2I215YOwsvmda9gdpnxrbk4y8MlSMOJwMXVYGKNSEg2h
23 | wWPo/4qsNV8hX7IlOYPOnVRCzpjCWTc2CzvhHISxv1CrXKV0D2qAxkX/ezRYsaiE
24 | T7E0K5kyXquVjhjnUTMjpOc/LM2bQ9v0lmmJIcnJFSlCTS5+DvUrngYSnqfyPgkS
25 | 7dbSuW8E1UusxnY8664snWugxCLB4E0PacKTr+0E77qukFAE02j8hwHbn+TplWaH
26 | jOVSyLicsqwi0TTxWoWk/fTk6StSGVuUTaPPoz6gkrN3H01V8vhcx/PPqWWbfjjz
27 | yGqOm6pXXaNwPYjgQUWFPc3QHOaPbTAl1Y4teCaAqnSDlEBYqDUGK0gSMAQ/vgdC
28 | uvUAGctb2Kikp4sQcvzKRHsStHrHDVdeum842r5zyHKMuEbhTGjmDR70FknpDaoS
29 | vQIfgasKqXjRKgQfSSiGTX5CsvYvSRqFSD4qDbQbYnR0XMNphJxK/3rWP86oEXk1
30 | -----END RSA PRIVATE KEY-----
31 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/keystore.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/browserup/browserup-proxy/0f28ec6e8f1423e1fdb014fded72e9278bdd083f/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/keystore.jks
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/keystore.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/browserup/browserup-proxy/0f28ec6e8f1423e1fdb014fded72e9278bdd083f/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/keystore.p12
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/trusted-cert.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/browserup/browserup-proxy/0f28ec6e8f1423e1fdb014fded72e9278bdd083f/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/trusted-cert.jks
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/resources/com/browserup/bup/mitm/unencrypted-private-key.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEA2vcm/qETdg92EjYka3Zt+UEraLKzTovzgvVx4F0EmCC3KDU2
3 | v2+WeX4wmVjP6qtMr6nJOSYkFedAvIRGi7hbf3JKQ1nqhH1qU2zP9HXNt+/LCw8k
4 | OFJFii9cp6/h8OnlF8hoIWz4lRTMMcjoiBzV5vfyTb2zWE0l1DXGypKTxjqg8Pd/
5 | tqsMl2uc4+xnEL/ZK9cK8wxg0suUqaGQRaX2R3SovbFKZ1c3VApS8zHksSm6qQSt
6 | bisuEEHSYLpFCrMnXsLJ9KfzTUDwBqrKaMyDAEjoS2LpoijFYalTW3bF721GiYl2
7 | GtcwCIzqpHcIbHAPn1PxQY4UHUt3z4YSjTsuXwIDAQABAoIBAB/Opyt12o3b0Rr0
8 | InY5zd/XR6b9zm4qhkUPwmsFGBXBKtn8YOeOHh2n5wdfj1RXbdxWnZRfpf5IiW7Z
9 | CCZjsWbiA0elWBvG3BsiQ1MPicKeYrBIkspbqR5Zouv48Kk+ULkTs4ynd7SwQLk6
10 | pgyfo7LZcak5VUQOcOBSr33drPmuZcTyozuEs+XmOaUIH9SHr5dLP3mysb7dEZQS
11 | gaHMR1a3BQQrQk9H5oVVU0kI0iqqX5NltiWodl3shUHqlXrlCEop+RxHhkfBgz8H
12 | w4MlyFSiYrrzTyL7yTkMa6JTcP0s4oNH2E+foIMyf46z/lxH7Nk0bg4pmsfXb0o7
13 | bKqJzAECgYEA8kRvRpDB9z6ddQkJ1I++fGh8vJMUuB6MNlS7Shhp6ClHQwdUK80f
14 | dpWT8CxIOX6sKJgm9HGbxaPxn7RnYc4v+M0L/QsPU8RGfVggNvQ9xQEaocp3CD9D
15 | TUeZUtTcTmKd86h9ICjlkbtF2coKNcIfM3teVtGnMKjf5VowupYyzj8CgYEA52CU
16 | 6Su4ewgTcEPRqWWyg/GHTPN8TJaXjutgvhnt7w8po8xMmIK1qSeOP4paF/UOuGsT
17 | rX6IoXmSzSz5MkFkjGLBd/wUd4p9YQbgjtv/lv52XBZ8mqffjDGTGl/n0r803yMH
18 | So7Fup9f8kXkgw+vszxzCqnHq3usx1WjCKNj1+ECgYAT1wTh24L283rDldznOmpY
19 | F9p3OvhMZ7wFywSXec5ag97hH12GRMMZ3AAEgCveAYCpxmQSSqd+FQH5mTWKLe+B
20 | yZD8xQYZTw6Svz/MIE5ars92hnUfCMdDMeTdgq8UAEF9LcQpeQ/r0lFTF5ekdWRG
21 | vAiqxXqSopHLX4p0DU7V0wKBgGi16c44Tg3H0tw8pPbPomFZ/gxSKM+UW1R/q1F8
22 | 9JP6vbJ2M7fVd5bs4tBYsXskGRxWwRoEKJtDJK+cCc63j2SFEN9XAoAy+ZjefuPI
23 | JjxUPoZgWtW24VFV4ifOfWB/zdKpzJPuVwelNsuy276Aa9hmo/2QZl9x4fh4BgdT
24 | wkyhAoGBAKrzqA0+kotqocA9cT7GuJb7mfjewXZx1jztQMC5mHs+L/tRGL85dZZk
25 | 5hK8Rtessw5TKmfA53bKbOEklEcsjSNWgIq3wYjJVtBDUvcmA2Hgm3psjUCrl1iv
26 | h/31bf05fYaWFFEeuHE/Pz5ev8ecY8gsKtX63HVVWLYtDxKnYuXk
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/browserup-proxy-mitm/src/test/resources/log4j2-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "configuration" : {
3 | "name": "test",
4 | "appenders": {
5 | "Console": {
6 | "name": "console",
7 | "target": "SYSTEM_OUT",
8 | "PatternLayout": {
9 | "pattern": "%-7r %date %level [%thread] %logger - %msg%n"
10 | }
11 | }
12 | },
13 |
14 | "loggers": {
15 | "root": {
16 | "level": "info",
17 | "appender-ref": {
18 | "ref": "console"
19 | }
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/main/resources/openapi-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "resourcePackages" : [
3 | "com.browserup.bup.rest.resource"
4 | ],
5 | "openapi" : "3.0.1",
6 | "info": {
7 | "version": "1.0",
8 | "title": "BrowserUp Proxy API",
9 | "description": "BrowserUp Proxy API",
10 | "contact": {
11 | "email": "hello@browserup.com"
12 | },
13 | "license": {
14 | "name": "Apache 2.0",
15 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/javascript/.gitignore:
--------------------------------------------------------------------------------
1 | client/
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/javascript/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:8.16.0-alpine
2 |
3 | USER root
4 |
5 | WORKDIR /
6 |
7 | COPY ./client/ /client/
8 |
9 | # Build javascript client, install locally
10 | WORKDIR /client/
11 | RUN rm -rf node_modules/
12 | RUN npm install
13 | RUN npm link
14 | RUN npm link /client
15 | RUN npm run build
16 |
17 | COPY . /javascript/
18 | WORKDIR /javascript/
19 |
20 | CMD ["node", "test/javascript_test.js"]
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/javascript/test/javascript_test.js:
--------------------------------------------------------------------------------
1 | var BrowserUpProxyApi = require('/client/node_modules/browser_up_proxy_api');
2 |
3 |
4 | var api = new BrowserUpProxyApi.DefaultApi()
5 | api.apiClient.basePath = 'http://' + process.env.PROXY_REST_HOST + ':' + process.env.PROXY_REST_PORT
6 | var port = process.env.PROXY_PORT;
7 | var urlPattern = ".*";
8 | var callback = function(error, data, response) {
9 | if (error) {
10 | console.error('Error while calling API: ' + JSON.stringify(error));
11 | throw new Error(error);
12 | } else {
13 | console.log('API called successfully. Returned data: ' + JSON.stringify(data));
14 | }
15 | };
16 | api.entries(port, urlPattern, callback);
17 |
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/python/.gitignore:
--------------------------------------------------------------------------------
1 | client/
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/python/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:2.7-alpine
2 |
3 | WORKDIR /
4 |
5 | COPY client/ /python-client/
6 |
7 | # Build python client, install locally
8 | WORKDIR /python-client/
9 | RUN python setup.py install --user
10 | RUN pip install -r requirements.txt
11 | RUN pip install -r test-requirements.txt
12 |
13 | COPY . /python/
14 | WORKDIR /python/
15 |
16 | CMD ["python", "test/python_test.py"]
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/python/test/python_test.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import time
3 | import openapi_client
4 | import os
5 |
6 | from openapi_client.rest import ApiException
7 | from pprint import pprint
8 |
9 | # Create an instance of the API class
10 | api_client = openapi_client.ApiClient()
11 | api_client.configuration.host = 'http://' + os.environ['PROXY_REST_HOST'] + ':' + os.environ['PROXY_REST_PORT']
12 |
13 | api_instance = openapi_client.DefaultApi(api_client)
14 | port = os.environ['PROXY_PORT']
15 | url_pattern = '.*'
16 |
17 | try:
18 | api_response = api_instance.entries(port, url_pattern)
19 | pprint(api_response)
20 | except ApiException as e:
21 | print("Exception when calling DefaultApi->entries: %s\n" % e)
22 | raise
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/resources/log4j2-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "configuration" : {
3 | "name": "test",
4 | "appenders": {
5 | "Console": {
6 | "name": "console",
7 | "target": "SYSTEM_OUT",
8 | "PatternLayout": {
9 | "pattern": "%-7r %date %level [%thread] %logger - %msg%n"
10 | }
11 | }
12 | },
13 |
14 | "loggers": {
15 | "logger": [
16 | {
17 | "name": "org.testcontainers",
18 | "level": "warn",
19 | "additivity": false,
20 | "AppenderRef": {
21 | "ref": "console"
22 | }
23 | },
24 | {
25 | "name": "com.github.dockerjava",
26 | "level": "warn",
27 | "additivity": false,
28 | "AppenderRef": {
29 | "ref": "console"
30 | }
31 | }
32 | ],
33 | "root": {
34 | "level": "info",
35 | "appender-ref": {
36 | "ref": "console"
37 | }
38 | }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/ruby/.gitignore:
--------------------------------------------------------------------------------
1 | client/
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/ruby/.rspec:
--------------------------------------------------------------------------------
1 | --color
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/ruby/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ruby:2.5
2 |
3 | RUN bundle config --global frozen 1
4 |
5 | WORKDIR /
6 |
7 | COPY ./client/ /ruby-client/
8 |
9 | # Build ruby client gem, install locally
10 | WORKDIR /ruby-client/
11 | RUN gem build openapi_client.gemspec
12 | RUN gem install ./openapi_client-1.0.0.gem
13 |
14 | COPY . /ruby/
15 | WORKDIR /ruby/
16 |
17 | RUN gem install bundler
18 | RUN bundle update --bundler
19 | RUN bundle config --delete frozen
20 | RUN bundle install
21 |
22 | CMD ["bundle", "exec", "rspec", "--backtrace"]
23 |
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/ruby/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | group :development, :test do
4 | gem 'rake', '~> 13.0.1'
5 | gem 'pry-byebug'
6 | gem 'json', '~> 2.4.0'
7 | gem 'rspec', '~> 3.10'
8 | gem 'rubocop', '~> 1.6.1'
9 | gem 'openapi_client', '~> 1.0.0'
10 | end
11 |
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/ruby/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | ast (2.4.1)
5 | byebug (11.1.3)
6 | coderay (1.1.3)
7 | diff-lcs (1.4.4)
8 | ethon (0.12.0)
9 | ffi (>= 1.3.0)
10 | ffi (1.13.1)
11 | json (2.4.0)
12 | method_source (1.0.0)
13 | openapi_client (1.0.0)
14 | json (~> 2.1, >= 2.1.0)
15 | typhoeus (~> 1.0, >= 1.0.1)
16 | parallel (1.20.1)
17 | parser (2.7.2.0)
18 | ast (~> 2.4.1)
19 | pry (0.13.1)
20 | coderay (~> 1.1)
21 | method_source (~> 1.0)
22 | pry-byebug (3.9.0)
23 | byebug (~> 11.0)
24 | pry (~> 0.13.0)
25 | rainbow (3.0.0)
26 | rake (13.0.1)
27 | regexp_parser (2.0.0)
28 | rexml (3.2.4)
29 | rspec (3.10.0)
30 | rspec-core (~> 3.10.0)
31 | rspec-expectations (~> 3.10.0)
32 | rspec-mocks (~> 3.10.0)
33 | rspec-core (3.10.0)
34 | rspec-support (~> 3.10.0)
35 | rspec-expectations (3.10.0)
36 | diff-lcs (>= 1.2.0, < 2.0)
37 | rspec-support (~> 3.10.0)
38 | rspec-mocks (3.10.0)
39 | diff-lcs (>= 1.2.0, < 2.0)
40 | rspec-support (~> 3.10.0)
41 | rspec-support (3.10.0)
42 | rubocop (1.6.1)
43 | parallel (~> 1.10)
44 | parser (>= 2.7.1.5)
45 | rainbow (>= 2.2.2, < 4.0)
46 | regexp_parser (>= 1.8, < 3.0)
47 | rexml
48 | rubocop-ast (>= 1.2.0, < 2.0)
49 | ruby-progressbar (~> 1.7)
50 | unicode-display_width (>= 1.4.0, < 2.0)
51 | rubocop-ast (1.3.0)
52 | parser (>= 2.7.1.5)
53 | ruby-progressbar (1.10.1)
54 | typhoeus (1.4.0)
55 | ethon (>= 0.9.0)
56 | unicode-display_width (1.7.0)
57 |
58 | PLATFORMS
59 | ruby
60 |
61 | DEPENDENCIES
62 | json (~> 2.4.0)
63 | openapi_client (~> 1.0.0)
64 | pry-byebug
65 | rake (~> 13.0.1)
66 | rspec (~> 3.10)
67 | rubocop (~> 1.6.1)
68 |
69 | BUNDLED WITH
70 | 2.1.4
71 |
--------------------------------------------------------------------------------
/browserup-proxy-rest-clients/src/test/ruby/spec/test_client_spec.rb:
--------------------------------------------------------------------------------
1 | require 'openapi_client'
2 |
3 | describe OpenapiClient do
4 | it 'connects to api' do
5 | proxy_rest_host = ENV["PROXY_REST_HOST"]
6 | proxy_rest_port = ENV["PROXY_REST_PORT"]
7 | proxy_port = ENV["PROXY_PORT"]
8 |
9 | p "Using the following env variables:"
10 | p "PROXY_REST_HOST = #{proxy_rest_host}"
11 | p "PROXY_REST_PORT = #{proxy_rest_port}"
12 | p "PROXY_PORT = #{proxy_port}"
13 |
14 | api_instance = OpenapiClient::DefaultApi.new
15 | api_instance.api_client.config.host = "#{proxy_rest_host}:#{proxy_rest_port}"
16 | port = proxy_port
17 | url_pattern = '^.*$'
18 |
19 | begin
20 | entries_response = api_instance.entries(port, url_pattern).to_json
21 | p "Got the following entries in the response: #{entries_response}"
22 | rescue OpenapiClient::ApiError => e
23 | puts "Exception when calling DefaultApi->entries: #{e}"
24 | raise
25 | end
26 | end
27 | end
--------------------------------------------------------------------------------
/browserup-proxy-rest/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | browserup-proxy-rest
4 | Project browserup-proxy-rest created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.buildship.core.gradleprojectbuilder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.buildship.core.gradleprojectnature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/exception/JavascriptCompilationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.exception;
6 |
7 | import com.google.sitebricks.headless.Request;
8 | import com.browserup.bup.filters.JavascriptRequestResponseFilter;
9 |
10 | /**
11 | * Indicates that an error occurred when compiling javascript in {@link JavascriptRequestResponseFilter},
12 | * for use by {@link com.browserup.bup.proxy.bricks.ProxyResource#addRequestFilter(int, Request)}
13 | * or {@link com.browserup.bup.proxy.bricks.ProxyResource#addResponseFilter(int, Request)}.
14 | */
15 | public class JavascriptCompilationException extends RuntimeException {
16 | public JavascriptCompilationException() {
17 | super();
18 | }
19 |
20 | public JavascriptCompilationException(String message) {
21 | super(message);
22 | }
23 |
24 | public JavascriptCompilationException(String message, Throwable cause) {
25 | super(message, cause);
26 | }
27 |
28 | public JavascriptCompilationException(Throwable cause) {
29 | super(cause);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/exception/ProxyExistsException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.exception;
6 |
7 | public class ProxyExistsException extends RuntimeException {
8 | private static final long serialVersionUID = -5515796684778166504L;
9 |
10 | private final int port;
11 |
12 | public ProxyExistsException(int port) {
13 | this.port = port;
14 | }
15 |
16 | public ProxyExistsException(String message, int port) {
17 | super(message);
18 | this.port = port;
19 | }
20 |
21 | public ProxyExistsException(String message, Throwable cause, int port) {
22 | super(message, cause);
23 | this.port = port;
24 | }
25 |
26 | public ProxyExistsException(Throwable cause, int port) {
27 | super(cause);
28 | this.port = port;
29 | }
30 |
31 | public int getPort() {
32 | return port;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/exception/ProxyPortsExhaustedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.exception;
6 |
7 | public class ProxyPortsExhaustedException extends RuntimeException {
8 | private static final long serialVersionUID = -6801448612785792233L;
9 |
10 | public ProxyPortsExhaustedException() {
11 | super();
12 | }
13 |
14 | public ProxyPortsExhaustedException(String message, Throwable cause) {
15 | super(message, cause);
16 | }
17 |
18 | public ProxyPortsExhaustedException(String message) {
19 | super(message);
20 | }
21 |
22 | public ProxyPortsExhaustedException(Throwable cause) {
23 | super(cause);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/proxy/guice/JettyModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.guice;
6 |
7 | import com.google.inject.Binder;
8 | import com.google.inject.Module;
9 | import org.eclipse.jetty.server.Server;
10 |
11 | public class JettyModule implements Module {
12 | @Override
13 | public void configure(Binder binder) {
14 | binder.bind(Server.class).toProvider(JettyServerProvider.class);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/proxy/guice/NamedImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.guice;
6 |
7 | import com.google.inject.name.Named;
8 |
9 | import java.lang.annotation.Annotation;
10 |
11 | public class NamedImpl implements Named {
12 | final String value;
13 |
14 | public NamedImpl(String value) {
15 | this.value = value == null ? "name" : value;
16 | }
17 |
18 | public String value() {
19 | return this.value;
20 | }
21 |
22 | public int hashCode() {
23 | // This is specified in java.lang.Annotation.
24 | return 127 * "value".hashCode() ^ value.hashCode();
25 | }
26 |
27 | public boolean equals(Object o) {
28 | if (!(o instanceof Named)) {
29 | return false;
30 | }
31 |
32 | Named other = (Named) o;
33 | return value.equals(other.value());
34 | }
35 |
36 | public String toString() {
37 | return "@" + Named.class.getName() + "(value=" + value + ")";
38 | }
39 |
40 | public Class extends Annotation> annotationType() {
41 | return Named.class;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/rest/filter/LoggingFilter.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.rest.filter;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import javax.ws.rs.container.ContainerRequestContext;
7 | import javax.ws.rs.container.ContainerRequestFilter;
8 |
9 | public class LoggingFilter implements ContainerRequestFilter {
10 | private static final Logger LOG = LoggerFactory.getLogger(LoggingFilter.class);
11 |
12 | @Override
13 | public void filter(ContainerRequestContext requestContext) {
14 | LOG.info(String.format("%s /%s", requestContext.getMethod().toUpperCase(), requestContext.getUriInfo().getPath()));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/NotBlankConstraint.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.rest.validation;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.validation.Constraint;
7 | import javax.validation.ConstraintValidator;
8 | import javax.validation.ConstraintValidatorContext;
9 | import javax.validation.Payload;
10 |
11 | import com.browserup.bup.rest.validation.util.MessageSanitizer;
12 | import org.apache.commons.lang3.StringUtils;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 |
16 | @Retention(RetentionPolicy.RUNTIME)
17 | @Constraint(validatedBy = { NotBlankConstraint.NotBlankValidator.class })
18 | public @interface NotBlankConstraint {
19 |
20 | String message() default "";
21 |
22 | String paramName() default "";
23 |
24 | Class>[] groups() default {};
25 |
26 | Class extends Payload>[] payload() default {};
27 |
28 | class NotBlankValidator implements ConstraintValidator {
29 | private static final Logger LOG = LoggerFactory.getLogger(NotBlankValidator.class);
30 |
31 | @Override
32 | public void initialize(NotBlankConstraint constraintAnnotation) {
33 | }
34 |
35 | @Override
36 | public boolean isValid(Object value, ConstraintValidatorContext context) {
37 | if (value != null && StringUtils.isNotEmpty(String.valueOf(value))) {
38 | return true;
39 | }
40 |
41 | String escapedValue = MessageSanitizer.escape(value == null ? null : value.toString());
42 | String errorMessage = String.format("Expected not empty value, got '%s'", escapedValue);
43 | LOG.warn(errorMessage);
44 |
45 | context.buildConstraintViolationWithTemplate(errorMessage).addConstraintViolation();
46 | return false;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/NotNullConstraint.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.rest.validation;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | import javax.validation.Constraint;
7 | import javax.validation.ConstraintValidator;
8 | import javax.validation.ConstraintValidatorContext;
9 | import javax.validation.Payload;
10 |
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Constraint(validatedBy = { NotNullConstraint.NotNullValidator.class })
16 | public @interface NotNullConstraint {
17 |
18 | String message() default "";
19 |
20 | String paramName() default "";
21 |
22 | Class>[] groups() default {};
23 |
24 | Class extends Payload>[] payload() default {};
25 |
26 | class NotNullValidator implements ConstraintValidator {
27 | private static final Logger LOG = LoggerFactory.getLogger(NotNullValidator.class);
28 |
29 | @Override
30 | public void initialize(NotNullConstraint constraintAnnotation) {
31 | }
32 |
33 | @Override
34 | public boolean isValid(Object value, ConstraintValidatorContext context) {
35 | if (value != null) {
36 | return true;
37 | }
38 | String errorMessage = "Expected not null value";
39 | LOG.warn(errorMessage);
40 |
41 | context.buildConstraintViolationWithTemplate(errorMessage).addConstraintViolation();
42 | return false;
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/PatternConstraint.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.rest.validation;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 | import java.util.regex.Pattern;
6 |
7 | import javax.validation.Constraint;
8 | import javax.validation.ConstraintValidator;
9 | import javax.validation.ConstraintValidatorContext;
10 | import javax.validation.Payload;
11 |
12 | import com.browserup.bup.rest.validation.util.MessageSanitizer;
13 | import org.apache.commons.lang3.StringUtils;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | @Retention(RetentionPolicy.RUNTIME)
18 | @Constraint(validatedBy = { PatternConstraint.PatternValidator.class })
19 | public @interface PatternConstraint {
20 |
21 | String message() default "";
22 |
23 | String paramName() default "";
24 |
25 | Class>[] groups() default {};
26 |
27 | Class extends Payload>[] payload() default {};
28 |
29 | class PatternValidator implements ConstraintValidator {
30 | private static final Logger LOG = LoggerFactory.getLogger(PatternValidator.class);
31 |
32 | @Override
33 | public void initialize(PatternConstraint constraintAnnotation) {
34 | }
35 |
36 | @Override
37 | public boolean isValid(String value, ConstraintValidatorContext context) {
38 | if (StringUtils.isEmpty(value)) {
39 | return true;
40 | }
41 |
42 | try {
43 | Pattern.compile(value);
44 | return true;
45 | } catch (Exception ex) {
46 | String escapedValue = MessageSanitizer.escape(value);
47 | String errorMessage = String.format("URL parameter '%s' is not a valid regexp", escapedValue);
48 | LOG.warn(errorMessage);
49 |
50 | context.buildConstraintViolationWithTemplate(errorMessage).addConstraintViolation();
51 | }
52 | return false;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/mapper/ConstraintViolationExceptionMapper.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.rest.validation.mapper;
2 |
3 | import com.browserup.bup.rest.validation.mapper.model.ConstraintsErrors;
4 | import org.apache.commons.lang3.StringUtils;
5 |
6 | import javax.validation.ConstraintViolation;
7 | import javax.validation.ConstraintViolationException;
8 | import javax.ws.rs.core.MediaType;
9 | import javax.ws.rs.core.Response;
10 | import javax.ws.rs.ext.ExceptionMapper;
11 | import java.util.ArrayList;
12 |
13 | public class ConstraintViolationExceptionMapper implements ExceptionMapper {
14 | private static final String PARAMETER_NAME_ATTRIBUTE = "paramName";
15 |
16 | @Override
17 | public Response toResponse(ConstraintViolationException exception) {
18 | return Response.status(Response.Status.BAD_REQUEST)
19 | .entity(createConstraintErrors(exception))
20 | .type(MediaType.APPLICATION_JSON_TYPE)
21 | .build();
22 | }
23 |
24 | private ConstraintsErrors createConstraintErrors(ConstraintViolationException exception) {
25 | ConstraintsErrors errors = new ConstraintsErrors();
26 | exception.getConstraintViolations().stream()
27 | .filter(v -> StringUtils.isNotEmpty(v.getMessage()))
28 | .forEach(violation -> errors.addError(getArgumentName(violation), violation.getMessage()));
29 |
30 | return errors;
31 | }
32 |
33 | private String getArgumentName(ConstraintViolation> violation) {
34 | String argumentIdentifier;
35 | Object paramName = violation.getConstraintDescriptor().getAttributes().get(PARAMETER_NAME_ATTRIBUTE);
36 | if (paramName instanceof String && paramName.toString().length() > 0) {
37 | argumentIdentifier = (String) paramName;
38 | } else {
39 | argumentIdentifier = StringUtils.substringAfterLast(violation.getPropertyPath().toString(), ".");
40 | }
41 | return argumentIdentifier;
42 | }
43 | }
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/mapper/model/ArgumentConstraintsErrors.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.rest.validation.mapper.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | public class ArgumentConstraintsErrors {
9 | private String name = "";
10 | private List errors = new ArrayList<>();
11 |
12 | public String getName() {
13 | return name;
14 | }
15 |
16 | public void setName(String name) {
17 | this.name = name;
18 | }
19 |
20 | public List getErrors() {
21 | return errors;
22 | }
23 |
24 | public void setErrors(List errors) {
25 | this.errors = errors;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/mapper/model/ConstraintsErrors.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.rest.validation.mapper.model;
2 |
3 | import java.util.*;
4 |
5 | public class ConstraintsErrors {
6 | private List errors = new ArrayList<>();
7 |
8 | public List getErrors() {
9 | return errors;
10 | }
11 |
12 | public void setErrors(List errors) {
13 | this.errors = errors;
14 | }
15 |
16 | private ArgumentConstraintsErrors getErrorsByArgumentName(String argumentName) {
17 | Optional argErrors = this.errors.stream()
18 | .filter(e -> e.getName().equals(argumentName))
19 | .findFirst();
20 | if (!argErrors.isPresent()) {
21 | ArgumentConstraintsErrors newArgErrors = new ArgumentConstraintsErrors();
22 | newArgErrors.setName(argumentName);
23 | errors.add(newArgErrors);
24 | return newArgErrors;
25 | } else {
26 | return argErrors.get();
27 | }
28 | }
29 |
30 | public void addError(String argumentName, String error) {
31 | getErrorsByArgumentName(argumentName).getErrors().add(error);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/java/com/browserup/bup/rest/validation/util/MessageSanitizer.java:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.rest.validation.util;
2 | /*
3 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
4 | * Original from:
5 | * https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/util/InterpolationHelper.java
6 | */
7 | /*
8 | * License: Apache License, Version 2.0
9 | * See the license file in the root directory or .
10 | */
11 |
12 | import java.util.regex.Matcher;
13 | import java.util.regex.Pattern;
14 |
15 | public class MessageSanitizer {
16 |
17 | public static final char BEGIN_CHAR = '{';
18 | public static final char END_CHAR = '}';
19 | public static final char EL_DESIGNATOR = '$';
20 | public static final char ESCAPE_CHARACTER = '\\';
21 |
22 | private static final Pattern ESCAPE_PATTERN = Pattern.compile( "([\\" + ESCAPE_CHARACTER + BEGIN_CHAR + END_CHAR + EL_DESIGNATOR + "])" );
23 |
24 | private MessageSanitizer() {
25 | }
26 |
27 | public static String escape(String message) {
28 | if ( message == null ) {
29 | return null;
30 | }
31 | return ESCAPE_PATTERN.matcher( message ).replaceAll( Matcher.quoteReplacement( String.valueOf( ESCAPE_CHARACTER ) ) + "$1" );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/main/resources/swagger-config.yaml:
--------------------------------------------------------------------------------
1 | resourcePackages:
2 | - com.browserup.bup.rest.resource
3 | prettyPrint: true
4 | readerClass: com.browserup.bup.rest.openapi.CustomOpenApiReader
5 | cacheTTL: 0
6 | openAPI:
7 | info:
8 | version: '1.0'
9 | title: BrowserUp Proxy API
10 | contact:
11 | email: hello@browserup.com
12 | license:
13 | name: Apache 2.0
14 | url: http://www.apache.org/licenses/LICENSE-2.0.html
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/test/groovy/com/browserup/bup/proxy/mitmproxy/BaseRestTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.mitmproxy
2 |
3 | import com.browserup.bup.assertion.model.AssertionResult
4 |
5 | import static org.junit.Assert.*
6 |
7 | abstract class BaseRestTest extends WithRunningProxyRestTest {
8 | protected static final int TARGET_SERVER_RESPONSE_DELAY = 500
9 | protected static final int TARGET_SERVER_SLOW_RESPONSE_DELAY = 1000
10 | protected static final int SUCCESSFUL_ASSERTION_TIME_WITHIN = TARGET_SERVER_RESPONSE_DELAY + 100
11 | protected static final int FAILED_ASSERTION_TIME_WITHIN = TARGET_SERVER_RESPONSE_DELAY - 100
12 | protected static final int MILLISECONDS_BETWEEN_REQUESTS = 50
13 |
14 | abstract String getUrlPath();
15 |
16 | String getFullUrlPath() {
17 | return "/proxy/${proxy.port}/${urlPath}"
18 | }
19 |
20 | static def assertAssertionNotNull(AssertionResult assertion) {
21 | assertNotNull('Expected to get non null assertion result', assertion)
22 | }
23 |
24 | static def assertAssertionPassed(AssertionResult assertion) {
25 | assertTrue("Expected assertion to pass", assertion.passed)
26 | assertFalse("Expected assertion to pass", assertion.failed)
27 | }
28 |
29 | static def assertAssertionFailed(AssertionResult assertion) {
30 | assertFalse("Expected assertion to fail", assertion.passed)
31 | assertTrue("Expected assertion to fail", assertion.failed)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/test/groovy/com/browserup/bup/proxy/mitmproxy/ProxyManagerTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.mitmproxy;
6 |
7 | import com.browserup.bup.BrowserUpProxyServer;
8 | import com.browserup.bup.MitmProxyServer;
9 | import com.browserup.bup.proxy.MitmProxyManager;
10 | import com.browserup.bup.proxy.ProxyManager;
11 | import com.browserup.bup.proxy.guice.ConfigModule;
12 | import com.google.inject.Guice;
13 | import com.google.inject.Injector;
14 | import org.junit.After;
15 | import org.junit.Before;
16 |
17 | public abstract class ProxyManagerTest {
18 | protected MitmProxyManager proxyManager;
19 |
20 | public String[] getArgs() {
21 | return [] as String[]
22 | }
23 |
24 | @Before
25 | public void setUp() throws Exception {
26 | Injector injector = Guice.createInjector(new ConfigModule(getArgs()));
27 | proxyManager = injector.getInstance(MitmProxyManager.class);
28 | }
29 |
30 | @After
31 | public void tearDown() throws Exception {
32 | for (MitmProxyServer p : proxyManager.get()) {
33 | try {
34 | proxyManager.delete(p.getPort());
35 | } catch (Exception e) {
36 | }
37 | }
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/test/groovy/com/browserup/bup/proxy/mitmproxy/ProxyPortAssignmentTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.mitmproxy;
6 |
7 | import com.browserup.bup.MitmProxyServer;
8 | import com.browserup.bup.exception.ProxyExistsException;
9 | import com.browserup.bup.exception.ProxyPortsExhaustedException;
10 | import org.junit.Test;
11 |
12 | import static org.junit.Assert.assertEquals;
13 | import static org.junit.Assert.fail;
14 |
15 | public class ProxyPortAssignmentTest extends ProxyManagerTest {
16 | @Override
17 | public String[] getArgs() {
18 | return new String[]{"--proxyPortRange", "9091-9093"};
19 | }
20 |
21 | @Test
22 | public void testAutoAssignment() {
23 | int[] ports = {9091, 9092, 9093};
24 | MitmProxyServer p;
25 | for(int port : ports){
26 | p = proxyManager.create();
27 | assertEquals(port, p.getPort());
28 | }
29 | try{
30 | proxyManager.create();
31 | fail();
32 | }catch(ProxyPortsExhaustedException e){
33 | proxyManager.delete(9093);
34 | p = proxyManager.create();
35 | assertEquals(9093, p.getPort());
36 |
37 | proxyManager.delete(9091);
38 | p = proxyManager.create();
39 | assertEquals(9091, p.getPort());
40 |
41 | for(int port : ports){
42 | proxyManager.delete(port);
43 | }
44 | }
45 | }
46 |
47 | @Test
48 | public void testManualAssignment() {
49 | MitmProxyServer p = proxyManager.create(9094);
50 | assertEquals(9094, p.getPort());
51 | try{
52 | proxyManager.create(9094);
53 | fail();
54 | }catch(ProxyExistsException e){
55 | assertEquals(9094, e.getPort());
56 | proxyManager.delete(9094);
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/test/groovy/com/browserup/bup/proxy/mitmproxy/validation/PatternConstraintTest.groovy:
--------------------------------------------------------------------------------
1 | package com.browserup.bup.proxy.mitmproxy.validation
2 |
3 | import com.browserup.bup.rest.validation.PatternConstraint
4 | import org.junit.Assert
5 | import org.junit.Test
6 | import org.mockito.Mockito
7 |
8 | import javax.validation.ConstraintValidatorContext
9 |
10 | import static org.mockito.ArgumentMatchers.any
11 | import static org.mockito.Mockito.mock
12 |
13 | class PatternConstraintTest {
14 |
15 | @Test
16 | void validPattern() {
17 | def validator = new PatternConstraint.PatternValidator()
18 | def pattern = ".*"
19 | def mockedContext = mock(ConstraintValidatorContext)
20 | def mockedBuilder = mock(ConstraintValidatorContext.ConstraintViolationBuilder)
21 |
22 | Mockito.when(mockedContext.buildConstraintViolationWithTemplate(any(String))).thenReturn(mockedBuilder)
23 |
24 | def result = validator.isValid(pattern, mockedContext)
25 |
26 | Assert.assertTrue("Expected pattern validation to pass", result)
27 | }
28 |
29 | @Test
30 | void invalidPattern() {
31 | def validator = new PatternConstraint.PatternValidator()
32 | def pattern = "["
33 | def mockedContext = mock(ConstraintValidatorContext)
34 | def mockedBuilder = mock(ConstraintValidatorContext.ConstraintViolationBuilder)
35 |
36 | Mockito.when(mockedContext.buildConstraintViolationWithTemplate(any(String))).thenReturn(mockedBuilder)
37 |
38 | def result = validator.isValid(pattern, mockedContext)
39 |
40 | Assert.assertFalse("Expected pattern validation to fail", result)
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/test/java/com/browserup/bup/proxy/ProxyPortAssignmentTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy;
6 |
7 | import static org.junit.Assert.assertEquals;
8 | import static org.junit.Assert.fail;
9 |
10 | import com.browserup.bup.MitmProxyServer;
11 | import com.browserup.bup.exception.ProxyExistsException;
12 | import com.browserup.bup.exception.ProxyPortsExhaustedException;
13 | import com.browserup.bup.proxy.test.util.ProxyManagerTest;
14 | import org.junit.Test;
15 |
16 | public class ProxyPortAssignmentTest extends ProxyManagerTest {
17 | @Override
18 | public String[] getArgs() {
19 | return new String[]{"--proxyPortRange", "9091-9093"};
20 | }
21 |
22 | @Test
23 | public void testAutoAssignment() {
24 | int[] ports = {9091, 9092, 9093};
25 | MitmProxyServer p;
26 | for(int port : ports){
27 | p = proxyManager.create();
28 | assertEquals(port, p.getPort());
29 | }
30 | try{
31 | proxyManager.create();
32 | fail();
33 | }catch(ProxyPortsExhaustedException e){
34 | proxyManager.delete(9093);
35 | p = proxyManager.create();
36 | assertEquals(9093, p.getPort());
37 |
38 | proxyManager.delete(9091);
39 | p = proxyManager.create();
40 | assertEquals(9091, p.getPort());
41 |
42 | for(int port : ports){
43 | proxyManager.delete(port);
44 | }
45 | }
46 | }
47 |
48 | @Test
49 | public void testManualAssignment() {
50 | MitmProxyServer p = proxyManager.create(9094);
51 | assertEquals(9094, p.getPort());
52 | try{
53 | proxyManager.create(9094);
54 | fail();
55 | }catch(ProxyExistsException e){
56 | assertEquals(9094, e.getPort());
57 | proxyManager.delete(9094);
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/test/java/com/browserup/bup/proxy/test/util/ProxyManagerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | package com.browserup.bup.proxy.test.util;
6 |
7 | import com.browserup.bup.MitmProxyServer;
8 | import com.browserup.bup.proxy.MitmProxyManager;
9 | import com.google.inject.Guice;
10 | import com.google.inject.Injector;
11 | import com.browserup.bup.BrowserUpProxyServer;
12 | import com.browserup.bup.proxy.ProxyManager;
13 | import com.browserup.bup.proxy.guice.ConfigModule;
14 | import org.junit.After;
15 | import org.junit.Before;
16 |
17 | public abstract class ProxyManagerTest {
18 | protected MitmProxyManager proxyManager;
19 |
20 | public String[] getArgs() {
21 | return new String[] {};
22 | }
23 |
24 | @Before
25 | public void setUp() throws Exception {
26 | Injector injector = Guice.createInjector(new ConfigModule(getArgs()));
27 | proxyManager = injector.getInstance(MitmProxyManager.class);
28 | }
29 |
30 | @After
31 | public void tearDown() throws Exception {
32 | for(MitmProxyServer p : proxyManager.get()){
33 | try{
34 | proxyManager.delete(p.getPort());
35 | }catch(Exception e){ }
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/browserup-proxy-rest/src/test/resources/log4j2-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "configuration" : {
3 | "name": "test",
4 | "appenders": {
5 | "Console": {
6 | "name": "console",
7 | "target": "SYSTEM_OUT",
8 | "PatternLayout": {
9 | "pattern": "%-7r %date %level [%thread] %logger - %msg%n"
10 | }
11 | }
12 | },
13 |
14 | "loggers": {
15 | "root": {
16 | "level": "info",
17 | "appender-ref": {
18 | "ref": "console"
19 | }
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/browserup-proxy.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/browserup/browserup-proxy/0f28ec6e8f1423e1fdb014fded72e9278bdd083f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/nohup.out:
--------------------------------------------------------------------------------
1 | Error starting proxy server: OSError(48, 'Address already in use')
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Modifications Copyright (c) 2019 BrowserUp, Inc.
3 | */
4 |
5 | include 'browserup-proxy-core'
6 | include 'browserup-proxy-dist'
7 | include 'browserup-proxy-rest'
8 | include 'browserup-proxy-mitm'
9 | include 'browserup-proxy-rest-clients'
10 |
--------------------------------------------------------------------------------